Unverified Commit 09994cb7 authored by Gagik Vardanyan's avatar Gagik Vardanyan Committed by GitHub
Browse files

Merge pull request #32159 from gemmaguest/32125_extract_load_from_rilap

Extract loading into separate preprocessing algorithm
parents ba795c09 ef8e794e
......@@ -270,6 +270,7 @@ set(PYTHON_PLUGINS
algorithms/WorkflowAlgorithms/ReflectometryILLPreprocess.py
algorithms/WorkflowAlgorithms/ReflectometryILLSumForeground.py
algorithms/WorkflowAlgorithms/ReflectometryILL_common.py
algorithms/WorkflowAlgorithms/ReflectometryISISPreprocess.py
algorithms/WorkflowAlgorithms/ReflectometryISISLoadAndProcess.py
algorithms/WorkflowAlgorithms/ResNorm2.py
algorithms/WorkflowAlgorithms/SANS/SANSBeamCentreFinder.py
......
......@@ -8,7 +8,7 @@
from mantid.api import (AlgorithmFactory, AnalysisDataService, DataProcessorAlgorithm,
WorkspaceGroup)
from mantid.simpleapi import (LoadEventNexus, LoadNexus, MergeRuns, RenameWorkspace)
from mantid.simpleapi import MergeRuns
from mantid.kernel import (CompositeValidator, Direction, EnabledWhenProperty,
IntBoundedValidator, Property, PropertyCriterion,
......@@ -329,29 +329,27 @@ class ReflectometryISISLoadAndProcess(DataProcessorAlgorithm):
# the ADS
AnalysisDataService.addOrReplace(output_ws_name, ws_group)
def _renameWorkspaceBasedOnRunNumber(self, workspace_name, isTrans):
"""Rename the given workspace based on its run number and a standard prefix"""
new_name = self._prefixedName(_getRunNumberAsString(workspace_name), isTrans)
if new_name != workspace_name:
RenameWorkspace(InputWorkspace=workspace_name, OutputWorkspace=new_name)
# Also rename the monitor workspace, if there is one
if AnalysisDataService.doesExist(_monitorWorkspace(workspace_name)):
RenameWorkspace(InputWorkspace=_monitorWorkspace(workspace_name),
OutputWorkspace=_monitorWorkspace(new_name))
return new_name
def _loadRun(self, run, isTrans):
"""Load a run as an event workspace if slicing is requested, or a histogram
workspace otherwise. Transmission runs are always loaded as histogram workspaces."""
workspace_name = self._prefixedName(run, isTrans)
if not isTrans and self._slicingEnabled():
LoadEventNexus(Filename=run, OutputWorkspace=workspace_name, LoadMonitors=True)
event_mode = not isTrans and self._slicingEnabled()
args = {'InputRunList': [run], 'EventMode': event_mode}
alg = self.createChildAlgorithm('ReflectometryISISPreprocess', **args)
alg.setRethrows(True)
alg.execute()
ws = alg.getProperty('OutputWorkspace').value
monitor_ws = alg.getProperty('MonitorWorkspace').value
workspace_name = self._prefixedName(_getRunNumberAsString(ws), isTrans)
AnalysisDataService.addOrReplace(workspace_name, ws)
if monitor_ws:
AnalysisDataService.addOrReplace(_monitorWorkspace(workspace_name), monitor_ws)
if event_mode:
_throwIfNotValidReflectometryEventWorkspace(workspace_name)
self.log().information('Loaded event workspace ' + workspace_name)
else:
LoadNexus(Filename=run, OutputWorkspace=workspace_name)
self.log().information('Loaded workspace ' + workspace_name)
workspace_name = self._renameWorkspaceBasedOnRunNumber(workspace_name, isTrans)
return workspace_name
def _sumWorkspaces(self, workspaces, isTrans):
......@@ -508,17 +506,16 @@ def _monitorWorkspace(workspace):
return workspace + '_monitors'
def _getRunNumberAsString(workspace_name):
def _getRunNumberAsString(workspace):
"""Get the run number for a workspace. If it's a workspace group, get
the run number from the first child workspace."""
try:
workspace = AnalysisDataService.retrieve(workspace_name)
if not isinstance(workspace, WorkspaceGroup):
return str(workspace.getRunNumber())
# Get first child in the group
return str(workspace[0].getRunNumber())
except:
raise RuntimeError('Could not find run number for workspace ' + workspace_name)
raise RuntimeError('Could not find run number for workspace ' + workspace.getName())
def _hasWorkspaceID(workspace_name, workspace_id):
......
# -*- coding: utf-8 -*-# Mantid Repository : https://github.com/mantidproject/mantid
#
# Copyright © 2021 ISIS Rutherford Appleton Laboratory UKRI,
# NScD Oak Ridge National Laboratory, European Spallation Source,
# Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
# SPDX - License - Identifier: GPL - 3.0 +
from mantid.api import (AlgorithmFactory, DataProcessorAlgorithm, MatrixWorkspaceProperty, MatrixWorkspace,
PropertyMode, WorkspaceGroup)
from mantid.kernel import (CompositeValidator, StringArrayLengthValidator, StringArrayMandatoryValidator,
StringArrayProperty, Direction)
class ReflectometryISISPreprocess(DataProcessorAlgorithm):
_RUNS = 'InputRunList'
_GROUP_TOF = 'GroupTOFWorkspaces'
_OUTPUT_WS = 'OutputWorkspace'
_MONITOR_WS = 'MonitorWorkspace'
_EVENT_MODE = "EventMode"
def __init__(self):
"""Initialize an instance of the algorithm."""
DataProcessorAlgorithm.__init__(self)
def category(self):
"""Return the categories of the algorithm."""
return 'ISIS\\Reflectometry;Workflow\\Reflectometry'
def name(self):
"""Return the name of the algorithm."""
return 'ReflectometryISISPreprocess'
def summary(self):
"""Return a summary of the algorithm."""
return "Preprocess ISIS reflectometry data, including optional loading and summing of the input runs."
def seeAlso(self):
"""Return a list of related algorithm names."""
return ['ReflectometryISISLoadAndProcess', 'ReflectometryReductionOneAuto']
def PyInit(self):
self.declareProperty(
StringArrayProperty(self._RUNS, values=[], validator=self._get_input_runs_validator()),
doc='A list of run numbers or workspace names to load and preprocess')
self.declareProperty(self._EVENT_MODE, False, direction=Direction.Input,
doc='If true, load the input workspaces as event data')
self.declareProperty(
MatrixWorkspaceProperty(self._OUTPUT_WS, '', direction=Direction.Output),
doc='The preprocessed output workspace. If multiple input runs are specified '
'they will be summed into a single output workspace.')
self.declareProperty(
MatrixWorkspaceProperty(self._MONITOR_WS, '', direction=Direction.Output, optional=PropertyMode.Optional),
doc='The loaded monitors workspace. This is only output in event mode.')
def PyExec(self):
workspace, monitor_ws = self._loadRun(self.getPropertyValue(self._RUNS))
self.setProperty(self._OUTPUT_WS, workspace)
if monitor_ws:
self.setProperty(self._MONITOR_WS, monitor_ws)
@staticmethod
def _get_input_runs_validator():
mandatoryInputRuns = CompositeValidator()
mandatoryInputRuns.add(StringArrayMandatoryValidator())
lenValidator = StringArrayLengthValidator()
lenValidator.setLengthMin(1)
mandatoryInputRuns.add(lenValidator)
return mandatoryInputRuns
def _loadRun(self, run: str) -> MatrixWorkspace:
"""Load a run as an event workspace if slicing is requested, or a histogram
workspace otherwise. Transmission runs are always loaded as histogram workspaces."""
event_mode = self.getProperty(self._EVENT_MODE).value
monitor_ws = None
if event_mode:
alg = self.createChildAlgorithm('LoadEventNexus', Filename=run, LoadMonitors=True)
alg.execute()
ws = alg.getProperty('OutputWorkspace').value
monitor_ws = alg.getProperty('MonitorWorkspace').value
self._validate_event_ws(ws)
self.log().information('Loaded event workspace')
else:
alg = self.createChildAlgorithm('LoadNexus', Filename=run)
alg.execute()
ws = alg.getProperty('OutputWorkspace').value
self.log().information('Loaded workspace ')
return ws, monitor_ws
@staticmethod
def _validate_event_ws(workspace):
if isinstance(workspace, WorkspaceGroup):
# Our reduction algorithm doesn't currently support this due to slicing
# (which would result in a group of groups)
raise RuntimeError('Loading Workspace Groups in event mode is not supported currently.')
if not workspace.run().hasProperty('proton_charge'):
# Reduction algorithm requires proton_charge
raise RuntimeError('Event workspaces must contain proton_charge')
AlgorithmFactory.subscribe(ReflectometryISISPreprocess)
......@@ -59,6 +59,7 @@ set(TEST_PY_FILES
ReflectometryILLPreprocessTest.py
ReflectometryILLSumForegroundTest.py
ReflectometryISISLoadAndProcessTest.py
ReflectometryISISPreprocessTest.py
ResNorm2Test.py
SANSDarkRunBackgroundCorrectionTest.py
SANSFitShiftScaleTest.py
......
......@@ -78,7 +78,7 @@ class ReflectometryISISLoadAndProcessTest(unittest.TestCase):
args['InputRunList'] = '13460'
outputs = ['IvsQ_13460', 'IvsQ_binned_13460', 'TOF_13460', 'TOF']
self._assert_run_algorithm_succeeds(args, outputs)
history = ['LoadNexus', 'ReflectometryReductionOneAuto', 'GroupWorkspaces']
history = ['ReflectometryISISPreprocess', 'ReflectometryReductionOneAuto', 'GroupWorkspaces']
self._check_history(AnalysisDataService.retrieve('IvsQ_binned_13460'), history)
def test_input_run_that_is_in_ADS_with_prefixed_name_is_not_reloaded(self):
......@@ -105,7 +105,7 @@ class ReflectometryISISLoadAndProcessTest(unittest.TestCase):
args['InputRunList'] = '13460'
outputs = ['IvsQ_13460', 'IvsQ_binned_13460', 'TEST_13460', 'TOF_13460', 'TOF']
self._assert_run_algorithm_succeeds(args, outputs)
history = ['LoadNexus', 'ReflectometryReductionOneAuto', 'GroupWorkspaces']
history = ['ReflectometryISISPreprocess', 'ReflectometryReductionOneAuto', 'GroupWorkspaces']
self._check_history(AnalysisDataService.retrieve('IvsQ_binned_13460'), history)
def test_existing_workspace_is_used_when_name_passed_in_input_list(self):
......@@ -122,7 +122,7 @@ class ReflectometryISISLoadAndProcessTest(unittest.TestCase):
args['InputRunList'] = 'INTER13460'
outputs = ['IvsQ_13460', 'IvsQ_binned_13460', 'TOF_13460', 'TOF']
self._assert_run_algorithm_succeeds(args, outputs)
history = ['LoadNexus', 'RenameWorkspace', 'ReflectometryReductionOneAuto', 'GroupWorkspaces']
history = ['ReflectometryISISPreprocess', 'ReflectometryReductionOneAuto', 'GroupWorkspaces']
self._check_history(AnalysisDataService.retrieve('IvsQ_binned_13460'), history)
def test_overriding_output_names(self):
......@@ -202,7 +202,7 @@ class ReflectometryISISLoadAndProcessTest(unittest.TestCase):
outputs = ['IvsQ_13460', 'IvsQ_binned_13460', 'TOF_13460', 'TRANS_13463', 'TRANS_13464',
'TRANS_LAM_13463_13464', 'TOF']
self._assert_run_algorithm_succeeds(args, outputs)
history = ['LoadNexus', 'LoadNexus', 'ReflectometryReductionOneAuto', 'GroupWorkspaces']
history = ['ReflectometryISISPreprocess', 'ReflectometryISISPreprocess', 'ReflectometryReductionOneAuto', 'GroupWorkspaces']
self._check_history(AnalysisDataService.retrieve('IvsQ_binned_13460'), history)
def test_trans_runs_are_not_loaded_if_in_ADS_without_prefix(self):
......@@ -234,7 +234,7 @@ class ReflectometryISISLoadAndProcessTest(unittest.TestCase):
outputs = ['IvsQ_13460', 'IvsQ_binned_13460', 'TOF_13460', 'TRANS_13463', 'TRANS_13464',
'TEST_13463', 'TEST_13464', 'TRANS_LAM_13463_13464', 'TOF']
self._assert_run_algorithm_succeeds(args, outputs)
history = ['LoadNexus', 'LoadNexus', 'ReflectometryReductionOneAuto', 'GroupWorkspaces']
history = ['ReflectometryISISPreprocess', 'ReflectometryISISPreprocess', 'ReflectometryReductionOneAuto', 'GroupWorkspaces']
self._check_history(AnalysisDataService.retrieve('IvsQ_binned_13460'), history)
def test_existing_workspace_is_used_for_trans_runs_when_name_passed_in_input_list(self):
......@@ -508,6 +508,8 @@ class ReflectometryISISLoadAndProcessTest(unittest.TestCase):
outputs = ['no_TOF_group', 'TOF_12345+67890', '12345', '67890']
self._assert_run_algorithm_succeeds(args, outputs)
# TODO test if no runNumber is on the WS
def _create_workspace(self, run_number, prefix='', suffix=''):
name = prefix + str(run_number) + suffix
ws = CreateSampleWorkspace(WorkspaceType='Histogram',NumBanks=1, NumMonitors=2,
......
# Mantid Repository : https://github.com/mantidproject/mantid
#
# Copyright © 2021 ISIS Rutherford Appleton Laboratory UKRI,
# NScD Oak Ridge National Laboratory, European Spallation Source,
# Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
# SPDX - License - Identifier: GPL - 3.0 +
import unittest
from mantid import config
from mantid.api import AnalysisDataService, IEventWorkspace, MatrixWorkspace, WorkspaceGroup
from mantid.simpleapi import CreateSampleWorkspace
from plugins.algorithms.WorkflowAlgorithms.ReflectometryISISPreprocess import ReflectometryISISPreprocess
from testhelpers import create_algorithm
class ReflectometryISISPreprocessTest(unittest.TestCase):
def setUp(self):
self._oldFacility = config['default.facility']
if self._oldFacility.strip() == '':
self._oldFacility = 'TEST_LIVE'
self._oldInstrument = config['default.instrument']
config['default.facility'] = 'ISIS'
config['default.instrument'] = 'INTER'
def tearDown(self):
AnalysisDataService.clear()
config['default.facility'] = self._oldFacility
config['default.instrument'] = self._oldInstrument
def test_input_run_is_loaded_histo_mode_by_default(self):
args = {'InputRunList': 'INTER13460',
"OutputWorkspace": "ws"}
output_ws = self._run_test(args)
self.assertIsInstance(output_ws, MatrixWorkspace)
self.assertEqual("Workspace2D", output_ws.id())
def test_input_run_is_loaded_histo_mode(self):
args = {'InputRunList': 'INTER13460',
"EventMode": False,
"OutputWorkspace": "ws"}
output_ws = self._run_test(args)
self.assertIsInstance(output_ws, MatrixWorkspace)
self.assertEqual("Workspace2D", output_ws.id())
def test_input_run_is_loaded_event_mode(self):
args = {'InputRunList': 'INTER13460',
"EventMode": True,
"OutputWorkspace": "ws"}
output_ws = self._run_test(args)
self.assertIsInstance(output_ws, IEventWorkspace)
def test_validation_of_event_workspaces_without_proton_charge_throws(self):
ws = CreateSampleWorkspace()
with self.assertRaisesRegex(RuntimeError, "proton_charge"):
ReflectometryISISPreprocess._validate_event_ws(ws)
def test_validation_of_event_workspace_group_throws(self):
ws = WorkspaceGroup()
with self.assertRaisesRegex(RuntimeError, "Workspace Groups"):
ReflectometryISISPreprocess._validate_event_ws(ws)
def test_monitors_are_not_loaded_in_histo_mode(self):
args = {'InputRunList': 'INTER13460',
"EventMode": False,
"OutputWorkspace": "ws"}
output_ws, monitor_ws = self._run_test_with_monitors(args)
self.assertIsInstance(output_ws, MatrixWorkspace)
self.assertIsNone(monitor_ws)
def test_monitors_are_loaded_in_event_mode(self):
args = {'InputRunList': 'INTER13460',
"EventMode": True,
"OutputWorkspace": "ws"}
output_ws, monitor_ws = self._run_test_with_monitors(args)
self.assertIsInstance(output_ws, IEventWorkspace)
self.assertIsInstance(monitor_ws, MatrixWorkspace)
def _run_test_with_monitors(self, args):
alg = create_algorithm('ReflectometryISISPreprocess', **args)
alg.setChild(True)
alg.setRethrows(True)
alg.execute()
output_ws = alg.getProperty('OutputWorkspace').value
monitor_ws = alg.getProperty('MonitorWorkspace').value
return output_ws, monitor_ws
def _run_test(self, args):
output_ws, _ = self._run_test_with_monitors(args)
return output_ws
if __name__ == '__main__':
unittest.main()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment