19#include "MantidHistogramData/Interpolate.h"
34using namespace Geometry;
35using HistogramData::interpolateLinearInplace;
36using namespace Kernel;
37using Kernel::DeltaEMode;
44constexpr size_t MAX_INTEGRATION_LENGTH{1000};
46const std::string CALC_SAMPLE =
"Sample";
47const std::string CALC_CONTAINER =
"Container";
48const std::string CALC_ENVIRONMENT =
"Environment";
50inline size_t findMiddle(
const size_t start,
const size_t stop) {
51 auto half =
static_cast<size_t>(floor(.5 * (
static_cast<double>(stop - start))));
56double energyToWavelength(
const double energyFixed) {
57 return 2. * M_PI * std::sqrt(E_mev_toNeutronWavenumberSq / energyFixed);
63 :
API::
Algorithm(), m_inputWS(), m_sampleObject(nullptr), m_L1s(), m_elementVolumes(), m_elementPositions(),
64 m_numVolumeElements(0), m_sampleVolume(0.0), m_linearCoefTotScatt(0), m_num_lambda(0), m_xStep(0),
65 m_emode(Kernel::
DeltaEMode::Undefined), m_lambdaFixed(0.), EXPONENTIAL() {}
70 auto wsValidator = std::make_shared<CompositeValidator>();
75 "The X values for the input workspace must be in units of wavelength");
77 "Output workspace name");
80 std::vector<std::string> scatter_options{CALC_SAMPLE, CALC_CONTAINER, CALC_ENVIRONMENT};
81 declareProperty(
"ScatterFrom", CALC_SAMPLE, std::make_shared<StringListValidator>(std::move(scatter_options)),
82 "The component to calculate the absorption for (default: Sample)");
84 auto mustBePositive = std::make_shared<BoundedValidator<double>>();
85 mustBePositive->setLower(0.0);
87 "The ABSORPTION cross-section, at 1.8 Angstroms, for the "
88 "sample material in barns. Column 8 of a table generated "
89 "from http://www.ncnr.nist.gov/resources/n-lengths/.");
91 "The (coherent + incoherent) scattering cross-section for "
92 "the sample material in barns. Column 7 of a table generated "
93 "from http://www.ncnr.nist.gov/resources/n-lengths/.");
95 "The number density of the sample in number of atoms per "
96 "cubic angstrom if not set with SetSampleMaterial");
98 auto positiveInt = std::make_shared<BoundedValidator<int64_t>>();
99 positiveInt->setLower(1);
101 "The number of wavelength points for which the numerical integral is\n"
102 "calculated (default: all points)");
104 std::vector<std::string> exp_options{
"Normal",
"FastApprox"};
105 declareProperty(
"ExpMethod",
"Normal", std::make_shared<StringListValidator>(exp_options),
106 "Select the method to use to calculate exponentials, normal or a\n"
107 "fast approximation (default: Normal)");
109 std::vector<std::string> propOptions{
"Elastic",
"Direct",
"Indirect"};
110 declareProperty(
"EMode",
"Elastic", std::make_shared<StringListValidator>(propOptions),
111 "The energy mode (default: elastic)");
113 "The value of the initial or final energy, as appropriate, in meV.\n"
114 "Will be taken from the instrument definition file, if available.");
122 std::map<std::string, std::string> result;
125 const std::string scatterFrom =
getProperty(
"ScatterFrom");
126 if (scatterFrom != CALC_SAMPLE) {
128 const auto &sample = wksp->sample();
129 if (sample.hasEnvironment()) {
130 const auto numComponents = sample.getEnvironment().nelements();
132 if (scatterFrom == CALC_CONTAINER && numComponents == 0) {
133 result[
"ScatterFrom"] =
"Sample does not have a container defined";
134 }
else if (scatterFrom == CALC_ENVIRONMENT) {
135 if (numComponents < 2) {
136 result[
"ScatterFrom"] =
"Sample does not have an environment defined";
137 }
else if (numComponents > 2) {
138 std::stringstream msg;
139 msg <<
"Do not know how to calculate absorption from multiple "
140 "component sample environment. Encountered "
141 << numComponents <<
" components";
142 result[
"ScatterFrom"] = msg.str();
146 if (scatterFrom == CALC_CONTAINER)
147 result[
"ScatterFrom"] =
"Sample does not have a container defined";
148 else if (scatterFrom == CALC_ENVIRONMENT)
149 result[
"ScatterFrom"] =
"Sample does not have an environment defined";
169 correctionFactors->setDistribution(
true);
170 correctionFactors->setYUnit(
"");
171 correctionFactors->setYUnitLabel(
"Attenuation factor");
175 const auto numHists =
static_cast<int64_t
>(
m_inputWS->getNumberHistograms());
176 const auto specSize =
static_cast<int64_t
>(
m_inputWS->blocksize());
186 std::ostringstream message;
187 message <<
"Numerical integration performed every " <<
m_xStep <<
" wavelength points";
194 throw std::runtime_error(
"Failed to define any initial scattering gauge volume for geometry");
197 const auto &spectrumInfo =
m_inputWS->spectrumInfo();
198 Progress prog(
this, 0.0, 1.0, numHists);
201 for (int64_t i = 0; i < int64_t(numHists); ++i) {
204 correctionFactors->setSharedX(i,
m_inputWS->sharedX(i));
206 if (!spectrumInfo.hasDetectors(i)) {
207 g_log.
information() <<
"Spectrum " << i <<
" does not have a detector defined for it\n";
210 const auto &det = spectrumInfo.detector(i);
221 lambdaFixed = energyToWavelength(par->value<
double>());
223 }
catch (std::runtime_error &) {
230 const auto wavelengths =
m_inputWS->points(i);
235 auto &
Y = correctionFactors->mutableY(i);
238 for (int64_t j = 0; j < specSize; j = j +
m_xStep) {
240 Y[j] = this->
doIntegration(-linearCoefAbs[j], L2s, 0, L2s.size());
242 Y[j] = this->
doIntegration(linearCoefAbsFixed, -linearCoefAbs[j], L2s, 0, L2s.size());
244 Y[j] = this->
doIntegration(-linearCoefAbs[j], linearCoefAbsFixed, L2s, 0, L2s.size());
246 throw std::runtime_error(
"AbsorptionCorrection doesn't have a known DeltaEMode defined");
251 if (
m_xStep > 1 && j +
m_xStep >= specSize && j + 1 != specSize) {
259 auto histnew = correctionFactors->histogram(i);
260 interpolateLinearInplace(histnew,
m_xStep);
261 correctionFactors->setHistogram(i, histnew);
281 double sigma_atten =
getProperty(
"AttenuationXSection");
282 double sigma_s =
getProperty(
"ScatteringXSection");
284 const std::string scatterFrom =
getProperty(
"ScatterFrom");
288 const auto &sampleObj =
m_inputWS->sample();
289 if (scatterFrom == CALC_SAMPLE) {
291 }
else if (scatterFrom == CALC_CONTAINER) {
292 m_material = sampleObj.getEnvironment().getContainer().material();
293 }
else if (scatterFrom == CALC_ENVIRONMENT) {
294 m_material = sampleObj.getEnvironment().getComponent(1).material();
297 if (createMaterial) {
307 NeutronAtom neutron(0, 0, 0.0, 0.0, sigma_s, 0.0, sigma_s, sigma_atten);
310 auto shape = std::shared_ptr<IObject>(
311 m_inputWS->sample().getShape().cloneWithMaterial(
Material(
"SetInAbsorptionCorrection", neutron,
rho)));
312 m_inputWS->mutableSample().setShape(shape);
325 if (exp_string ==
"Normal")
327 else if (exp_string ==
"FastApprox")
333 if (emodeStr ==
"Direct")
335 else if (emodeStr ==
"Indirect")
337 else if (emodeStr ==
"Elastic")
340 std::stringstream msg;
341 msg <<
"Unknown EMode \"" << emodeStr <<
"\"";
342 throw std::runtime_error(msg.str());
357 const std::string xmlstring =
sampleXML();
358 const std::string scatterFrom =
getProperty(
"ScatterFrom");
359 if (xmlstring.empty()) {
361 if (scatterFrom == CALC_SAMPLE)
363 else if (scatterFrom == CALC_CONTAINER)
365 else if (scatterFrom == CALC_ENVIRONMENT)
368 throw std::runtime_error(
"Somebody forgot to fill in an if/else tree");
372 const std::string mess(
"No shape has been defined for the sample in the input workspace");
374 throw std::invalid_argument(mess);
376 }
else if (scatterFrom != CALC_SAMPLE) {
377 std::stringstream msg;
378 msg <<
"Cannot use geometry xml for ScatterFrom=" << scatterFrom;
379 throw std::runtime_error(msg.str());
395 if (detector.
nDets() > 1) {
399 detector.
getPhi() * 180.0 / M_PI);
419 const size_t startIndex,
const size_t endIndex)
const {
420 if (endIndex - startIndex > MAX_INTEGRATION_LENGTH) {
421 size_t middle = findMiddle(startIndex, endIndex);
425 double integral = 0.0;
428 for (
size_t i = startIndex; i < endIndex; ++i) {
440 const std::vector<double> &L2s,
const size_t startIndex,
441 const size_t endIndex)
const {
442 if (endIndex - startIndex > MAX_INTEGRATION_LENGTH) {
443 size_t middle = findMiddle(startIndex, endIndex);
445 return doIntegration(linearCoefAbsL1, linearCoefAbsL2, L2s, startIndex, middle) +
446 doIntegration(linearCoefAbsL1, linearCoefAbsL2, L2s, middle, endIndex);
448 double integral = 0.0;
451 for (
size_t i = startIndex; i < endIndex; ++i) {
#define PARALLEL_START_INTERRUPT_REGION
Begins a block to skip processing is the algorithm has been interupted Note the end of the block if n...
#define PARALLEL_END_INTERRUPT_REGION
Ends a block to skip processing is the algorithm has been interupted Note the start of the block if n...
#define PARALLEL_FOR_IF(condition)
Empty definitions - to enable set your complier to enable openMP.
#define PARALLEL_CHECK_INTERRUPT_REGION
Adds a check after a Parallel region to see if it was interupted.
Base class from which all concrete algorithm classes should be derived.
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
static bool isEmpty(const NumT toCheck)
checks that the value was not set by users, uses the value in empty double/int.
A validator which checks that a workspace has a valid instrument.
Helper class for reporting progress from algorithms.
This class stores information about the sample used in particular run.
void setShape(const Geometry::IObject_sptr &shape)
Update the shape of the object.
const Geometry::IObject & getShape() const
Return the sample shape.
const Geometry::SampleEnvironment & getEnvironment() const
Get a reference to the sample's environment.
A property class for workspaces.
A validator which checks that the unit of the workspace referred to by a WorkspaceProperty is the exp...
std::vector< double > m_elementVolumes
Cached element volumes.
std::map< std::string, std::string > validateInputs() override
Method checking errors on ALL the inputs, before execution.
void retrieveBaseProperties()
Fetch the properties and set the appropriate member variables.
int64_t m_xStep
interpolated linearly
virtual void retrieveProperties()
A virtual function in which additional properties should be retrieved into member variables.
void exec() override
Execution code.
virtual void defineProperties()
A virtual function in which additional properties of an algorithm should be declared.
double m_linearCoefTotScatt
The total scattering cross-section in 1/m.
double m_lambdaFixed
The wavelength corresponding to the fixed energy,.
Kernel::V3D m_beamDirection
The direction of the beam.
expfunction EXPONENTIAL
Pointer to exponential function.
double m_sampleVolume
The total volume of the sample.
double doIntegration(const double linearCoefAbs, const std::vector< double > &L2s, const size_t startIndex, const size_t endIndex) const
Carries out the numerical integration over the sample for elastic instruments.
API::MatrixWorkspace_sptr m_inputWS
A pointer to the input workspace.
AbsorptionCorrection()
(Empty) Constructor
const Geometry::IObject * m_sampleObject
Local cache of sample object.
Kernel::DeltaEMode::Type m_emode
size_t m_numVolumeElements
The number of volume elements.
std::vector< Kernel::V3D > m_elementPositions
Cached element positions.
std::vector< double > m_L1s
Cached L1 distances.
void constructSample(API::Sample &sample)
Create the sample object using the Geometry classes, or use the existing one.
void calculateDistances(const Geometry::IDetector &detector, std::vector< double > &L2s) const
Calculate the distances traversed by the neutrons within the sample.
void init() override
Initialisation code.
virtual std::string sampleXML()=0
Returns the XML string describing the sample, which can be used by the ShapeFactory.
Kernel::Material m_material
int64_t m_num_lambda
The number of points in wavelength, the rest is.
virtual void initialiseCachedDistances()=0
Calculate the distances for L1 and element size for each element in the sample.
virtual Kernel::V3D getPos() const =0
Get the position of the IComponent. Tree structure is traverse through the.
Interface class for detector objects.
virtual double getPhi() const =0
Gives the phi of this detector object in radians.
virtual std::size_t nDets() const =0
Get the number of physical detectors this object represents.
virtual double getTwoTheta(const Kernel::V3D &observer, const Kernel::V3D &axis) const =0
Gives the angle of this detector object with respect to an axis.
virtual int interceptSurface(Geometry::Track &) const =0
virtual bool hasValidShape() const =0
const Container & getContainer() const
const IObject & getComponent(const size_t index) const
Returns the requested IObject.
Class originally intended to be used with the DataHandling 'LoadInstrument' algorithm.
std::shared_ptr< CSGObject > createShape(Poco::XML::Element *pElem)
Creates a geometric object from a DOM-element-node pointing to an element whose child nodes contain t...
Defines a track as a start point and a direction.
double totalDistInsideObject() const
Returns the sum of all the links distInsideObject in the track.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void error(const std::string &msg)
Logs at error level.
void information(const std::string &msg)
Logs at information level.
A material is defined as being composed of a given element, defined as a PhysicalConstants::NeutronAt...
double absorbXSection(const double lambda=PhysicalConstants::NeutronAtom::ReferenceLambda) const
Get the absorption cross section at a given wavelength in barns.
double numberDensityEffective() const
Get the effective number density.
double linearAbsorpCoef(const double lambda=PhysicalConstants::NeutronAtom::ReferenceLambda) const
Returns the linear coefficient of absorption for the material in units of cm^-1 this should match the...
double totalScatterXSection() const
Return the total scattering cross section for a given wavelength in barns.
void report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
void spherical(const double R, const double theta, const double phi) noexcept
Sets the vector position based on spherical coordinates.
double norm() const noexcept
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
std::shared_ptr< Parameter > Parameter_sptr
Typedef for the shared pointer.
double fast_exp(double y)
std::enable_if< std::is_pointer< Arg >::value, bool >::type threadSafe(Arg workspace)
Thread-safety check Checks the workspace to ensure it is suitable for multithreaded access.
MANTID_KERNEL_DLL V3D normalize(V3D v)
Normalizes a V3D.
A namespace containing physical constants that are required by algorithms and unit routines.
static constexpr double E_mev_toNeutronWavenumberSq
Transformation coefficient to transform neutron energy into neutron wavevector: K-neutron[m^-10] = sq...
constexpr int EMPTY_INT() noexcept
Returns what we consider an "empty" integer within a property.
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Generate a tableworkspace to store the calibration results.
Defines the possible energy transfer modes:
@ Input
An input workspace.
@ Output
An output workspace.
Structure to store neutronic scattering information for the various elements.
static const double ReferenceLambda
The reference wavelength value for absorption cross sections.