From e6911bca50751d49028c5ff8b883ff032565dca8 Mon Sep 17 00:00:00 2001 From: Marshall McDonnell <mcdonnellmt@ornl.gov> Date: Wed, 16 Jan 2019 10:41:34 -0500 Subject: [PATCH] Fix docs and input wksp err CalculateEfficiencyCorrection Refs #24432 --- .../CalculateEfficiencyCorrection.py | 75 +++++++++---------- .../CalculateEfficiencyCorrectionTest.py | 51 ++++++++----- .../CalculateEfficiencyCorrection-v1.rst | 9 ++- docs/source/release/v3.14.0/framework.rst | 2 +- 4 files changed, 76 insertions(+), 61 deletions(-) diff --git a/Framework/PythonInterface/plugins/algorithms/CalculateEfficiencyCorrection.py b/Framework/PythonInterface/plugins/algorithms/CalculateEfficiencyCorrection.py index 5020f5004a8..0fa64666e9c 100644 --- a/Framework/PythonInterface/plugins/algorithms/CalculateEfficiencyCorrection.py +++ b/Framework/PythonInterface/plugins/algorithms/CalculateEfficiencyCorrection.py @@ -54,106 +54,103 @@ class CalculateEfficiencyCorrection(PythonAlgorithm): self.declareProperty( MatrixWorkspaceProperty('OutputWorkspace', '', direction=Direction.Output), - doc="Outputs the efficiency correction which can be applied by multiplying \ - the OutputWorkspace to the workspace that requires the correction.") + doc="Output workspace for the efficiency correction. \ + This can be applied by multiplying the OutputWorkspace \ + to the workspace that requires the correction.") self.declareProperty( name='ChemicalFormula', defaultValue='None', validator=StringMandatoryValidator(), - doc='Sample chemical formula used to determine :math:`\\sigma (\\lambda_{ref})` term.') + doc='Sample chemical formula used to determine cross-section term.') self.declareProperty( name='DensityType', defaultValue = 'Mass Density', validator=StringListValidator(['Mass Density', 'Number Density']), - doc = 'Use of Mass density or Number density') + doc = 'Use of Mass density (g/cm^3) or Number density (atoms/Angstrom^3)') self.declareProperty( name='Density', defaultValue=0.0, validator=FloatBoundedValidator(0.0), - doc='Mass density (g/cm^3) or Number density (atoms/Angstrom^3), :math:`\\rho`. \ - Default=0.0') + doc='Mass density (g/cm^3) or Number density (atoms/Angstrom^3).') self.declareProperty( name='Thickness', defaultValue=1.0, validator=FloatBoundedValidator(0.0), - doc='Sample thickness (cm), :math:`T`. Default value=1.0') + doc='Sample thickness (cm).') self.declareProperty( name='MeasuredEfficiency', defaultValue=0.0, validator=FloatBoundedValidator(0.0, 1.0), - doc="Directly input the efficiency, :math:`\\epsilon`, measured at \ - MeasuredEfficiencyWavelength, :math:`\\lambda_{\\epsilon}`, to determine :math:`\\rho * T`, where \ - :math:`\\rho * T = - ln(1-\\epsilon) \\frac{1}{ \\frac{\\lambda_{\\epsilon} \\sigma (\\lambda_{ref})}{\\lambda_{ref}}}` \ - term for XSectionType == AttenuationXSection and \ - :math:`\\rho * T = - ln(1-\\epsilon) \\frac{1} \ - { \\sigma_s + \\frac{\\lambda_{\\epsilon} \\sigma (\\lambda_{ref})}{\\lambda_{ref}}}` \ - for XSectionType == TotalXSection \ - with :math:`\\lambda_{ref} =` 1.7982. Default=0.0") + doc="Directly input the efficiency measured at MeasuredEfficiencyWavelength. \ + This is used to determine a Density*Thickness term.") self.declareProperty( name='MeasuredEfficiencyWavelength', defaultValue=1.7982, validator=FloatBoundedValidator(0.0), - doc="The wavelength, :math:`\\lambda_{\\epsilon}`, at which the \ - MeasuredEfficiency, :math:`\\epsilon`, was measured. Default=1.7982") + doc="The wavelength at which the MeasuredEfficiency was measured.") self.declareProperty( - name='Alpha', - defaultValue=0.0, - doc="Directly input :math:`\\alpha`, where \ - :math:`\\alpha = \\rho * T * \\sigma (\\lambda_{ref}) / \\lambda_{ref}`, \ - where :math:`\\lambda_{ref} =` 1.7982. XSectionType has no effect. Default=0.0") + name='Alpha', defaultValue=0.0, + doc="Directly input the alpha term in exponential to multiply by the wavelength. \ + XSectionType has no effect if this is used.") self.declareProperty( name='XSectionType', defaultValue="AttenuationXSection", validator=StringListValidator(['AttenuationXSection', 'TotalXSection']), - doc = 'Use either the absorption cross section (for monitor-type correction) or, \ - the total cross section (for transmission-type correction) in Alpha term. \ - Default=AttenuationXSection') + doc = 'Use either the absorption or total cross section in exponential term. \ + The absorption cross section is for monitor-type corrections and \ + the total cross section is for transmission-type corrections' ) def validateInputs(self): issues = dict() - if self.getProperty('InputWorkspace').isDefault and self.getProperty('WavelengthRange').isDefault: + # Check the inputs for wavelength + isInWSDefault = self.getProperty('InputWorkspace').isDefault + isWlRangeDefault = self.getProperty('WavelengthRange').isDefault + + if isInWSDefault and isWlRangeDefault: issues['InputWorkspace'] = "Must select either InputWorkspace and WavelengthRange as input" issues['WavelengthRange'] = "Must select either InputWorkspace and WavelengthRange as input" - if not self.getProperty('InputWorkspace').isDefault and not self.getProperty('WavelengthRange').isDefault: + if isInWSDefault and isWlRangeDefault: issues['InputWorkspace'] = "Cannot select both InputWorkspace and WavelengthRange as input" issues['WavelengthRange'] = "Cannot select both InputWorkspace and WavelengthRange as input" - if not self.getProperty('Density').isDefault: - if self.getProperty('ChemicalFormula').isDefault: - issues['ChemicalFormula'] = "Must specify the ChemicalFormula with Density" + # Check the different inputs for the exponential term + isDensityDefault = self.getProperty('Density').isDefault + isFormulaDefault = self.getProperty('ChemicalFormula').isDefault + isEffDefault = self.getProperty('MeasuredEfficiency').isDefault + isAlphaDefault = self.getProperty('Alpha').isDefault - if not self.getProperty('MeasuredEfficiency').isDefault: - if self.getProperty('ChemicalFormula').isDefault: - issues['ChemicalFormula'] = "Must specify the ChemicalFormula with MeasuredEfficiency" + if not isDensityDefault: + if isFormulaDefault: + issues['ChemicalFormula'] = "Must specify the ChemicalFormula with Density" - if not self.getProperty('MeasuredEfficiency').isDefault: - if self.getProperty('ChemicalFormula').isDefault: + if not isEffDefault: + if isFormulaDefault: issues['ChemicalFormula'] = "Must specify the ChemicalFormula with MeasuredEfficiency" - if not self.getProperty('MeasuredEfficiency').isDefault and not self.getProperty('Density').isDefault: + if not isEffDefault and not isDensityDefault: issues['MeasuredEfficiency'] = "Cannot select both MeasuredEfficiency and Density as input" issues['Density'] = "Cannot select both MeasuredEfficiency and Density as input" - if not self.getProperty('Alpha').isDefault and not self.getProperty('Density').isDefault: + if not isAlphaDefault and not isDensityDefault: issues['Alpha'] = "Cannot select both Alpha and Density as input" issues['Density'] = "Cannot select both Alpha and Density as input" - if not self.getProperty('MeasuredEfficiency').isDefault and not self.getProperty('Alpha').isDefault: + if not isEffDefault and not isAlphaDefault: issues['MeasuredEfficiency'] = "Cannot select both MeasuredEfficiency and Alpha as input" issues['Alpha'] = "Cannot select both MeasuredEfficiency and Alpha as input" return issues def _setup(self): - self._input_ws = self.getPropertyValue('InputWorkspace') + self._input_ws = self.getProperty('InputWorkspace').value self._bin_params = self.getPropertyValue('WavelengthRange') self._output_ws = self.getProperty('OutputWorkspace').valueAsStr self._chemical_formula = self.getPropertyValue('ChemicalFormula') diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/CalculateEfficiencyCorrectionTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/CalculateEfficiencyCorrectionTest.py index 503bcdd4797..5254b3e668d 100644 --- a/Framework/PythonInterface/test/python/plugins/algorithms/CalculateEfficiencyCorrectionTest.py +++ b/Framework/PythonInterface/test/python/plugins/algorithms/CalculateEfficiencyCorrectionTest.py @@ -8,8 +8,8 @@ from __future__ import (absolute_import, division, print_function) import unittest from mantid.simpleapi import \ - ConvertToPointData, CalculateEfficiencyCorrection, CreateSampleWorkspace, \ - DeleteWorkspace, LoadAscii, Multiply + CalculateEfficiencyCorrection, CloneWorkspace, ConvertToPointData, \ + CreateSampleWorkspace, DeleteWorkspace, LoadAscii, Multiply from testhelpers import run_algorithm from mantid.api import AnalysisDataService @@ -48,7 +48,9 @@ class CalculateEfficiencyCorrectionTest(unittest.TestCase): Unit="Wavelength") ConvertToPointData(InputWorkspace=self._input_wksp, OutputWorkspace=self._input_wksp) - def checkResults(self, xsection="AttenuationXSection"): + def checkResults(self, eventCheck=False, xsection="AttenuationXSection"): + # Check results + Multiply(LHSWorkspace=self._input_wksp, RHSWorkspace=self._correction_wksp, OutputWorkspace=self._output_wksp) @@ -56,10 +58,13 @@ class CalculateEfficiencyCorrectionTest(unittest.TestCase): self.assertEqual(output_wksp.getAxis(0).getUnit().unitID(), 'Wavelength') self.assertAlmostEqual(output_wksp.readX(0)[79], 0.995) - if xsection == "AttenuationXSection": - self.assertAlmostEqual(output_wksp.readY(0)[79], 3250.28183501) - if xsection == "TotalXSection": - self.assertAlmostEqual(output_wksp.readY(0)[79], 3245.70148939) + if eventCheck: + self.assertAlmostEqual(output_wksp.readY(0)[79], 62.22517501) + else: + if xsection == "AttenuationXSection": + self.assertAlmostEqual(output_wksp.readY(0)[79], 3250.28183501) + if xsection == "TotalXSection": + self.assertAlmostEqual(output_wksp.readY(0)[79], 3245.70148939) # Result tests def testCalculateEfficiencyCorrectionAlphaForEventWksp(self): @@ -81,18 +86,29 @@ class CalculateEfficiencyCorrectionTest(unittest.TestCase): Alpha=self._alpha, OutputWorkspace=self._correction_wksp) self.assertTrue(alg_test.isExecuted()) - - # Apply correction ConvertToPointData(InputWorkspace=self._input_wksp, OutputWorkspace=self._input_wksp) - Multiply(LHSWorkspace=self._input_wksp, - RHSWorkspace=self._correction_wksp, - OutputWorkspace=self._output_wksp) + self.checkResults(eventCheck=True) - # Check results - output_wksp = AnalysisDataService.retrieve(self._output_wksp) - self.assertEqual(output_wksp.getAxis(0).getUnit().unitID(), 'Wavelength') - self.assertAlmostEqual(output_wksp.readX(0)[79], 0.995) - self.assertAlmostEqual(output_wksp.readY(0)[79], 62.22517501) + def testCalculateEfficiencyCorrectionAlphaForEventWkspInputWkspNotInADS(self): + self.cleanup() + + # Create an exponentially decaying function in wavelength to simulate + # measured sample + tmp_wksp = CreateSampleWorkspace(WorkspaceType="Event", Function="User Defined", + UserDefinedFunction="name=ExpDecay, Height=100, Lifetime=4", + Xmin=0.2, Xmax=4.0, BinWidth=0.01, XUnit="Wavelength", + NumEvents=10000, NumBanks=1, BankPixelWidth=1, + OutputWorkspace=self._input_wksp, StoreInADS=False) + + # Calculate the efficiency correction + alg_test = run_algorithm("CalculateEfficiencyCorrection", + InputWorkspace=tmp_wksp, + Alpha=self._alpha, + OutputWorkspace=self._correction_wksp) + self.assertTrue(alg_test.isExecuted()) + CloneWorkspace(InputWorkspace=tmp_wksp, OutputWorkspace=self._input_wksp) + ConvertToPointData(InputWorkspace=self._input_wksp, OutputWorkspace=self._input_wksp) + self.checkResults(eventCheck=True) def testCalculateEfficiencyCorrectionAlpha(self): alg_test = run_algorithm("CalculateEfficiencyCorrection", @@ -109,7 +125,6 @@ class CalculateEfficiencyCorrectionTest(unittest.TestCase): Alpha=self._alpha, OutputWorkspace=self._correction_wksp) self.assertTrue(alg_test.isExecuted()) - self.checkResults() def testCalculateEfficiencyCorrectionMassDensityAndThickness(self): diff --git a/docs/source/algorithms/CalculateEfficiencyCorrection-v1.rst b/docs/source/algorithms/CalculateEfficiencyCorrection-v1.rst index 6db84f168b3..bc31d255f76 100644 --- a/docs/source/algorithms/CalculateEfficiencyCorrection-v1.rst +++ b/docs/source/algorithms/CalculateEfficiencyCorrection-v1.rst @@ -8,7 +8,6 @@ Description ----------- - This algorithm calculates the detection efficiency correction, :math:`\epsilon`, defined by: .. math:: @@ -46,8 +45,12 @@ The optional inputs into the algorithm are to input either: 2. The ``Density`` and ``ChemicalFormula`` to calculate the :math:`\sigma(\lambda_{ref})` term. 3. The ``MeasuredEfficiency``, an optional ``MeasuredEfficiencyWavelength``, and ``ChemicalFormula`` to calculate the :math:`\sigma(\lambda_{ref})` term. -The ``MeasuredEfficiency`` is the :math:`\epsilon` term measured at a specific wavelength, ``MeasuredEfficiencyWavelength``. This helps -if the efficiency has been directly measured experimentally at a given wavelength. +The ``MeasuredEfficiency`` is the :math:`\epsilon` term measured at a specific wavelength, :math:`\lambda_{\epsilon}`, which is specified by ``MeasuredEfficiencyWavelength``. This helps +if the efficiency has been directly measured experimentally at a given wavelength. This will calculate the +:math:`\rho * T` term, where it will be either: + +- :math:`\rho * T = - ln(1-\epsilon) \frac{1}{ \frac{\lambda_{\epsilon} \sigma (\lambda_{ref})}{\lambda_{ref}}}` for ``XSectionType`` == ``AttenuationXSection`` +- :math:`\rho * T = - ln(1-\epsilon) \frac{1}{ \sigma_s + \frac{\lambda_{\epsilon} \sigma (\lambda_{ref})}{\lambda_{ref}}}` for ``XSectionType`` == ``TotalXSection`` For the ``XSectionType``, if the efficiency correction is applied to a beam monitor to determine the incident spectrum, then the ``AttenuationXSection`` option should be used. This is due to the fact that scatter events do not lead to neutrons that will be in the incident beam. If the efficiency correction is to be used similar to a transmission measurement for an actual sample measurement, such as in :ref:`algm-CalculateSampleTransmission-v1`, then the ``TotalXSection`` should be used to include both types of events. diff --git a/docs/source/release/v3.14.0/framework.rst b/docs/source/release/v3.14.0/framework.rst index 9d1d1ba2f12..2b3254822a7 100644 --- a/docs/source/release/v3.14.0/framework.rst +++ b/docs/source/release/v3.14.0/framework.rst @@ -64,7 +64,7 @@ New Algorithms - :ref:`MaskBinsIf <algm-MaskBinsIf>` is an algorithm to mask bins according to criteria specified as a muparser expression. - :ref:`MaskNonOverlappingBins <algm-MaskNonOverlappingBins>` masks the bins that do not overlap with another workspace. - :ref:`ParallaxCorrection <algm-ParallaxCorrection>` will perform a geometric correction for the so-called parallax effect in tube based SANS detectors. -- :ref:`CalculateEfficiencyCorrection <algm-CalculateEfficiencyCorrection>` will calculate an detection efficiency correction with mulitple and flexible inputs for calculation. +- :ref:`CalculateEfficiencyCorrection <algm-CalculateEfficiencyCorrection>` will calculate a detection efficiency correction with multiple and flexible inputs for calculation. Improvements ############ -- GitLab