29using namespace Kernel;
30using namespace CurveFitting;
31using namespace CurveFitting::Functions;
33using std::placeholders::_1;
45double DEG2RAD = M_PI / 180.0;
47double ABSORB_WAVELENGTH = 1.83618;
59VesuvioCalculateGammaBackground::VesuvioCalculateGammaBackground()
60 :
Algorithm(), m_inputWS(), m_indices(), m_profileFunction(), m_npeaks(0), m_reversed(), m_samplePos(), m_l1(0.0),
61 m_foilRadius(0.0), m_foilUpMin(0.0), m_foilUpMax(0.0), m_foils0(), m_foils1(), m_backgroundWS(), m_correctedWS() {
65VesuvioCalculateGammaBackground::~VesuvioCalculateGammaBackground() {
m_indices.clear(); }
71const std::string VesuvioCalculateGammaBackground::name()
const {
return "VesuvioCalculateGammaBackground"; }
73int VesuvioCalculateGammaBackground::version()
const {
return 1; }
75const std::string VesuvioCalculateGammaBackground::category()
const {
76 return "CorrectionFunctions\\BackgroundCorrections";
79void VesuvioCalculateGammaBackground::init() {
81 auto wsValidator = std::make_shared<CompositeValidator>();
85 "An input workspace containing TOF data");
88 "Function that is able to compute the mass spectrum for the input data"
89 "This will usually be the output from the Fitting");
92 "Indices of the spectra to include in the correction. If "
93 "provided, the output only include these spectra\n"
94 "(Default: all spectra from input)");
97 "A new workspace containing the calculated background.");
99 "A new workspace containing the calculated background subtracted from "
103void VesuvioCalculateGammaBackground::exec() {
107 const auto nhist =
static_cast<int64_t
>(
m_indices.size());
109 m_progress = std::make_unique<Progress>(
this, 0.0, 1.0, nreports);
112 for (int64_t i = 0; i < nhist; ++i) {
114 const size_t outputIndex = i;
116 std::advance(indexIter, i);
117 const size_t inputIndex = indexIter->second;
139bool VesuvioCalculateGammaBackground::calculateBackground(
const size_t inputIndex,
const size_t outputIndex) {
147 const auto &inSpec =
m_inputWS->getSpectrum(inputIndex);
148 const specnum_t spectrumNo(inSpec.getSpectrumNo());
150 m_correctedWS->getSpectrum(outputIndex).copyInfoFrom(inSpec);
152 if (spectrumNo >= FORWARD_SCATTER_SPECMIN && spectrumNo <= FORWARD_SCATTER_SPECMAX) {
156 " not in forward scatter range. Skipping correction.");
174void VesuvioCalculateGammaBackground::applyCorrection(
const size_t inputIndex,
const size_t outputIndex) {
175 m_progress->report(
"Computing TOF from detector");
184 m_progress->report(
"Computing correction to input");
188 const auto &inY =
m_inputWS->y(inputIndex);
193 double dataCounts(0.0), simulCounts(0.0);
194 for (
size_t j = 0; j < nbins; ++j) {
195 dataCounts += inY[j] * deltaT;
196 simulCounts += (detY[j] - foilY[j]) * deltaT;
200 const double corrFactor = dataCounts / simulCounts;
201 if (
g_log.
is(Logger::Priority::PRIO_INFORMATION))
202 g_log.
information() <<
"Correction factor for background=" << corrFactor <<
"\n";
204 for (
size_t j = 0; j < nbins; ++j) {
207 double &foilValue = foilY[j];
208 foilValue *= corrFactor;
209 detY[j] = (inY[j] - foilValue);
219void VesuvioCalculateGammaBackground::calculateSpectrumFromDetector(
const size_t inputIndex,
const size_t outputIndex) {
229 std::vector<double> tmpWork(ctdet.size());
232 const double detDistCorr = 0.5 / detPar.
l2 / detPar.
l2;
233 std::transform(ctdet.begin(), ctdet.end(), ctdet.begin(), std::bind(std::multiplies<double>(), _1, detDistCorr));
243void VesuvioCalculateGammaBackground::calculateBackgroundFromFoils(
const size_t inputIndex,
const size_t outputIndex) {
250 std::vector<double> foilSpectrum(nxvalues);
255 for (
size_t i = 0; i <
m_foils0.size(); ++i) {
256 foilSpectrum.assign(nxvalues, 0.0);
259 std::transform(ctfoil.begin(), ctfoil.end(), foilSpectrum.begin(), ctfoil.begin(), std::plus<double>());
261 foilSpectrum.assign(nxvalues, 0.0);
264 std::transform(ctfoil.begin(), ctfoil.end(), foilSpectrum.begin(), ctfoil.begin(), std::minus<double>());
266 bool reversed = (
m_reversed.count(
m_inputWS->getSpectrum(inputIndex).getSpectrumNo()) != 0);
270 std::transform(ctfoil.begin(), ctfoil.end(), ctfoil.begin(), std::bind(std::multiplies<double>(), _1, -1.0));
287void VesuvioCalculateGammaBackground::calculateBackgroundSingleFoil(std::vector<double> &ctfoil,
const size_t wsIndex,
296 const double thetaStep = (foilInfo.
thetaMax - foilInfo.
thetaMin) /
static_cast<double>(NTHETA);
297 const double thetaStepRad = thetaStep * DEG2RAD;
299 const double elementArea = abs(
m_foilRadius * upStep * thetaStepRad);
309 const size_t nvalues = ctfoil.size();
310 std::vector<double> singleElement(nvalues), tmpWork(nvalues);
312 for (
size_t i = 0; i < NTHETA; ++i) {
313 double thetaZeroRad = (foilInfo.
thetaMin + (
static_cast<double>(i) + 0.5) * thetaStep) * DEG2RAD;
316 for (
size_t j = 0; j < NUP; ++j) {
317 double ypos =
m_foilUpMin + (
static_cast<double>(j) + 0.5) * upStep;
318 elementPos.
setY(ypos);
323 singleElement.assign(nvalues, 0.0);
327 const double den = (elementPos.
Z() * cos(thetaZeroRad) + elementPos.
X() * sin(thetaZeroRad));
328 const double absorbFactor = 1.0 / (1.0 - exp(-ABSORB_WAVELENGTH * foilPar.
l2 / den));
329 const double elemDetDist = elementPos.
distance(detPos);
330 const double distFactor = elementArea / (4.0 * M_PI * foilPar.
l2 * foilPar.
l2 * elemDetDist * elemDetDist);
332 for (
size_t k = 0; k < nvalues; ++k) {
333 ctfoil[k] += singleElement[k] * absorbFactor * distFactor;
348std::vector<double> VesuvioCalculateGammaBackground::calculateTofSpectrum(
const std::vector<double> &inSpectrum,
349 std::vector<double> &tmpWork,
350 const size_t wsIndex,
353 assert(inSpectrum.size() == tmpWork.size());
357 std::transform(tseconds.begin(), tseconds.end(), tseconds.begin(), std::bind(std::multiplies<double>(), _1, 1e-6));
362 auto profileFunction =
365 std::vector<double> correctedVals(inSpectrum);
367 for (
size_t i = 0; i <
m_npeaks; ++i) {
368 auto profile = std::dynamic_pointer_cast<CurveFitting::Functions::ComptonProfile>(profileFunction->getFunction(i));
369 profile->disableLogging();
370 profile->setUpForFit();
375 profile->cacheYSpaceValues(
m_backgroundWS->points(wsIndex), detpar, respar);
377 profile->massProfile(tmpWork.data(), tmpWork.size());
380 std::transform(correctedVals.begin(), correctedVals.end(), tmpWork.begin(), correctedVals.begin(),
381 std::plus<double>());
385 std::transform(tseconds.begin(), tseconds.end(), tseconds.begin(), std::bind(std::multiplies<double>(), _1, 1e6));
386 return correctedVals;
392void VesuvioCalculateGammaBackground::retrieveInputs() {
401 if (
auto composite = std::dynamic_pointer_cast<CompositeFunction>(profileFunction)) {
403 for (
size_t i = 0; i <
m_npeaks; ++i) {
404 auto single = std::dynamic_pointer_cast<CurveFitting::Functions::ComptonProfile>(composite->getFunction(i));
406 throw std::invalid_argument(
"Invalid function. Composite must contain "
407 "only ComptonProfile functions");
411 throw std::invalid_argument(
"Invalid function found. Expected ComptonFunction to contain a "
412 "composite of ComptonProfiles or a single ComptonProfile.");
418 if ((i >= 143 && i <= 150) || (i >= 159 && i <= 166) || (i >= 175 && i <= 182) || (i >= 191 && i <= 198))
424 std::vector<int> requestedIndices =
getProperty(
"WorkspaceIndexList");
425 if (requestedIndices.empty()) {
426 for (
size_t i = 0; i <
m_inputWS->getNumberHistograms(); ++i) {
430 for (
size_t i = 0; i < requestedIndices.size(); ++i) {
431 m_indices.emplace(i,
static_cast<size_t>(requestedIndices[i]));
441void VesuvioCalculateGammaBackground::createOutputWorkspaces() {
447void VesuvioCalculateGammaBackground::cacheInstrumentGeometry() {
449 auto refFrame = inst->getReferenceFrame();
450 auto upAxis = refFrame->pointingUp();
451 auto source = inst->getSource();
452 auto sample = inst->getSample();
457 auto changer = std::dynamic_pointer_cast<const Geometry::IObjComponent>(inst->getComponentByName(
"foil-changer"));
459 throw std::invalid_argument(
"Input workspace has no component named foil-changer. "
460 "One is required to define integration area.");
465 changer->getBoundingBox(boundBox);
472 auto foils0 = inst->getAllComponentsWithName(
"foil-pos0");
473 auto foils1 = inst->getAllComponentsWithName(
"foil-pos1");
474 const size_t nfoils = foils0.size();
475 if (nfoils != foils1.size()) {
476 std::ostringstream os;
477 os <<
"Mismatch in number of foils between pos 0 & 1: pos0=" << nfoils <<
", pos1=" << foils1.size();
478 throw std::runtime_error(os.str());
482 auto firstFoilPos = foils0[0]->getPos();
489 for (
size_t i = 0; i < nfoils; ++i) {
490 const auto &foil0 = foils0[i];
499 const auto &foil1 = foils1[i];
508 if (
g_log.
is(Kernel::Logger::Priority::PRIO_INFORMATION)) {
509 std::ostringstream os;
510 os <<
"Instrument geometry:\n"
511 <<
" l1 = " <<
m_l1 <<
"m\n"
513 <<
" foil integration min = " <<
m_foilUpMin <<
"\n"
514 <<
" foil integration max = " <<
m_foilUpMax <<
"\n";
515 std::ostringstream secondos;
516 for (
size_t i = 0; i < nfoils; ++i) {
518 os <<
" foil theta range in position 0: theta_min=" << descr0.thetaMin <<
", theta_max=" << descr0.thetaMax
521 secondos <<
" foil theta range in position 1: theta_min=" << descr1.thetaMin <<
", theta_max=" << descr1.thetaMax
536std::pair<double, double>
538 const double radius,
const unsigned int horizDir)
const {
539 auto shapedObject = std::dynamic_pointer_cast<const Geometry::IObjComponent>(foilComp);
541 throw std::invalid_argument(
"A foil has been defined without a shape. "
542 "Please check instrument definition.");
546 auto pos = foilComp->getPos();
547 double theta(0.0), dummy(0.0);
548 pos.getSpherical(dummy, theta, dummy);
549 if (pos[horizDir] < 0.0)
553 const auto &box = shapedObject->shape()->getBoundingBox();
555 double xmax = box.maxPoint()[0];
556 double dtheta = std::asin(xmax /
radius) * 180.0 / M_PI;
557 return std::make_pair(theta - dtheta, theta + dtheta);
#define DECLARE_ALGORITHM(classname)
#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.
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
A validator which checks that a workspace contains histogram data (the default) or point data as requ...
A property class for workspaces.
A validator which checks that the unit of the workspace referred to by a WorkspaceProperty is the exp...
static DetectorParams getDetectorParameters(const API::MatrixWorkspace_const_sptr &ws, const size_t index)
Creates a POD struct containing the required detector parameters for this spectrum.
static double getComponentParameter(const Geometry::IComponent &det, const Geometry::ParameterMap &pmap, const std::string &name)
Retrieve a component parameter.
void calculateBackgroundFromFoils(const size_t inputIndex, const size_t outputIndex)
Compute the expected background from the foils.
double m_foilRadius
Radius of (imaginary) circle that foils sit on.
std::set< specnum_t > m_reversed
List of spectra numbers whose background sum is to be reversed.
Kernel::V3D m_samplePos
Sample position.
void calculateBackgroundSingleFoil(std::vector< double > &ctfoil, const size_t wsIndex, const FoilInfo &foilInfo, const Kernel::V3D &detPos, const DetectorParams &detPar, const CurveFitting::Functions::ResolutionParams &detRes)
Compute expected background from single foil for spectrum at wsIndex.
double m_l1
Source to sample distance.
void applyCorrection(const size_t inputIndex, const size_t outputIndex)
Calculate & correct the given index of the input workspace.
std::vector< FoilInfo > m_foils0
Description of foils in the position 0.
void createOutputWorkspaces()
Create the output workspaces.
API::MatrixWorkspace_const_sptr m_inputWS
Input TOF data.
std::vector< FoilInfo > m_foils1
Description of foils in the position 0.
std::unique_ptr< API::Progress > m_progress
Pointer to progress reporting.
double m_foilUpMax
Minimum in up dir to stop integration over foil volume.
std::unordered_map< size_t, size_t > m_indices
Sorted indices to correct.
void cacheInstrumentGeometry()
Compute & store the parameters that are fixed during the correction.
std::vector< double > calculateTofSpectrum(const std::vector< double > &inSpectrum, std::vector< double > &tmpWork, const size_t wsIndex, const DetectorParams &detpar, const CurveFitting::Functions::ResolutionParams &respar)
Compute a TOF spectrum for the given inputs & spectrum.
void calculateSpectrumFromDetector(const size_t inputIndex, const size_t outputIndex)
Compute the expected spectrum from a given detector.
void retrieveInputs()
Check and store appropriate input data.
size_t m_npeaks
The number of peaks in spectrum.
std::string m_profileFunction
Function that defines the mass profile.
API::MatrixWorkspace_sptr m_backgroundWS
Stores the value of the calculated background.
std::pair< double, double > calculateThetaRange(const Geometry::IComponent_const_sptr &foilComp, const double radius, const unsigned int horizDir) const
Compute the theta range for a given foil.
double m_foilUpMin
Minimum in up dir to start integration over foil volume.
bool calculateBackground(size_t inputIndex, size_t outputIndex)
Avoid nested try catch in openmp loop by returning boolean if spectrum was corrceted.
API::MatrixWorkspace_sptr m_correctedWS
Stores the corrected data.
static ResolutionParams getResolutionParameters(const API::MatrixWorkspace_const_sptr &ws, const size_t index)
Creates a POD struct containing the required resolution parameters for this spectrum.
A simple structure that defines an axis-aligned cuboid shaped bounding box for a geometrical object.
const Kernel::V3D & minPoint() const
Returns the min point of the box.
const Kernel::V3D & maxPoint() const
Returns the min point of the box.
Support for a property that holds an array of values.
Exception for when an item is not found in a collection.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
bool is(int level) const
Returns true if at least the given log level is set.
void information(const std::string &msg)
Logs at information level.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
double distance(const V3D &v) const noexcept
Calculates the distance between two vectors.
constexpr double X() const noexcept
Get x.
void setZ(const double zz) noexcept
Set is z position.
void setX(const double xx) noexcept
Set is x position.
void setY(const double yy) noexcept
Set is y position.
constexpr double Z() const noexcept
Get z.
std::shared_ptr< IFunction > IFunction_sptr
shared pointer to the function base class
std::shared_ptr< const IComponent > IComponent_const_sptr
Typdef of a shared pointer to a const IComponent.
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.
int32_t specnum_t
Typedef for a spectrum Number.
Generate a tableworkspace to store the calibration results.
std::string to_string(const wide_integer< Bits, Signed > &n)
Simple data structure to store nominal detector values It avoids some functions taking a huge number ...
double theta
scattering angle in radians
double t0
time delay in seconds
Kernel::V3D pos
Full 3D position.
double l2
sample-detector distance in metres
Hold information about a single foil.
Simple data structure to store resolution parameter values It avoids some functions taking a huge num...
double dEnLorentz
lorentz width in energy (meV)
double dEnGauss
gaussian width in energy (meV
@ InOut
Both an input & output workspace.
@ Input
An input workspace.
@ Output
An output workspace.