26#include "MantidIndexing/IndexInfo.h"
33#include "MantidTypes/SpectrumDefinition.h"
40using namespace Kernel;
42using namespace Geometry;
43using namespace DataObjects;
48 auto dataVal = std::make_shared<CompositeValidator>();
54 "Particle counts as a function of wavelength");
56 "Name of the workspace that will contain the result of the calculation");
58 "A comma separated list of first bin boundary, width, last bin boundary. "
60 "this can be followed by a comma and more widths and last boundary "
62 "Negative width values indicate logarithmic binning.");
64 "Scaling to apply to each spectrum. Must have\n"
65 "the same number of spectra as the DetBankWorkspace");
66 auto wavVal = std::make_shared<CompositeValidator>();
71 "Scaling to apply to each bin.\n"
72 "Must have the same number of bins as the DetBankWorkspace");
75 "Scaling that depends on both pixel and wavelength together.\n"
76 "Must have the same number of bins and spectra as the DetBankWorkspace.");
77 declareProperty(
"AccountForGravity",
false,
"Whether to correct for the effects of gravity");
78 declareProperty(
"SolidAngleWeighting",
true,
"If true, pixels will be weighted by their solid angle.",
80 auto mustBePositive = std::make_shared<BoundedValidator<double>>();
81 mustBePositive->setLower(0.0);
82 auto mustBeIntOver2 = std::make_shared<BoundedValidator<int>>();
83 mustBeIntOver2->setLower(3);
86 "To increase resolution some wavelengths are excluded within "
87 "this distance from the beam center (mm). Note that RadiusCut\n"
88 " and WaveCut both need to be larger than 0 to affect \n"
89 "the effective cutoff. See the algorithm description for\n"
90 " a detailed explanation of the cutoff.");
93 "To increase resolution by starting to remove some wavelengths below this"
94 " threshold (angstrom). Note that WaveCut\n"
95 " and RadiusCut both need to be larger than 0 to affect \n"
96 "on the effective cutoff. See the algorithm description for\n"
97 " a detailed explanation of the cutoff.");
100 "Set to true to output two additional workspaces which will "
101 "have the names OutputWorkspace_sumOfCounts "
102 "OutputWorkspace_sumOfNormFactors. The division of "
103 "_sumOfCounts and _sumOfNormFactors equals the workspace"
104 " returned by the property OutputWorkspace "
105 "(default is false).");
106 declareProperty(
"ExtraLength", 0.0, mustBePositive,
"Additional length for gravity correction.");
108 "SolidAngleNumberOfCylinderSlices", 10, mustBeIntOver2,
109 "The number of angular slices used when triangulating a cylinder in order to calculate the solid "
110 "angle of a tube detector. The default is 10 to preserve legacy behaviour, but increased accuracy has "
111 "been observed when using values of 11+");
114 "Workspace to calculate the Q resolution.\n");
126 const bool doGravity =
getProperty(
"AccountForGravity");
133 g_log.
debug() <<
"All input workspaces were found to be valid\n";
135 double const *
const binNorms = waveAdj ? &(waveAdj->y(0)[0]) :
nullptr;
137 double const *
const binNormEs = waveAdj ? &(waveAdj->e(0)[0]) :
nullptr;
143 auto useQResolution =
static_cast<bool>(qResolution);
148 auto &QOut = outputWS->x(0);
149 auto &YOut = outputWS->mutableY(0);
150 auto &EOutTo2 = outputWS->mutableE(0);
152 HistogramData::HistogramY normSum(YOut.size(), 0.0);
154 HistogramData::HistogramE normError2(EOutTo2.size(), 0.0);
156 HistogramData::HistogramDx qResolutionOut(YOut.size(), 0.0);
158 const auto numSpec =
static_cast<int>(
m_dataWS->getNumberHistograms());
161 const auto &spectrumInfo =
m_dataWS->spectrumInfo();
163 for (
int i = 0; i < numSpec; ++i) {
165 if (!spectrumInfo.hasDetectors(i)) {
166 g_log.
warning() <<
"Workspace index " << i <<
" (SpectrumIndex = " <<
m_dataWS->getSpectrum(i).getSpectrumNo()
167 <<
") has no detector assigned to it - discarding\n";
171 if (spectrumInfo.isMonitor(i) || spectrumInfo.isMasked(i))
177 const size_t wavStart =
179 if (wavStart >=
m_dataWS->y(i).size()) {
184 const size_t numWavbins =
m_dataWS->y(i).size() - wavStart;
188 HistogramData::HistogramY _noDirectUseStorage_(3 * numWavbins);
190 auto norms = _noDirectUseStorage_.begin();
193 auto normETo2s = norms + numWavbins;
195 auto QIn = normETo2s + numWavbins;
204 auto YIn =
m_dataWS->y(i).cbegin() + wavStart;
205 auto EIn =
m_dataWS->e(i).cbegin() + wavStart;
213 auto QResIn = useQResolution ? (qResolution->y(i).cbegin() + wavStart) : YIn;
217 auto loc = QOut.cend();
220 const auto end =
m_dataWS->y(i).cend();
221 for (; YIn != end; ++YIn, ++EIn, ++QIn, ++norms, ++normETo2s) {
226 if ((loc != QOut.begin()) && (loc != QOut.end())) {
228 const size_t bin = loc - QOut.begin() - 1;
231 normSum[bin] += *norms;
234 EOutTo2[bin] += (*EIn) * (*EIn);
235 normError2[bin] += *normETo2s;
236 if (useQResolution) {
237 auto QBin = (QOut[bin + 1] - QOut[bin]);
241 qResolutionOut[bin] += (*YIn) * std::sqrt((*QResIn) * (*QResIn) + QBin * QBin / 12.0);
247 if (useQResolution) {
255 const auto &inSpec =
m_dataWS->getSpectrum(i);
256 auto &outSpec = outputWS->getSpectrum(0);
257 outSpec.addDetectorIDs(inSpec.getDetectorIDs());
264 if (useQResolution) {
268 auto countsIterator = YOut.cbegin();
269 auto qResolutionIterator = qResolutionOut.begin();
270 for (; countsIterator != YOut.end(); ++countsIterator, ++qResolutionIterator) {
273 if ((*countsIterator) > 0.0) {
274 *qResolutionIterator = (*qResolutionIterator) / (*countsIterator);
277 outputWS->setPointStandardDeviations(0, std::move(qResolutionOut));
283 ws_sumOfCounts->setSharedX(0, outputWS->sharedX(0));
285 ws_sumOfCounts->mutableY(0) = YOut;
286 ws_sumOfCounts->setSharedDx(0, outputWS->sharedDx(0));
287 ws_sumOfCounts->setFrequencyVariances(0, outputWS->e(0));
290 ws_sumOfNormFactors->setSharedX(0, outputWS->sharedX(0));
291 ws_sumOfNormFactors->mutableY(0) = normSum;
292 ws_sumOfNormFactors->setSharedDx(0, outputWS->sharedDx(0));
293 ws_sumOfNormFactors->setFrequencyVariances(0, normError2);
295 helper.
outputParts(
this, ws_sumOfCounts, ws_sumOfNormFactors);
298 progress.report(
"Normalizing I(Q)");
300 normalize(normSum, normError2, YOut, EOutTo2);
312 std::vector<double> xAxisTmp;
314 HistogramData::BinEdges XOut(std::move(xAxisTmp));
317 Indexing::IndexInfo indexInfo(1);
318 indexInfo.setSpectrumDefinitions(std::vector<SpectrumDefinition>(1));
319 auto outputWS = create<MatrixWorkspace>(*
m_dataWS, indexInfo, XOut);
320 outputWS->getAxis(0)->unit() = UnitFactory::Instance().create(
"MomentumTransfer");
321 outputWS->setYUnitLabel(
"1/cm");
323 outputWS->setDistribution(
true);
325 outputWS->getSpectrum(0).clearDetectorIDs();
326 outputWS->getSpectrum(0).setSpectrumNo(1);
351 double const *
const binNormEs, HistogramData::HistogramY::iterator norm,
352 HistogramData::HistogramY::iterator normETo2)
const {
353 double detectorAdj, detAdjErr;
354 pixelWeight(pixelAdj, wsIndex, detectorAdj, detAdjErr);
356 for (
auto n = norm, e = normETo2;
n != normETo2; ++
n, ++e) {
358 *e = detAdjErr * detAdjErr;
361 if (binNorms && binNormEs) {
364 addWaveAdj(binNorms + wavStart, binNormEs + wavStart, norm, normETo2, wavePixelAdj->y(wsIndex).begin() + wavStart,
365 wavePixelAdj->e(wsIndex).begin() + wavStart);
367 addWaveAdj(binNorms + wavStart, binNormEs + wavStart, norm, normETo2);
369 normToMask(wavStart, wsIndex, norm, normETo2);
384 double &
error)
const {
390 const int numberOfCylinderSlices =
getProperty(
"SolidAngleNumberOfCylinderSlices");
392 for (
const auto detID :
m_dataWS->getSpectrum(wsIndex).getDetectorIDs()) {
395 weight += componentInfo.
solidAngle(
index, {samplePos, numberOfCylinderSlices});
400 if (weight < 1e-200) {
401 throw std::logic_error(
"Invalid (zero or negative) solid angle for one detector");
405 weight *= pixelAdj->y(wsIndex)[0];
406 error = weight * pixelAdj->e(wsIndex)[0];
424void Q1D2::addWaveAdj(
const double *c,
const double *Dc, HistogramData::HistogramY::iterator bInOut,
425 HistogramData::HistogramY::iterator e2InOut)
const {
437 const auto end = e2InOut;
438 for (; bInOut != end; ++e2InOut, ++c, ++Dc, ++bInOut) {
440 *e2InOut = ((*e2InOut) * (*c) * (*c)) + ((*Dc) * (*Dc) * (*bInOut) * (*bInOut));
442 *bInOut = (*bInOut) * (*c);
461void Q1D2::addWaveAdj(
const double *c,
const double *Dc, HistogramData::HistogramY::iterator bInOut,
462 HistogramData::HistogramY::iterator e2InOut,
463 HistogramData::HistogramY::const_iterator wavePixelAdjData,
464 HistogramData::HistogramE::const_iterator wavePixelAdjError)
const {
486 const auto end = e2InOut;
487 for (; bInOut != end; ++e2InOut, ++c, ++Dc, ++bInOut, ++wavePixelAdjData, ++wavePixelAdjError) {
489 *e2InOut = ((*e2InOut) * (*c) * (*c) * (*wavePixelAdjData) * (*wavePixelAdjData)) +
490 ((*Dc) * (*Dc) * (*bInOut) * (*bInOut) * (*wavePixelAdjData) * (*wavePixelAdjData)) +
491 ((*wavePixelAdjError) * (*wavePixelAdjError) * (*c) * (*c) * (*bInOut) * (*bInOut));
493 *bInOut = (*bInOut) * (*c) * (*wavePixelAdjData);
506void Q1D2::normToMask(
const size_t offSet,
const size_t wsIndex,
const HistogramData::HistogramY::iterator theNorms,
507 const HistogramData::HistogramY::iterator errorSquared)
const {
509 if (m_dataWS->hasMaskedBins(wsIndex)) {
513 MatrixWorkspace::MaskList::const_iterator it;
514 for (it = mask.begin(); it != mask.end(); ++it) {
515 size_t outBin = it->first;
516 if (outBin < offSet) {
523 const double factor = 1.0 - (it->second);
524 *(theNorms + outBin) *= factor;
525 *(errorSquared + outBin) *= factor * factor;
543void Q1D2::convertWavetoQ(
const SpectrumInfo &spectrumInfo,
const size_t wsInd,
const bool doGravity,
544 const size_t offset, HistogramData::HistogramY::iterator Qs,
const double extraLength)
const {
545 static const double FOUR_PI = 4.0 * M_PI;
548 auto waves = m_dataWS->x(wsInd).cbegin() + offset;
550 const auto end = m_dataWS->x(wsInd).end() - 1;
553 for (; waves != end; ++Qs, ++waves) {
556 const double lambda = 0.5 * (*(waves + 1) + (*waves));
561 *Qs = FOUR_PI * sinTheta /
lambda;
566 const double factor = 2.0 * FOUR_PI * sin(spectrumInfo.
twoTheta(wsInd) * 0.5);
567 for (; waves != end; ++Qs, ++waves) {
570 *Qs = factor / (*(waves + 1) + (*waves));
587void Q1D2::getQBinPlus1(
const HistogramData::HistogramX &OutQs,
const double QToFind,
588 HistogramData::HistogramX::const_iterator &loc)
const {
589 if (loc != OutQs.end()) {
590 while (loc != OutQs.begin()) {
591 if ((QToFind >= *(loc - 1)) && (QToFind < *loc)) {
596 if (QToFind < *loc) {
602 if (OutQs.empty() || QToFind > *(loc - 1)) {
610 loc = std::lower_bound(OutQs.begin(), OutQs.end(), QToFind);
623void Q1D2::normalize(
const HistogramData::HistogramY &normSum,
const HistogramData::HistogramE &normError2,
624 HistogramData::HistogramY &counts, HistogramData::HistogramE &errors)
const {
625 for (
size_t k = 0; k < counts.size(); ++k) {
627 const double c = normSum[k];
628 const double a = counts[k] /= c;
635 const double aOverc = a / c;
636 errors[k] = std::sqrt(errors[k] / (c * c) + normError2[k] * aOverc * aOverc);
#define DECLARE_ALGORITHM(classname)
const std::vector< double > * lambda
std::map< DeltaEMode::Type, std::string > index
#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_CRITICAL(name)
#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.
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
A validator which provides a TENTATIVE check that a workspace contains common bins in each spectrum.
A validator which checks that a workspace contains histogram data (the default) or point data as requ...
A validator which checks that a workspace has a valid instrument.
std::map< size_t, double > MaskList
Masked bins for each spectrum are stored as a set of pairs containing <bin index, weight>
Helper class for reporting progress from algorithms.
API::SpectrumInfo is an intermediate step towards a SpectrumInfo that is part of Instrument-2....
double twoTheta(const size_t index) const
Returns the scattering angle 2 theta in radians (angle w.r.t.
A property class for workspaces.
A validator which checks that the unit of the workspace referred to by a WorkspaceProperty is the exp...
A helper class for calculating neutron's gravitional drop.
double calcSinTheta(const double wavAngstroms) const
Caclulates the sin of the that the neutron left the sample at, before the effect of gravity.
void normToMask(const size_t offSet, const size_t wsIndex, const HistogramData::HistogramY::iterator theNorms, const HistogramData::HistogramY::iterator errorSquared) const
Scaled to bin masking, to the normalization.
void calculateNormalization(const size_t wavStart, const size_t wsIndex, const API::MatrixWorkspace_const_sptr &pixelAdj, const API::MatrixWorkspace_const_sptr &wavePixelAdj, double const *const binNorms, double const *const binNormEs, HistogramData::HistogramY::iterator norm, HistogramData::HistogramY::iterator normETo2) const
Calculate the normalization term for each output bin.
void normalize(const HistogramData::HistogramY &normSum, const HistogramData::HistogramE &normError2, HistogramData::HistogramY &counts, HistogramData::HistogramE &errors) const
Divides the number of counts in each output Q bin by the wrighting ("number that would expected to ar...
void pixelWeight(const API::MatrixWorkspace_const_sptr &pixelAdj, const size_t wsIndex, double &weight, double &error) const
Calculates the normalisation for the spectrum specified by the index number that was passed as the so...
Q1D2()
Default constructor.
void convertWavetoQ(const API::SpectrumInfo &spectrumInfo, const size_t wsInd, const bool doGravity, const size_t offset, HistogramData::HistogramY::iterator Qs, const double extraLength) const
Fills a vector with the Q values calculated from the wavelength bin centers from the input workspace ...
API::MatrixWorkspace_sptr setUpOutputWorkspace(const std::vector< double > &binParams) const
Creates the output workspace, its size, units, etc.
API::MatrixWorkspace_const_sptr m_dataWS
the experimental workspace with counts across the detector
void init() override
Initialisation code.
void getQBinPlus1(const HistogramData::HistogramX &OutQs, const double QToFind, HistogramData::HistogramY::const_iterator &loc) const
This is a slightly "clever" method as it makes some guesses about where is best to look for the right...
void exec() override
Execution code.
void addWaveAdj(const double *c, const double *Dc, HistogramData::HistogramY::iterator bInOut, HistogramData::HistogramY::iterator e2InOut) const
Calculates the contribution to the normalization terms from each bin in a spectrum.
Helper class for the Q1D and Qxy algorithms.
size_t waveLengthCutOff(const API::MatrixWorkspace_const_sptr &dataWS, const API::SpectrumInfo &spectrumInfo, const double RCut, const double WCut, const size_t wsInd) const
Finds the first index number of the first wavelength bin that should included based on the the calcul...
void outputParts(API::Algorithm *alg, const API::MatrixWorkspace_sptr &sumOfCounts, const API::MatrixWorkspace_sptr &sumOfNormFactors)
This method performs the common work between Qxy and Q1D2 if algorihtm parameter OutputParts=True.
void examineInput(const API::MatrixWorkspace_const_sptr &dataWS, const API::MatrixWorkspace_const_sptr &binAdj, const API::MatrixWorkspace_const_sptr &detectAdj, const API::MatrixWorkspace_const_sptr &qResolution)
Checks if workspaces input to Q1D or Qxy are reasonable.
ComponentInfo : Provides a component centric view on to the instrument.
double solidAngle(const size_t componentIndex, const Geometry::SolidAngleParams ¶ms) const
Kernel::V3D samplePosition() const
Geometry::DetectorInfo is an intermediate step towards a DetectorInfo that is part of Instrument-2....
bool isMasked(const size_t index) const
Returns true if the detector is masked.
size_t indexOf(const detid_t id) const
Returns the index of the detector with the given detector ID.
Support for a property that holds an array of values.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void debug(const std::string &msg)
Logs at debug level.
void warning(const std::string &msg)
Logs at warning level.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
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::size_t MANTID_KERNEL_DLL createAxisFromRebinParams(const std::vector< double > ¶ms, std::vector< double > &xnew, const bool resize_xnew=true, const bool full_bins_only=false, const double xMinHint=std::nan(""), const double xMaxHint=std::nan(""), const bool useReverseLogarithmic=false, const double power=-1)
Creates a new output X array given a 'standard' set of rebinning parameters.
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.
@ Input
An input workspace.
@ Output
An output workspace.