forked from AmbaPant/mantid
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathCalculateSampleTransmission.py
134 lines (100 loc) · 5.25 KB
/
CalculateSampleTransmission.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# 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 & CSNS, Institute of High Energy Physics, CAS
# SPDX - License - Identifier: GPL - 3.0 +
#pylint: disable=no-init,invalid-name
from mantid.simpleapi import *
from mantid.api import *
from mantid.kernel import *
import math
import numpy as np
class CalculateSampleTransmission(PythonAlgorithm):
_bin_params = None
_chemical_formula = None
_density_type = None
_density = None
_thickness = None
_output_ws = None
def category(self):
return 'Sample'
def seeAlso(self):
return [ "SetSampleMaterial" ]
def summary(self):
return 'Calculates the scattering & transmission for a given sample material and size over a given wavelength range.'
def PyInit(self):
self.declareProperty(name='WavelengthRange', defaultValue='',
validator=StringMandatoryValidator(),
doc='Wavelength range to calculate transmission for.')
self.declareProperty(name='ChemicalFormula', defaultValue='',
validator=StringMandatoryValidator(),
doc='Sample chemical formula')
self.declareProperty(name='DensityType', defaultValue = 'Mass Density',
validator=StringListValidator(['Mass Density', 'Number Density']),
doc = 'Use of Mass density or Number density')
self.declareProperty(name='Density', defaultValue=0.1,
doc='Mass density (g/cm^3) or Number density (atoms/Angstrom^3). Default=0.1')
self.declareProperty(name='Thickness', defaultValue=0.1,
doc='Sample thickness (cm). Default=0.1')
self.declareProperty(MatrixWorkspaceProperty('OutputWorkspace', '', Direction.Output),
doc='Outputs the sample transmission over the wavelength range as a function of wavelength.')
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'
return issues
def PyExec(self):
self._setup()
# Create the workspace and set the sample material
CreateWorkspace(OutputWorkspace=self._output_ws, NSpec=2, DataX=[0, 1], DataY=[0, 0],
VerticalAxisUnit='Text', VerticalAxisValues='Transmission,Scattering')
Rebin(InputWorkspace=self._output_ws, OutputWorkspace=self._output_ws,
Params=self._bin_params)
if self._density_type == 'Mass Density':
builder = MaterialBuilder()
mat = builder.setFormula(self._chemical_formula).setMassDensity(self._density).build()
self._density = mat.numberDensity
SetSampleMaterial(InputWorkspace=self._output_ws, ChemicalFormula=self._chemical_formula, SampleNumberDensity=self._density)
ConvertToPointData(InputWorkspace=self._output_ws, OutputWorkspace=self._output_ws)
ws = mtd[self._output_ws]
wavelengths = ws.readX(0)
transmission_data = np.zeros(len(wavelengths))
scattering_data = np.zeros(len(wavelengths))
# Calculate transmission and scattering for each wavelength point
for idx in range(0, len(wavelengths)):
transmission, scattering = self._calculate_at_wavelength(wavelengths[idx])
transmission_data[idx] = transmission
scattering_data[idx] = scattering
ws.setY(0, transmission_data)
ws.setY(1, scattering_data)
self.setProperty('OutputWorkspace', self._output_ws)
def _setup(self):
"""
Gets algorithm properties.
"""
self._bin_params = self.getPropertyValue('WavelengthRange')
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._output_ws = self.getPropertyValue('OutputWorkspace')
def _calculate_at_wavelength(self, wavelength):
"""
Calculates transmission and scattering at a given wavelength.
@param wavelength Wavelength at which to calculate (in Angstroms)
@return Tuple of transmission and scattering percentages
"""
TABULATED_WAVELENGTH = 1.798
material = mtd[self._output_ws].mutableSample().getMaterial()
absorption_x_section = material.absorbXSection() * wavelength / TABULATED_WAVELENGTH
total_x_section = absorption_x_section + material.totalScatterXSection()
transmission = math.exp(-self._density * total_x_section * self._thickness)
scattering = 1.0 - math.exp(-self._density * material.totalScatterXSection() * self._thickness)
return transmission, scattering
# Register algorithm with Mantid
AlgorithmFactory.subscribe(CalculateSampleTransmission)