Skip to content
Snippets Groups Projects
Commit e6911bca authored by McDonnell, Marshall's avatar McDonnell, Marshall
Browse files

Fix docs and input wksp err CalculateEfficiencyCorrection Refs #24432

parent 3caec64b
No related branches found
No related tags found
No related merge requests found
......@@ -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')
......
......@@ -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):
......
......@@ -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.
......
......@@ -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
############
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment