28double calculateSummationTerm(
const Kernel::Material &material) {
30 const auto &formula = material.chemicalFormula();
31 auto sumLambda = [](
double sum,
const auto &formula_unit) {
32 return sum + formula_unit.multiplicity * formula_unit.atom->neutron.tot_scatt_xs / formula_unit.atom->mass;
34 const double unnormalizedTerm = std::accumulate(formula.begin(), formula.end(), 0.0, sumLambda);
39 const double totalStoich = material.totalAtoms();
41 return neutronMass * unnormalizedTerm / (4. * M_PI * totalStoich);
51 "Raw diffraction data workspace for associated correction to be "
52 "calculated for. Workspace must have instrument and sample data.");
53 auto inspValidator = std::make_shared<Mantid::Kernel::CompositeValidator>();
57 "Workspace of fitted incident spectrum with it's first derivative. Must be in units of Wavelength.");
60 "Workspace with the Self scattering correction, in the same unit as the InputWorkspace.");
61 declareProperty(
"CrystalDensity",
EMPTY_DBL(),
"The crystalographic density of the sample material.");
62 declareProperty(
"ScaleByPackingFraction",
true,
"Scale the correction value by packing fraction.");
68 std::map<std::string, std::string> issues;
71 if (specInfo.
size() == 0) {
72 issues[
"InputWorkspace"] =
"Input workspace does not have detector information";
75 if (formula.size() == 0) {
76 issues[
"InputWorkspace"] =
"Input workspace does not have a valid sample";
84 const auto &material = ws->sample().getMaterial();
87 double packingFraction = material.packingFraction();
90 const double crystalDensity =
getProperty(
"CrystalDensity");
91 if (crystalDensity > 0. && !
isEmpty(crystalDensity)) {
93 packingFraction = material.numberDensity() / crystalDensity;
96 return packingFraction;
105 const bool scaleByPackingFraction =
getProperty(
"ScaleByPackingFraction");
106 auto inputUnit = inWS->getAxis(0)->unit();
109 const double summationTerm = calculateSummationTerm(inWS->sample().getMaterial());
113 const MantidVec xLambda = incidentWS->readX(0);
114 const MantidVec incident = incidentWS->readY(0);
115 const MantidVec incidentPrime = incidentWS->readY(1);
116 const double dx = (xLambda[1] - xLambda[0]) / 2.0;
117 std::vector<double> phi1;
118 for (
size_t i = 0; i < xLambda.size() - 1; i++) {
119 phi1.emplace_back((xLambda[i] + dx) * incidentPrime[i] / incident[i]);
122 std::vector<double> eps1;
123 constexpr auto LambdaD = 1.44;
124 for (
size_t i = 0; i < xLambda.size() - 1; i++) {
125 const auto xTerm = -(xLambda[i] + dx) / LambdaD;
126 eps1.emplace_back(xTerm * exp(xTerm) / (1.0 - exp(xTerm)));
139 const auto &specInfo = inWS->spectrumInfo();
144 DataObjects::create<API::HistoWorkspace>(*inWS, incidentWS->getSpectrum(0).binEdges());
146 outputWS->getAxis(0)->unit() = incidentWS->getAxis(0)->unit();
149 outputWS->setDistribution(
true);
150 outputWS->setYUnit(
"");
151 for (
size_t specIndex = 0; specIndex < specInfo.size(); specIndex++) {
152 auto &
y = outputWS->mutableY(specIndex);
153 double l1 = specInfo.l1();
154 double l2 = specInfo.l2(specIndex);
156 if (!specInfo.isMonitor(specIndex) && !(specInfo.l2(specIndex) == 0.0)) {
157 double twoTheta = specInfo.twoTheta(specIndex);
158 const double sinThetaBy2 = sin(
twoTheta / 2.0);
159 const double f = l1 / (l1 +
l2);
160 for (
size_t xIndex = 0; xIndex < xLambda.size() - 1; xIndex++) {
161 const double term1 = (f - 1.0) * phi1[xIndex];
162 const double term2 = f * (1.0 - eps1[xIndex]);
163 const double inelasticPlaczekSelfCorrection =
164 2.0 * (term1 + term2 - 3) * sinThetaBy2 * sinThetaBy2 * summationTerm;
166 scaleByPackingFraction ? inelasticPlaczekSelfCorrection * packingFraction : inelasticPlaczekSelfCorrection;
169 for (
size_t xIndex = 0; xIndex < xLambda.size() - 1; xIndex++) {
176 cvtalg->setProperty(
"InputWorkspace", outputWS);
177 cvtalg->setProperty(
"OutputWorkspace", outputWS);
178 cvtalg->setProperty(
"Target", inputUnit->unitID());
180 outputWS = cvtalg->getProperty(
"OutputWorkspace");
#define DECLARE_ALGORITHM(classname)
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
virtual std::shared_ptr< Algorithm > createChildAlgorithm(const std::string &name, const double startProgress=-1., const double endProgress=-1., const bool enableLogging=true, const int &version=-1)
Create a Child Algorithm.
static bool isEmpty(const NumT toCheck)
checks that the value was not set by users, uses the value in empty double/int.
API::SpectrumInfo is an intermediate step towards a SpectrumInfo that is part of Instrument-2....
size_t size() const
Returns the size of the SpectrumInfo, i.e., the number of spectra.
A property class for workspaces.
A validator which checks that the unit of the workspace referred to by a WorkspaceProperty is the exp...
CalculatePlaczekSelfScattering : This algorithm calculates a correction for an incident spectrum defr...
double getPackingFraction(const API::MatrixWorkspace_const_sptr &ws)
void exec() override
Execute the algorithm.
std::map< std::string, std::string > validateInputs() override
Validate inputs.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
std::vector< FormulaUnit > ChemicalFormula
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
static constexpr double NeutronMass
Mass of the neutron in kg.
static constexpr double AtomicMassUnit
AMU in kg.
std::vector< double > MantidVec
typedef for the data storage used in Mantid matrix workspaces
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
@ Input
An input workspace.
@ Output
An output workspace.