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

Initial addition for CalculateEfficiencyCorrection algorithm Refs #24432

parent 1b29223f
No related branches found
No related tags found
No related merge requests found
# Mantid Repository : https://github.com/mantidproject/mantid
#
# Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
# NScD Oak Ridge National Laboratory, European Spallation Source
# & Institut Laue - Langevin
# SPDX - License - Identifier: GPL - 3.0 +
from __future__ import absolute_import, division, print_function
import numpy as np
from mantid.simpleapi import \
CloneWorkspace, ConvertFromDistribution, ConvertToPointData, ConvertUnits, SetSampleMaterial
from mantid.api import \
mtd, AlgorithmFactory, DataProcessorAlgorithm, MatrixWorkspaceProperty
from mantid.kernel import \
Direction, FloatBoundedValidator, MaterialBuilder, StringMandatoryValidator
PROPS_FOR_TRANS = ['DensityType']
TABULATED_WAVELENGTH = 1.7982
class CalculateEfficiencyCorrection(DataProcessorAlgorithm):
_input_ws = None
_output_ws = None
def category(self):
return 'CorrectionFunctions\\EfficiencyCorrections'
def name(self):
return 'CalculateEfficiencyCorrection'
def summary(self):
return 'Calculate an efficiency correction using various inputs. Can be used to determine \
an incident spectrum after correcting a measured spectrum from beam monitors \
or vanadium measurements.'
def seeAlso(self):
return [ "He3TubeEfficiency", "DetectorEfficiencyCor", "DetectorEfficiencyCorUser", "CalculateEfficiency", "ComputeCalibrationCoefVan" ]
def PyInit(self):
self.declareProperty(
MatrixWorkspaceProperty('InputWorkspace', '',
direction=Direction.Input),
doc='Input workspace with wavelength range to calculate for the correction.')
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.")
self.declareProperty(
name='Density',
defaultValue=0.0,
doc='Mass density (g/cm^3) or Number density (atoms/Angstrom^3), :math:`\\rho`. \
Default=0.0')
self.declareProperty(
name='Thickness',
defaultValue=1.0,
doc='Sample thickness (cm), :math:`T`. Default value=1.0')
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 = - ln(1-\epsilon) \\frac{\\lambda_{ref}}{\\lambda_{\epsilon} \\sigma_{a}(\\lambda_{ref})}` term, \
where :math:`\\lambda_{ref} =` 1.7982. Default=0.0")
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")
self.declareProperty(
name='Alpha',
defaultValue=0.0,
doc="Directly input :math:`\\alpha`, where \
:math:`\\alpha = \\rho * T * \\sigma_{a}(\\lambda_{ref}) / \\lambda_{ref}`, \
where :math:`\\lambda_{ref} =` 1.7982. Default=0.0")
self.declareProperty(
name='ChemicalFormula', defaultValue='None',
validator=StringMandatoryValidator(),
doc='Sample chemical formula used to determine :math:`\\sigma_{a}(\\lambda_{ref}) term.`')
self.copyProperties('CalculateSampleTransmission', PROPS_FOR_TRANS)
def validateInputs(self):
issues = dict()
density = self.getProperty('Density').value
if density < 0.0:
issues['Density'] = 'Density must be positive'
thickness = self.getProperty('Thickness').value
if thickness < 0.0:
issues['Thickness'] = 'Thickness must be positive'
if not self.getProperty('Density').isDefault:
if self.getProperty('ChemicalFormula').isDefault:
issues['ChemicalFormula'] = "Must specify the ChemicalFormula with Density"
if not self.getProperty('MeasuredEfficiency').isDefault:
if self.getProperty('ChemicalFormula').isDefault:
issues['ChemicalFormula'] = "Must specify the ChemicalFormula with MeasuredEfficiency"
if not self.getProperty('MeasuredEfficiency').isDefault:
if self.getProperty('ChemicalFormula').isDefault:
issues['ChemicalFormula'] = "Must specify the ChemicalFormula with MeasuredEfficiency"
if not self.getProperty('MeasuredEfficiency').isDefault and not self.getProperty('Density'):
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'):
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'):
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._efficiency = self.getProperty('MeasuredEfficiency').value
self._efficiency_wavelength = self.getProperty('MeasuredEfficiencyWavelength').value
self._chemical_formula = self.getPropertyValue('ChemicalFormula')
self._density_type = self.getPropertyValue('DensityType')
self._density = self.getProperty('Density').value
self._thickness = self.getProperty('Thickness').value
self._alpha = self.getProperty('Alpha').value
self._output_ws = self.getProperty('OutputWorkspace').valueAsStr
def PyExec(self):
self._setup()
CloneWorkspace(
Inputworkspace=self._input_ws,
OutputWorkspace=self._output_ws)
if mtd[self._output_ws].isDistribution():
ConvertFromDistribution(Workspace=self._output_ws)
ConvertToPointData(
InputWorkspace=self._output_ws,
OutputWorkspace=self._output_ws)
ConvertUnits(
InputWorkspace=self._output_ws,
OutputWorkspace=self._output_ws,
Target='Wavelength',
EMode='Elastic')
if self.getProperty('Alpha').isDefault:
SetSampleMaterial(
InputWorkspace=self._output_ws,
ChemicalFormula=self._chemical_formula,
SampleNumberDensity=self._density)
if self.getProperty('MeasuredEfficiency').isDefault:
self._calculate_area_density_from_density()
else:
self._calculate_area_density_from_efficiency()
self._calculate_alpha()
ws = mtd[self._output_ws]
wavelengths = ws.readX(0)
efficiency = self._calculate_efficiency(wavelengths)
for histo in range(ws.getNumberHistograms()):
mtd[self._output_ws].setY(histo, efficiency)
self.setProperty('OutputWorkspace', mtd[self._output_ws])
def _calculate_area_density_from_efficiency(self):
'''
Calculates area density (atom/cm^2) using efficiency
'''
material = mtd[self._output_ws].sample().getMaterial()
ref_absXS = material.absorbXSection()
self._area_density = - np.log( 1.0 - self._efficiency) / ref_absXS
self._area_density *= TABULATED_WAVELENGTH / self._efficiency_wavelength
def _calculate_area_density_from_density(self):
'''
Calculates area density (atom/cm^2) using number density and thickness.
'''
if self._density_type == 'Mass Density':
builder = MaterialBuilder().setFormula(self._chemical_formula)
mat = builder.setMassDensity(self._density).build()
self._density = mat.numberDensity
self._area_density = self._density * self._thickness
def _calculate_alpha(self):
'''
Calculates alpha = -area_density / absXS / 1.7982
'''
material = mtd[self._output_ws].sample().getMaterial()
absorption_x_section = material.absorbXSection() / TABULATED_WAVELENGTH
self._alpha = self._area_density * absorption_x_section
def _calculate_efficiency(self, wavelength):
'''
Calculates efficiency of a detector / monitor at a given wavelength.
@param wavelength Wavelength at which to calculate (in Angstroms)
@return efficiency
'''
efficiency = 1. / (1.0 - np.exp(-self._alpha * wavelength))
return efficiency
AlgorithmFactory.subscribe(CalculateEfficiencyCorrection)
......@@ -12,6 +12,7 @@ set ( TEST_PY_FILES
AngularAutoCorrelationsTwoAxesTest.py
ApplyDetectorScanEffCorrTest.py
BinWidthAtXTest.py
CalculateEfficiencyCorrectionTest.py
CalculateSampleTransmissionTest.py
CheckForSampleLogsTest.py
ConjoinSpectraTest.py
......
# Mantid Repository : https://github.com/mantidproject/mantid
#
# Copyright &copy; 2018 ISIS Rutherford Appleton Laboratory UKRI,
# NScD Oak Ridge National Laboratory, European Spallation Source
# & Institut Laue - Langevin
# SPDX - License - Identifier: GPL - 3.0 +
from __future__ import (absolute_import, division, print_function)
import unittest
from mantid.simpleapi import \
LoadAscii, DeleteWorkspace, Multiply, ConvertToPointData, CalculateEfficiencyCorrection
from testhelpers import run_algorithm
from mantid.api import AnalysisDataService
class CalculateEfficiencyCorrectionTest(unittest.TestCase):
_input_wksp = "input_wksp"
_correction_wksp = "correction_wksp"
_output_wksp = "output_wksp"
_alpha = 0.693
_chemical_formula = "(He3)"
_number_density = 0.0002336682167635477
_mass_density = 0.0011702649036052439
_efficiency1 = 0.712390781371
_efficiency2 = { "Efficiency": 0.74110947758, "Wavelength": 1.95}
_thickness = 1.0
def setUp(self):
'''
This file is the back-calculated spectrum of polyethylene moderator (ambient 300K)
prior to the efficiency correction described in Eq (3) of:
Mildner et al. "A cooled polyethylene moderator on a pulsed neutron source",
Nucl. Instr. Meth. 152, 1978, doi:/10.1016/0029-554X(78)90043-5
After the correction is applied, the workspace will replicated (b) in Fig. 2 of this article.
Similar results are shown in Fig 1.a for "ambient (300K)" in:
S. Howells, "On the choice of moderator for a liquids diffractometer on a pulsed neutron source",
Nucl. Instr. Meth. Phys. Res. 223, 1984, doi:10.1016/0167-5087(84)90256-4
'''
input_wksp = LoadAscii(
Filename="CalculateEfficiencyCorrection_milder_moderator_polyethlyene_300K.txt",
Unit="Wavelength")
ConvertToPointData(InputWorkspace=input_wksp, OutputWorkspace=input_wksp)
self._input_wksp = input_wksp
def checkResults(self):
Multiply(LHSWorkspace=self._input_wksp,
RHSWorkspace=self._correction_wksp,
OutputWorkspace=self._output_wksp)
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], 3250.28183501)
# Result tests
def testCalculateEfficiencyCorrectionAlpha(self):
alg_test = run_algorithm("CalculateEfficiencyCorrection",
InputWorkspace=self._input_wksp,
Alpha=self._alpha,
OutputWorkspace=self._correction_wksp)
self.assertTrue(alg_test.isExecuted())
self.checkResults()
def testCalculateEfficiencyCorrectionMassDensityAndThickness(self):
correction_wksp = "correction_ws"
alg_test = run_algorithm("CalculateEfficiencyCorrection",
InputWorkspace=self._input_wksp,
ChemicalFormula=self._chemical_formula,
Density=self._mass_density,
Thickness=self._thickness,
OutputWorkspace=correction_wksp)
self.assertTrue(alg_test.isExecuted())
self._correction_wksp = AnalysisDataService.retrieve(correction_wksp)
self.checkResults()
def testCalculateEfficiencyCorrectionNumberDensityAndThickness(self):
correction_wksp = "correction_ws"
alg_test = run_algorithm("CalculateEfficiencyCorrection",
InputWorkspace=self._input_wksp,
ChemicalFormula=self._chemical_formula,
DensityType="Number Density",
Density=self._number_density,
Thickness=self._thickness,
OutputWorkspace=correction_wksp)
self.assertTrue(alg_test.isExecuted())
self._correction_wksp = AnalysisDataService.retrieve(correction_wksp)
self.checkResults()
def testCalculateEfficiencyCorrectionEfficiency(self):
correction_wksp = "correction_ws"
alg_test = run_algorithm("CalculateEfficiencyCorrection",
InputWorkspace=self._input_wksp,
ChemicalFormula=self._chemical_formula,
MeasuredEfficiency=self._efficiency1,
OutputWorkspace=correction_wksp)
self.assertTrue(alg_test.isExecuted())
self._correction_wksp = AnalysisDataService.retrieve(correction_wksp)
self.checkResults()
def testCalculateEfficiencyCorrectionEfficiencyWithWavelength(self):
correction_wksp = "correction_ws"
efficiency=self._efficiency2['Efficiency']
wavelength=self._efficiency2['Wavelength']
alg_test = run_algorithm("CalculateEfficiencyCorrection",
InputWorkspace=self._input_wksp,
ChemicalFormula=self._chemical_formula,
MeasuredEfficiency=efficiency,
MeasuredEfficiencyWavelength=wavelength,
OutputWorkspace=correction_wksp)
self.assertTrue(alg_test.isExecuted())
self._correction_wksp = AnalysisDataService.retrieve(correction_wksp)
self.checkResults()
# Invalid checks
def testCalculateEfficiencyCorretionInvalidDensity(self):
self.assertRaises(RuntimeError,
CalculateEfficiencyCorrection,
InputWorkspace=self._input_wksp,
ChemicalFormula=self._chemical_formula,
Density=-1.0,
OutputWorkspace=self._output_wksp)
def testCalculateEfficiencyCorretionMassDensityWithoutChemicalFormula(self):
self.assertRaises(RuntimeError,
CalculateEfficiencyCorrection,
InputWorkspace=self._input_wksp,
Density=1.0,
OutputWorkspace=self._output_wksp)
def testCalculateEfficiencyCorretionNumberDensityWithoutChemicalFormula(self):
self.assertRaises(RuntimeError,
CalculateEfficiencyCorrection,
InputWorkspace=self._input_wksp,
DensityType="Number Density",
Density=1.0,
OutputWorkspace=self._output_wksp)
def testCalculateEfficiencyCorretionEfficiencyWithoutChemicalFormula(self):
self.assertRaises(RuntimeError,
CalculateEfficiencyCorrection,
InputWorkspace=self._input_wksp,
MeasuredEfficiency=1.0,
OutputWorkspace=self._output_wksp)
def testCalculateEfficiencyCorretionEfficiencyAndDensity(self):
self.assertRaises(RuntimeError,
CalculateEfficiencyCorrection,
InputWorkspace=self._input_wksp,
Density=1.0,
MeasuredEfficiency=1.0,
OutputWorkspace=self._output_wksp)
def testCalculateEfficiencyCorretionAlphaAndDensity(self):
self.assertRaises(RuntimeError,
CalculateEfficiencyCorrection,
InputWorkspace=self._input_wksp,
Density=1.0,
Alpha=1.0,
OutputWorkspace=self._output_wksp)
def testCalculateEfficiencyCorretionEfficiencyAndAlpha(self):
self.assertRaises(RuntimeError,
CalculateEfficiencyCorrection,
InputWorkspace=self._input_wksp,
Alpha=1.0,
MeasuredEfficiency=1.0,
OutputWorkspace=self._output_wksp)
def cleanUp(self):
if AnalysisDataService.doesExist(self._input_wksp):
DeleteWorkspace(self._input_wksp)
if AnalysisDataService.doesExist(self._output_wksp):
DeleteWorkspace(self._output_wksp)
if __name__ == "__main__":
unittest.main()
1d78382b08411d49a4189d8c68980fe1
.. algorithm::
.. summary::
.. relatedalgorithms::
.. properties::
Description
-----------
This algorithm calculates the detection efficiency correction, :math:`\epsilon`, defined by:
.. math::
:label: efficiency
\epsilon &= 1-e^{-\rho T \sigma_a (\lambda)} \\
&= 1-e^{-\rho_{A} \sigma_a (\lambda)} \\
&= 1-e^{-\alpha \lambda}
and output correction is given as:
.. math::
:label: efficiency_correction
\frac{1}{\epsilon} = \frac{1}{1-e^{-\alpha \lambda}}
where :math:`\rho` is the number density in :math:`atoms/\AA^3`,
:math:`T` is a sample thickness given in :math:`cm`,
:math:`\sigma_a(\lambda)` is the wavelength-dependent absorption cross-section given as
:math:`\sigma_a (\lambda) = \sigma_a (\lambda_{ref}) \left( \frac{\lambda}{\lambda_{ref}} \right)`,
in units of :math:`barns` and with :math:`\lambda_{ref}` = 1.7982 :math:`\AA`,
:math:`\rho_{A}` is the area density (:math:`\rho_{A}=\rho * T`) in units of :math:`atoms*cm/\AA^3`,
:math:`\alpha = \rho_{A} * \frac{\sigma_a (\lambda_{ref})}{\lambda_{ref}} = \rho * T * \frac{\sigma_a (\lambda_{ref})}{\lambda_{ref}}` in units of :math:`1/\AA`.
and :math:`\lambda` is in units of :math:`\AA`.
NOTE: :math:`1 \AA^2 = 10^{8} barns` and :math:`1 \AA = 10^{-8} cm`.
The optional inputs into the algorithm are to input either:
1. The ``Alpha`` parameter
2. The ``Density`` and ``ChemicalFormula`` to calculate the :math:`\sigma_a(\lambda_{ref})` term.
3. The ``MeasuredEfficiency``, an optional ``MeasuredEfficiencyWavelength``, and ``ChemicalFormula`` to calculate the :math:`\sigma_a(\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.
Usage
-----
**Example - Basics of running CalculateEfficiencyCorrection with Alpha.**
.. testcode:: ExBasicCalcualteEfficiencyCorrectionWithAlpha
# Create an exponentially decaying function in wavelength to simulate measured sample
input_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)
# Calculate the efficiency correction
correction_wksp = CalculateEfficiencyCorrection(InputWorkspace=input_wksp, Alpha=0.5)
# Apply the efficiency correction to the measured spectrum
input_wksp = ConvertToPointData(InputWorkspace=input_wksp)
output_wksp = Multiply(LHSWorkspace=input_wksp, RHSWorkspace=correction_wksp)
print('Input workspace: {}'.format(input_wksp.readY(0)[:5]))
print('Correction workspace: {}'.format(correction_wksp.readY(0)[:5]))
print('Output workspace: {}'.format(output_wksp.readY(0)[:5]))
Ouptut:
.. testoutput:: ExBasicCalcualteEfficiencyCorrectionWithAlpha
Input workspace: [ 38. 38. 38. 38. 38.]
Correction workspace: [ 10.26463773 9.81128219 9.39826191 9.02042771 8.67347109]
Output workspace: [ 390.05623383 372.82872321 357.13395265 342.77625306 329.59190131]
**Example - Basics of running CalculateEfficiencyCorrection with Density and ChemicalFormula.**
.. testcode:: ExBasicCalcualteEfficiencyCorrectionWithDensity
# Create an exponentially decaying function in wavelength to simulate measured sample
input_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)
# Calculate the efficiency correction
correction_wksp = CalculateEfficiencyCorrection(InputWorkspace=input_wksp,
Density=6.11,
ChemicalFormula="V")
# Apply the efficiency correction to the measured spectrum
input_wksp = ConvertToPointData(InputWorkspace=input_wksp)
output_wksp = Multiply(LHSWorkspace=input_wksp, RHSWorkspace=correction_wksp)
print('Input workspace: {}'.format(input_wksp.readY(0)[:5]))
print('Correction workspace: {}'.format(correction_wksp.readY(0)[:5]))
print('Output workspace: {}'.format(output_wksp.readY(0)[:5]))
Ouptut:
.. testoutput:: ExBasicCalcualteEfficiencyCorrectionWithDensity
Input workspace: [ 38. 38. 38. 38. 38.]
Correction workspace: [ 24.40910309 23.29738394 22.28449939 21.35783225 20.50682528]
Output workspace: [ 927.54591732 885.30058981 846.81097679 811.59762534 779.25936055]
**Example - Basics of running CalculateEfficiencyCorrection with MeasuredEfficiency and ChemicalFormula.**
.. testcode:: ExBasicCalcualteEfficiencyCorrectionWithEfficiency
# Create an exponentially decaying function in wavelength to simulate measured sample
input_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)
# Calculate the efficiency correction
correction_wksp = CalculateEfficiencyCorrection(InputWorkspace=input_wksp,
MeasuredEfficiency=1e-2,
ChemicalFormula="(He3)")
# Apply the efficiency correction to the measured spectrum
input_wksp = ConvertToPointData(InputWorkspace=input_wksp)
output_wksp = Multiply(LHSWorkspace=input_wksp, RHSWorkspace=correction_wksp)
print('Input workspace: {}'.format(input_wksp.readY(0)[:5]))
print('Correction workspace: {}'.format(correction_wksp.readY(0)[:5]))
print('Output workspace: {}'.format(output_wksp.readY(0)[:5]))
Ouptut:
.. testoutput:: ExBasicCalcualteEfficiencyCorrectionWithEfficiency
Input workspace: [ 38. 38. 38. 38. 38.]
Correction workspace: [ 873.27762699 832.68332786 795.69741128 761.85923269 730.78335476]
Output workspace: [ 33184.54982567 31641.9664586 30236.50162877 28950.65084207
27769.76748099]
**Example - Running CalculateEfficiencyCorrection for incident spectrum.**
To model the incident spectrum of polyethylene moderators, the following function is used to
join the exponential decay of the epithermal flux to the Maxwellian distribution of the thermal flux [1]_:
.. math::
:label: incident_spectrum
\phi(\lambda) = \phi_{max} \frac{\lambda_T^4}{\lambda^5} \mathrm{e}^{-(\lambda_T / \lambda)^2} + \phi_{epi} \frac{\Delta(\lambda_T / \lambda)}{\lambda^{1+2\alpha}}
To determine this incident spectrum experimentally, one must make a measurement either via using a sample measurement such as vanadium [1]_ or using beam monitors. [2]_ [3]_ In either case, an efficiency correction must be applied to the measured spectrum to obtain the actual incident spectrum. This incident spectrum is a crucial part of calculating Placzek recoil sample corrections. [4]_
From Eq. :eq:`incident_spectrum`, the parameters vary based on the moderator material. For a polyethlyene moderator at a temperature of 300K, the following parameters have been used to accurately model the incident spectrum. [1]_ The parameter labels, variables used in the following code example, and values for the parameters are given in the table below:
+--------------------+-------------+-----------------------------+
| Parameter | Variables | Polyethlyene 300K (ambient) |
+====================+=============+=============================+
| :math:`\phi_{max}` | ``phiMax`` | 6324 |
+--------------------+-------------+-----------------------------+
| :math:`\phi_{epi}` | ``phiEpi`` | 786 |
+--------------------+-------------+-----------------------------+
| :math:`\alpha` | ``alpha`` | 0.099 |
+--------------------+-------------+-----------------------------+
| :math:`\lambda_1` | ``lambda1`` | 0.67143 |
+--------------------+-------------+-----------------------------+
| :math:`\lambda_2` | ``lambda2`` | 0.06075 |
+--------------------+-------------+-----------------------------+
| :math:`\lambda_T` | ``lambdaT`` | 1.58 :math:`\AA` |
+--------------------+-------------+-----------------------------+
To first back out the measured spectrum of Milder et al. [1]_, the incident spectrum for polyethylene at 300K using Eq. :eq:`incident_spectrum` is obtained, then the efficiency correction is calculated, and then the incident spectrum is divided by this correction to back out what was originally measured. Then, the correction is applied by multiplying it by the measured spectrum to get back to the corrected incident spectrum to demonstrate how this is regularly apply this to a measured spectrum:
.. testcode:: ExIncidentSpectrum
# Create the workspace to hold the already corrected incident spectrum
incident_wksp_name = 'incident_spectrum_wksp'
binning = "%s,%s,%s" % (0.2,0.01,4.0)
incident_wksp = CreateWorkspace(OutputWorkspace=incident_wksp_name,
NSpec=1, DataX=[0], DataY=[0],
UnitX='Wavelength',
VerticalAxisUnit='Text',
VerticalAxisValues='IncidentSpectrum')
incident_wksp = Rebin(InputWorkspace=incident_wksp, Params=binning)
incident_wksp = ConvertToPointData(InputWorkspace=incident_wksp)
# Spectrum function given in Milder et al. Eq (5)
def incidentSpectrum(wavelengths, phiMax, phiEpi, alpha, lambda1, lambda2, lamdaT):
deltaTerm = 1. / (1. + np.exp((wavelengths - lambda1) / lambda2))
term1 = phiMax * (lambdaT**4. / wavelengths**5.) * np.exp(-(lambdaT / wavelengths)**2.)
term2 = phiEpi * deltaTerm / (wavelengths**(1 + 2 * alpha))
return term1 + term2
# Variables for polyethlyene moderator at 300K
phiMax = 6324
phiEpi = 786
alpha = 0.099
lambda1 = 0.67143
lambda2 = 0.06075
lambdaT = 1.58
# Add the incident spectrum to the workspace
corrected_spectrum = incidentSpectrum(incident_wksp.readX(0),
phiMax, phiEpi, alpha,
lambda1, lambda2, lambdaT)
incident_wksp.setY(0, corrected_spectrum)
# Calculate the efficiency correction for Alpha=0.693 and back calculate measured spectrum
eff_wksp = CalculateEfficiencyCorrection(InputWorkspace=incident_wksp, Alpha=0.693)
measured_wksp = Divide(LHSWorkspace=incident_wksp, RHSWorkspace=eff_wksp)
# Re-applying the correction to the measured data (how to normally use it)
eff2_wksp = CalculateEfficiencyCorrection(InputWorkspace=measured_wksp, Alpha=0.693)
recorrected_wksp = Multiply(LHSWorkspace=measured_wksp, RHSWorkspace=eff2_wksp)
print('Measured incident spectrum: {}'.format(measured_wksp.readY(0)[:5]))
print('Corrected incident spectrum: {}'.format(incident_wksp.readY(0)[:5]))
print('Re-corrected incident spectrum: {}'.format(recorrected_wksp.readY(0)[:5]))
Output:
.. testoutput:: ExIncidentSpectrum
Measured incident spectrum: [ 694.61415533 685.71520053 677.21326605 669.0696332 661.25022644]
Corrected incident spectrum: [ 5244.9385468 4953.63834159 4690.60136547 4451.98728342 4234.6092648 ]
Re-corrected incident spectrum: [ 5244.9385468 4953.63834159 4690.60136547 4451.98728342 4234.6092648 ]
References
------------
.. [1] D. F. R. Mildner, B. C. Boland, R. N. Sinclair, C. G. Windsor, L. J. Bunce, and J. H. Clarke (1977) *A Cooled Polyethylene Moderator on a Pulsed Neutron Source*, Nuclear Instruments and Methods 152 437-446 `doi: 10.1016/0029-554X(78)90043-5 <https://doi.org/10.1016/0029-554X(78)90043-5>`__
.. [2] J. P. Hodges, J. D. Jorgensen, S. Short, D. N. Argyiou, and J. W. Richardson, Jr. *Incident Spectrum Determination for Time-of-Flight Neutron Powder Diffraction Data Analysis* ICANS 14th Meeting of the International Collaboration on Advanced Neutron Sources 813-822 `link to paper <http://www.neutronresearch.com/parch/1998/01/199801008130.pdf>`__
.. [3] F. Issa, A. Khaplanov, R. Hall-Wilton, I. Llamas, M. Dalseth Ricktor, S. R. Brattheim, and H. Perrey (2017) *Characterization of Thermal Neutron Beam Monitors* Physical Review Accelerators and Beams 20 092801 `doi: 10.1103/PhysRevAccelBeams.20.092801 <https://doi.org/10.1103/PhysRevAccelBeams.20.092801>`__
.. [4] W. S. Howells (1983) *On the Choice of Moderator for Liquids Diffractometer on a Pulsed Neutron Source*, Nuclear Instruments and Methods in Physics Research 223 141-146 `doi: 10.1016/0167-5087(84)90256-4 <https://doi.org/10.1016/0167-5087(84)90256-4>`__
.. categories::
.. sourcelink::
......@@ -64,6 +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.
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