diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ApplyPaalmanPingsCorrection.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ApplyPaalmanPingsCorrection.py index 8a93e86ae19d024d06e27a6c9076a15a769e80ba..1d7ab8509af9affb163d48a0f87bb497b2ed404e 100644 --- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ApplyPaalmanPingsCorrection.py +++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ApplyPaalmanPingsCorrection.py @@ -1,5 +1,5 @@ #pylint: disable=no-init,too-many-instance-attributes -from mantid.simpleapi import * +import mantid.simpleapi as s_api from mantid.api import PythonAlgorithm, AlgorithmFactory, MatrixWorkspaceProperty, WorkspaceGroupProperty, \ PropertyMode, MatrixWorkspace, Progress from mantid.kernel import Direction, logger @@ -17,6 +17,11 @@ class ApplyPaalmanPingsCorrection(PythonAlgorithm): _output_ws_name = None _corrections = None _scaled_container = None + _shift_can = False + _shifted_container = None + _can_shift_factor = 0.0 + _scaled_container_wavelength = None + _sample_ws_wavelength = None def category(self): @@ -42,11 +47,14 @@ class ApplyPaalmanPingsCorrection(PythonAlgorithm): self.declareProperty(name='CanScaleFactor', defaultValue=1.0, doc='Factor to scale the can data') + self.declareProperty(name='CanShiftFactor', defaultValue=0.0, + doc='Amount by which to shift the container data') + self.declareProperty(MatrixWorkspaceProperty('OutputWorkspace', '', direction=Direction.Output), doc='The output corrections workspace.') - + #pylint: disable=too-many-branches def PyExec(self): self._setup() @@ -55,23 +63,52 @@ class ApplyPaalmanPingsCorrection(PythonAlgorithm): if not self._use_can: logger.information('Not using container') - # Apply container scale factor if needed - prog_container = Progress(self, start=0.0, end=0.2, nreports=2) + prog_container = Progress(self, start=0.0, end=0.2, nreports=4) prog_container.report('Starting algorithm') + + # Units should be wavelength + sample_unit = s_api.mtd[self._sample_ws_name].getAxis(0).getUnit().unitID() + self._convert_units_wavelength(sample_unit, + self._sample_ws_name, + self._sample_ws_wavelength, + "Wavelength") + if self._use_can: + + # Appy container shift if needed + if self._shift_can: + # Use temp workspace so we don't modify data + prog_container.report('Shifting can') + s_api.ScaleX(InputWorkspace=self._can_ws_name, + OutputWorkspace=self._shifted_container, + Factor=self._can_shift_factor, + Operation='Add') + logger.information('Container data shifted by %f' % self._can_shift_factor) + else: + prog_container.report('Cloning Workspace') + s_api.CloneWorkspace(InputWorkspace=self._can_ws_name, + OutputWorkspace=self._shifted_container) + + # Apply container scale factor if needed if self._scale_can: # Use temp workspace so we don't modify original data prog_container.report('Scaling can') - Scale(InputWorkspace=self._can_ws_name, - OutputWorkspace=self._scaled_container, - Factor=self._can_scale_factor, - Operation='Multiply') + s_api.Scale(InputWorkspace=self._shifted_container, + OutputWorkspace=self._scaled_container, + Factor=self._can_scale_factor, + Operation='Multiply') logger.information('Container scaled by %f' % self._can_scale_factor) else: prog_container.report('Cloning Workspace') - CloneWorkspace(InputWorkspace=self._can_ws_name, - OutputWorkspace=self._scaled_container) + s_api.CloneWorkspace(InputWorkspace=self._shifted_container, + OutputWorkspace=self._scaled_container) + # Units should be wavelength + can_unit = s_api.mtd[self._scaled_container].getAxis(0).getUnit().unitID() + self._convert_units_wavelength(can_unit, + self._scaled_container, + self._scaled_container_wavelength, + "Wavelength") prog_corr = Progress(self, start=0.2, end=0.6, nreports=2) if self._use_corrections: @@ -89,11 +126,10 @@ class ApplyPaalmanPingsCorrection(PythonAlgorithm): correction_type = 'sample_corrections_only' # Add corrections filename to log values prog_corr.report('Correcting sample') - AddSampleLog(Workspace=self._output_ws_name, - LogName='corrections_filename', - LogType='String', - LogText=self._corrections_ws_name) - + s_api.AddSampleLog(Workspace=self._output_ws_name, + LogName='corrections_filename', + LogType='String', + LogText=self._corrections_ws_name) else: # Do simple subtraction @@ -103,48 +139,66 @@ class ApplyPaalmanPingsCorrection(PythonAlgorithm): can_cut = self._can_ws_name.index('_') can_base = self._can_ws_name[:can_cut] prog_corr.report('Adding container filename') - AddSampleLog(Workspace=self._output_ws_name, - LogName='container_filename', - LogType='String', - LogText=can_base) + s_api.AddSampleLog(Workspace=self._output_ws_name, + LogName='container_filename', + LogType='String', + LogText=can_base) - prog_wrkflow = Progress(self, 0.6, 1.0, nreports=4) + prog_wrkflow = Progress(self, 0.6, 1.0, nreports=5) # Record the container scale factor if self._use_can and self._scale_can: prog_wrkflow.report('Adding container scaling') - AddSampleLog(Workspace=self._output_ws_name, - LogName='container_scale', - LogType='Number', - LogText=str(self._can_scale_factor)) + s_api.AddSampleLog(Workspace=self._output_ws_name, + LogName='container_scale', + LogType='Number', + LogText=str(self._can_scale_factor)) + + # Record the container shift amount + if self._use_can and self._shift_can: + prog_wrkflow.report('Adding container shift') + s_api.AddSampleLog(Workspace=self._output_ws_name, + LogName='container_shift', + LogType='Number', + LogText=str(self._can_shift_factor)) # Record the type of corrections applied prog_wrkflow.report('Adding correction type') - AddSampleLog(Workspace=self._output_ws_name, - LogName='corrections_type', - LogType='String', - LogText=correction_type) + s_api.AddSampleLog(Workspace=self._output_ws_name, + LogName='corrections_type', + LogType='String', + LogText=correction_type) # Add original sample as log entry sam_cut = self._sample_ws_name.index('_') sam_base = self._sample_ws_name[:sam_cut] prog_wrkflow.report('Adding sample filename') - AddSampleLog(Workspace=self._output_ws_name, - LogName='sample_filename', - LogType='String', - LogText=sam_base) + s_api.AddSampleLog(Workspace=self._output_ws_name, + LogName='sample_filename', + LogType='String', + LogText=sam_base) + + # Convert Units back to original + self._convert_units_wavelength(sample_unit, + self._output_ws_name, + self._output_ws_name, + sample_unit) self.setPropertyValue('OutputWorkspace', self._output_ws_name) # Remove temporary workspaces prog_wrkflow.report('Deleting Workspaces') - if self._corrections in mtd: - DeleteWorkspace(self._corrections) - if self._scaled_container in mtd: - DeleteWorkspace(self._scaled_container) + if self._corrections in s_api.mtd: + s_api.DeleteWorkspace(self._corrections) + if self._scaled_container in s_api.mtd: + s_api.DeleteWorkspace(self._scaled_container) + if self._shifted_container in s_api.mtd: + s_api.DeleteWorkspace(self._shifted_container) + if self._scaled_container_wavelength in s_api.mtd: + s_api.DeleteWorkspace(self._scaled_container_wavelength) + if self._sample_ws_wavelength in s_api.mtd: + s_api.DeleteWorkspace(self._sample_ws_wavelength) prog_wrkflow.report('Algorithm Complete') - - def validateInputs(self): """ Validate user input. @@ -159,13 +213,13 @@ class ApplyPaalmanPingsCorrection(PythonAlgorithm): issues['CorrectionsWorkspace'] = error_msg issues['CanWorkspace'] = error_msg - sample_ws = mtd[self._sample_ws_name] + sample_ws = s_api.mtd[self._sample_ws_name] if isinstance(sample_ws, MatrixWorkspace): sample_unit_id = sample_ws.getAxis(0).getUnit().unitID() # Check sample and container X axis units match if self._use_can: - can_ws = mtd[self._can_ws_name] + can_ws = s_api.mtd[self._can_ws_name] if isinstance(can_ws, MatrixWorkspace): can_unit_id = can_ws.getAxis(0).getUnit().unitID() if can_unit_id != sample_unit_id: @@ -177,7 +231,6 @@ class ApplyPaalmanPingsCorrection(PythonAlgorithm): return issues - def _setup(self): """ Get properties and setup instance variables. @@ -197,10 +250,42 @@ class ApplyPaalmanPingsCorrection(PythonAlgorithm): self._can_scale_factor = self.getProperty('CanScaleFactor').value self._scale_can = self._can_scale_factor != 1.0 + self._can_shift_factor = self.getProperty('CanShiftFactor').value + self._shift_can = self._can_shift_factor != 0.0 + # This temporary WS is needed because ConvertUnits does not like named WS in a Group self._corrections = '__converted_corrections' self._scaled_container = '__scaled_container' + self._shifted_container = '_shifted_container' + self._scaled_container_wavelength = '_scaled_container_wavelength' + self._sample_ws_wavelength = '_sample_ws_wavelength' + + def _convert_units_wavelength(self, unit, input_ws, output_ws, target): + + if unit != 'Wavelength': + # Configure conversion + if unit == 'dSpacing': + emode = 'Elastic' + efixed = 0.0 + elif unit == 'DeltaE': + emode = 'Indirect' + from IndirectCommon import getEfixed + efixed = getEfixed(input_ws) + else: + raise ValueError('Unit %s in sample workspace is not supported' % unit) + # Do conversion + # Use temporary workspace so we don't modify data + s_api.ConvertUnits(InputWorkspace=input_ws, + OutputWorkspace=output_ws, + Target=target, + EMode=emode, + EFixed=efixed) + + else: + # No need to convert + s_api.CloneWorkspace(InputWorkspace=input_ws, + OutputWorkspace=output_ws) def _get_correction_factor_ws_name(self, factor_type): """ @@ -210,7 +295,7 @@ class ApplyPaalmanPingsCorrection(PythonAlgorithm): @return Full name of workspace (None if not found) """ - corrections_ws = mtd[self._corrections_ws_name] + corrections_ws = s_api.mtd[self._corrections_ws_name] for ws_name in corrections_ws.getNames(): if factor_type in ws_name: @@ -218,14 +303,13 @@ class ApplyPaalmanPingsCorrection(PythonAlgorithm): return None - def _pre_process_corrections(self): """ If the sample is not in wavelength then convert the corrections to whatever units the sample is in. """ - unit_id = mtd[self._sample_ws_name].getAxis(0).getUnit().unitID() + unit_id = s_api.mtd[self._sample_ws_wavelength].getAxis(0).getUnit().unitID() logger.information('x-unit is ' + unit_id) factor_types = ['ass'] @@ -236,52 +320,33 @@ class ApplyPaalmanPingsCorrection(PythonAlgorithm): input_name = self._get_correction_factor_ws_name(factor_type) output_name = self._corrections + '_' + factor_type - if unit_id != 'Wavelength': - # Configure conversion - if unit_id == 'dSpacing': - emode = 'Elastic' - efixed = 0.0 - elif unit_id == 'DeltaE': - emode = 'Indirect' - from IndirectCommon import getEfixed - efixed = getEfixed(mtd[self._sample_ws_name]) - else: - raise ValueError('Unit %s in sample workspace is not supported' % unit_id) - - # Do conversion - ConvertUnits(InputWorkspace=input_name, - OutputWorkspace=output_name, - Target=unit_id, - EMode=emode, - EFixed=efixed) - - else: - # No need to convert - CloneWorkspace(InputWorkspace=input_name, - OutputWorkspace=output_name) + s_api.CloneWorkspace(InputWorkspace=input_name, + OutputWorkspace=output_name) # Group the temporary factor workspaces (for easy removal later) - GroupWorkspaces(InputWorkspaces=[self._corrections + '_' + f_type for f_type in factor_types], - OutputWorkspace=self._corrections) - + s_api.GroupWorkspaces(InputWorkspaces=[self._corrections + '_' + f_type for f_type in factor_types], + OutputWorkspace=self._corrections) def _subtract(self): """ Do a simple container subtraction (when no corrections are given). """ - logger.information('Rebining container to ensure Minus') - RebinToWorkspace(WorkspaceToRebin=self._can_ws_name, - WorkspaceToMatch=self._sample_ws_name, - OutputWorkspace=self._can_ws_name) + s_api.RebinToWorkspace(WorkspaceToRebin=self._can_ws_name, + WorkspaceToMatch=self._sample_ws_wavelength, + OutputWorkspace=self._can_ws_name) logger.information('Using simple container subtraction') - Minus(LHSWorkspace=self._sample_ws_name, - RHSWorkspace=self._scaled_container, - OutputWorkspace=self._output_ws_name) + # Rebin can + s_api.RebinToWorkspace(WorkspaceToRebin=self._scaled_container_wavelength, + WorkspaceToMatch=self._sample_ws_wavelength, + OutputWorkspace=self._scaled_container_wavelength) + s_api.Minus(LHSWorkspace=self._sample_ws_wavelength, + RHSWorkspace=self._scaled_container_wavelength, + OutputWorkspace=self._output_ws_name) def _correct_sample(self): """ @@ -291,10 +356,9 @@ class ApplyPaalmanPingsCorrection(PythonAlgorithm): logger.information('Correcting sample') # Ass - Divide(LHSWorkspace=self._sample_ws_name, - RHSWorkspace=self._corrections + '_ass', - OutputWorkspace=self._output_ws_name) - + s_api.Divide(LHSWorkspace=self._sample_ws_wavelength, + RHSWorkspace=self._corrections + '_ass', + OutputWorkspace=self._output_ws_name) def _correct_sample_can(self): """ @@ -304,25 +368,45 @@ class ApplyPaalmanPingsCorrection(PythonAlgorithm): logger.information('Correcting sample and container') corrected_can_ws = '__corrected_can' + factor_types = ['_ass'] + if self._use_can: + factor_types.extend(['_acc', '_acsc', '_assc']) + corr_unit = s_api.mtd[self._corrections + '_ass'].getAxis(0).getUnit().unitID() + for f_type in factor_types: + self._convert_units_wavelength(corr_unit, + self._corrections + f_type, + self._corrections + f_type, + "Wavelength") + + s_api.RebinToWorkspace(WorkspaceToRebin=self._scaled_container_wavelength, + WorkspaceToMatch=self._corrections + '_acc', + OutputWorkspace=self._scaled_container_wavelength) + # Acc - Divide(LHSWorkspace=self._scaled_container, - RHSWorkspace=self._corrections + '_acc', - OutputWorkspace=corrected_can_ws) + s_api.Divide(LHSWorkspace=self._scaled_container_wavelength, + RHSWorkspace=self._corrections + '_acc', + OutputWorkspace=corrected_can_ws) # Acsc - Multiply(LHSWorkspace=corrected_can_ws, - RHSWorkspace=self._corrections + '_acsc', - OutputWorkspace=corrected_can_ws) - Minus(LHSWorkspace=self._sample_ws_name, - RHSWorkspace=corrected_can_ws, - OutputWorkspace=self._output_ws_name) + s_api.Multiply(LHSWorkspace=corrected_can_ws, + RHSWorkspace=self._corrections + '_acsc', + OutputWorkspace=corrected_can_ws) + s_api.Minus(LHSWorkspace=self._sample_ws_wavelength, + RHSWorkspace=corrected_can_ws, + OutputWorkspace=self._output_ws_name) # Assc - Divide(LHSWorkspace=self._output_ws_name, - RHSWorkspace=self._corrections + '_assc', - OutputWorkspace=self._output_ws_name) + s_api.Divide(LHSWorkspace=self._output_ws_name, + RHSWorkspace=self._corrections + '_assc', + OutputWorkspace=self._output_ws_name) + + for f_type in factor_types: + self._convert_units_wavelength(corr_unit, + self._corrections + f_type, + self._corrections + f_type, + corr_unit) - DeleteWorkspace(corrected_can_ws) + s_api.DeleteWorkspace(corrected_can_ws) # Register algorithm with Mantid diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/ApplyPaalmanPingsCorrectionTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/ApplyPaalmanPingsCorrectionTest.py index dc07067b50cdd3b5bb89ab9ecd279d95c9954ce6..f3c1174cb970b5d18bf08873fa1aab090ad37975 100644 --- a/Framework/PythonInterface/test/python/plugins/algorithms/ApplyPaalmanPingsCorrectionTest.py +++ b/Framework/PythonInterface/test/python/plugins/algorithms/ApplyPaalmanPingsCorrectionTest.py @@ -91,6 +91,13 @@ class ApplyPaalmanPingsCorrectionTest(unittest.TestCase): self._verify_workspace(corr, 'can_subtraction') + def test_can_subtraction_with_can_shift(self): + corr = ApplyPaalmanPingsCorrection(SampleWorkspace=self._sample_ws, + CanWorkspace=self._can_ws, + CanShiftFactor=0.03) + + self._verify_workspace(corr, 'can_subtraction') + def test_sample_corrections_only(self): corr = ApplyPaalmanPingsCorrection(SampleWorkspace=self._sample_ws, @@ -115,6 +122,14 @@ class ApplyPaalmanPingsCorrectionTest(unittest.TestCase): self._verify_workspace(corr, 'sample_and_can_corrections') + def test_sample_and_can_corrections_with_can_shift(self): + corr = ApplyPaalmanPingsCorrection(SampleWorkspace=self._sample_ws, + CorrectionsWorkspace=self._corrections_ws, + CanWorkspace=self._can_ws, + CanShiftFactor = 0.03) + + self._verify_workspace(corr, 'sample_and_can_corrections') + if __name__=="__main__": unittest.main() diff --git a/MantidQt/CustomInterfaces/src/Indirect/ApplyPaalmanPings.cpp b/MantidQt/CustomInterfaces/src/Indirect/ApplyPaalmanPings.cpp index ed52c383a1bd2f5ea1e643aa6920864da766de8e..a330eb5637e520f4909ae219c02470e608939d1c 100644 --- a/MantidQt/CustomInterfaces/src/Indirect/ApplyPaalmanPings.cpp +++ b/MantidQt/CustomInterfaces/src/Indirect/ApplyPaalmanPings.cpp @@ -151,17 +151,7 @@ void ApplyPaalmanPings::run() { MatrixWorkspace_sptr sampleWs = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>( m_sampleWorkspaceName); - m_originalSampleUnits = sampleWs->getAxis(0)->unit()->unitID(); - - // If not in wavelength then do conversion - if (m_originalSampleUnits != "Wavelength") { - g_log.information( - "Sample workspace not in wavelength, need to convert to continue."); - absCorProps["SampleWorkspace"] = - addConvertUnitsStep(sampleWs, "Wavelength"); - } else { - absCorProps["SampleWorkspace"] = m_sampleWorkspaceName; - } + absCorProps["SampleWorkspace"] = m_sampleWorkspaceName; const bool useCan = m_uiForm.ckUseCan->isChecked(); const bool useCorrections = m_uiForm.ckUseCorrections->isChecked(); @@ -178,25 +168,6 @@ void ApplyPaalmanPings::run() { clone->setProperty("Outputworkspace", cloneName); clone->execute(); - const bool useShift = m_uiForm.ckShiftCan->isChecked(); - if (useShift) { - IAlgorithm_sptr scaleX = AlgorithmManager::Instance().create("ScaleX"); - scaleX->initialize(); - scaleX->setLogging(false); - scaleX->setProperty("InputWorkspace", cloneName); - scaleX->setProperty("OutputWorkspace", cloneName); - scaleX->setProperty("Factor", m_uiForm.spCanShift->value()); - scaleX->setProperty("Operation", "Add"); - scaleX->execute(); - IAlgorithm_sptr rebin = - AlgorithmManager::Instance().create("RebinToWorkspace"); - rebin->initialize(); - rebin->setLogging(false); - rebin->setProperty("WorkspaceToRebin", cloneName); - rebin->setProperty("WorkspaceToMatch", m_sampleWorkspaceName); - rebin->setProperty("OutputWorkspace", cloneName); - rebin->execute(); - } canClone = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(cloneName); // Check for same binning across sample and container @@ -221,21 +192,17 @@ void ApplyPaalmanPings::run() { } } - // If not in wavelength then do conversion - std::string originalCanUnits = canClone->getAxis(0)->unit()->unitID(); - if (originalCanUnits != "Wavelength") { - g_log.information("Container workspace not in wavelength, need to " - "convert to continue."); - absCorProps["CanWorkspace"] = addConvertUnitsStep(canClone, "Wavelength"); - } else { - absCorProps["CanWorkspace"] = cloneName; - } + absCorProps["CanWorkspace"] = cloneName; const bool useCanScale = m_uiForm.ckScaleCan->isChecked(); if (useCanScale) { const double canScaleFactor = m_uiForm.spCanScale->value(); applyCorrAlg->setProperty("CanScaleFactor", canScaleFactor); } + if (m_uiForm.ckShiftCan->isChecked()) { // If container is shifted + const double canShiftFactor = m_uiForm.spCanShift->value(); + applyCorrAlg->setProperty("canShiftFactor", canShiftFactor); + } } if (useCorrections) { @@ -401,30 +368,18 @@ void ApplyPaalmanPings::absCorComplete(bool error) { disconnect(m_batchAlgoRunner, SIGNAL(batchComplete(bool)), this, SLOT(absCorComplete(bool))); const bool useCan = m_uiForm.ckUseCan->isChecked(); - const bool useShift = m_uiForm.ckShiftCan->isChecked(); if (error) { emit showMessageBox( "Unable to apply corrections.\nSee Results Log for more details."); return; } - // Convert back to original sample units - if (m_originalSampleUnits != "Wavelength") { - auto ws = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>( - m_pythonExportWsName); - - std::string eMode(""); - if (m_originalSampleUnits == "dSpacing") - eMode = "Elastic"; - addConvertUnitsStep(ws, m_originalSampleUnits, "", eMode); - } - // Add save algorithms if required bool save = m_uiForm.ckSave->isChecked(); if (save) addSaveWorkspaceToQueue(QString::fromStdString(m_pythonExportWsName)); if (useCan) { - if (useShift) { + if (m_uiForm.ckShiftCan->isChecked()) { // If container is shifted IAlgorithm_sptr shiftLog = AlgorithmManager::Instance().create("AddSampleLog"); shiftLog->initialize(); diff --git a/docs/source/release/v3.8.0/indirect_inelastic.rst b/docs/source/release/v3.8.0/indirect_inelastic.rst index c015b173ff11b79254303bd5f746eeeefe03b749..2b560061910883d5f24051b4455f09d944af8e5f 100644 --- a/docs/source/release/v3.8.0/indirect_inelastic.rst +++ b/docs/source/release/v3.8.0/indirect_inelastic.rst @@ -76,6 +76,7 @@ Improvements - Range bars colours in the *ISIS Calibration* interface have been updated to match the convention in the fit wizard. - Vesuvio sigma_theta value updated for single and double differencing in both forward and back scattering. The new value is 0.016 for all. - The Elwin interface now uses the resolution of the instrument to create the range bars when possible +- Shift of container data and conversion of units to wavelength have been removed from ApplyPaalmanPings interface and added to ApplyPaalmanPingsCorrection algorithm. Bugfixes