Mantid
Loading...
Searching...
No Matches
Q1D2.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
7#include <utility>
8
9#include "MantidAPI/Axis.h"
12#include "MantidAPI/ISpectrum.h"
25#include "MantidIndexing/IndexInfo.h"
32#include "MantidTypes/SpectrumDefinition.h"
33
34namespace Mantid::Algorithms {
35
36// Register the algorithm into the AlgorithmFactory
38
39using namespace Kernel;
40using namespace API;
41using namespace Geometry;
42using namespace DataObjects;
43
44Q1D2::Q1D2() : API::Algorithm(), m_dataWS(), m_doSolidAngle(false) {}
45
46void Q1D2::init() {
47 auto dataVal = std::make_shared<CompositeValidator>();
48 dataVal->add<WorkspaceUnitValidator>("Wavelength");
49 dataVal->add<HistogramValidator>();
50 dataVal->add<InstrumentValidator>();
51 dataVal->add<CommonBinsValidator>();
52 declareProperty(std::make_unique<WorkspaceProperty<>>("DetBankWorkspace", "", Direction::Input, dataVal),
53 "Particle counts as a function of wavelength");
54 declareProperty(std::make_unique<WorkspaceProperty<>>("OutputWorkspace", "", Direction::Output),
55 "Name of the workspace that will contain the result of the calculation");
56 declareProperty(std::make_unique<ArrayProperty<double>>("OutputBinning", std::make_shared<RebinParamsValidator>()),
57 "A comma separated list of first bin boundary, width, last bin boundary. "
58 "Optionally\n"
59 "this can be followed by a comma and more widths and last boundary "
60 "pairs.\n"
61 "Negative width values indicate logarithmic binning.");
63 "Scaling to apply to each spectrum. Must have\n"
64 "the same number of spectra as the DetBankWorkspace");
65 auto wavVal = std::make_shared<CompositeValidator>();
66 wavVal->add<WorkspaceUnitValidator>("Wavelength");
67 wavVal->add<HistogramValidator>();
69 std::make_unique<WorkspaceProperty<>>("WavelengthAdj", "", Direction::Input, PropertyMode::Optional, wavVal),
70 "Scaling to apply to each bin.\n"
71 "Must have the same number of bins as the DetBankWorkspace");
73 std::make_unique<WorkspaceProperty<>>("WavePixelAdj", "", Direction::Input, PropertyMode::Optional, dataVal),
74 "Scaling that depends on both pixel and wavelength together.\n"
75 "Must have the same number of bins and spectra as the DetBankWorkspace.");
76 declareProperty("AccountForGravity", false, "Whether to correct for the effects of gravity");
77 declareProperty("SolidAngleWeighting", true, "If true, pixels will be weighted by their solid angle.",
79 auto mustBePositive = std::make_shared<BoundedValidator<double>>();
80 mustBePositive->setLower(0.0);
81 auto mustBeIntOver2 = std::make_shared<BoundedValidator<int>>();
82 mustBeIntOver2->setLower(3);
83
84 declareProperty("RadiusCut", 0.0, mustBePositive,
85 "To increase resolution some wavelengths are excluded within "
86 "this distance from the beam center (mm). Note that RadiusCut\n"
87 " and WaveCut both need to be larger than 0 to affect \n"
88 "the effective cutoff. See the algorithm description for\n"
89 " a detailed explanation of the cutoff.");
90
91 declareProperty("WaveCut", 0.0, mustBePositive,
92 "To increase resolution by starting to remove some wavelengths below this"
93 " threshold (angstrom). Note that WaveCut\n"
94 " and RadiusCut both need to be larger than 0 to affect \n"
95 "on the effective cutoff. See the algorithm description for\n"
96 " a detailed explanation of the cutoff.");
97
98 declareProperty("OutputParts", false,
99 "Set to true to output two additional workspaces which will "
100 "have the names OutputWorkspace_sumOfCounts "
101 "OutputWorkspace_sumOfNormFactors. The division of "
102 "_sumOfCounts and _sumOfNormFactors equals the workspace"
103 " returned by the property OutputWorkspace "
104 "(default is false).");
105 declareProperty("ExtraLength", 0.0, mustBePositive, "Additional length for gravity correction.");
107 "SolidAngleNumberOfCylinderSlices", 10, mustBeIntOver2,
108 "The number of angular slices used when triangulating a cylinder in order to calculate the solid "
109 "angle of a tube detector. The default is 10 to preserve legacy behaviour, but increased accuracy has "
110 "been observed when using values of 11+");
112 std::make_unique<WorkspaceProperty<>>("QResolution", "", Direction::Input, PropertyMode::Optional, dataVal),
113 "Workspace to calculate the Q resolution.\n");
114}
119 m_dataWS = getProperty("DetBankWorkspace");
120 MatrixWorkspace_const_sptr waveAdj = getProperty("WavelengthAdj");
121 MatrixWorkspace_const_sptr pixelAdj = getProperty("PixelAdj");
122 MatrixWorkspace_const_sptr wavePixelAdj = getProperty("WavePixelAdj");
123 MatrixWorkspace_const_sptr qResolution = getProperty("QResolution");
124
125 const bool doGravity = getProperty("AccountForGravity");
126 m_doSolidAngle = getProperty("SolidAngleWeighting");
127
128 // throws if we don't have common binning or another incompatibility
129 Qhelper helper;
130 helper.examineInput(m_dataWS, waveAdj, pixelAdj, qResolution);
131 // FIXME: how to examine the wavePixelAdj?
132 g_log.debug() << "All input workspaces were found to be valid\n";
133 // normalization as a function of wavelength (i.e. centers of x-value bins)
134 double const *const binNorms = waveAdj ? &(waveAdj->y(0)[0]) : nullptr;
135 // error on the wavelength normalization
136 double const *const binNormEs = waveAdj ? &(waveAdj->e(0)[0]) : nullptr;
137
138 // define the (large number of) data objects that are going to be used in all
139 // iterations of the loop below
140
141 // Flag to decide if Q Resolution is to be used
142 auto useQResolution = static_cast<bool>(qResolution);
143
144 // this will become the output workspace from this algorithm
145 MatrixWorkspace_sptr outputWS = setUpOutputWorkspace(getProperty("OutputBinning"));
146
147 auto &QOut = outputWS->x(0);
148 auto &YOut = outputWS->mutableY(0);
149 auto &EOutTo2 = outputWS->mutableE(0);
150 // normalisation that is applied to counts in each Q bin
151 HistogramData::HistogramY normSum(YOut.size(), 0.0);
152 // the error on the normalisation
153 HistogramData::HistogramE normError2(EOutTo2.size(), 0.0);
154 // the averaged Q resolution.
155 HistogramData::HistogramDx qResolutionOut(YOut.size(), 0.0);
156
157 const auto numSpec = static_cast<int>(m_dataWS->getNumberHistograms());
158 Progress progress(this, 0.05, 1.0, numSpec + 1);
159
160 const auto &spectrumInfo = m_dataWS->spectrumInfo();
161 PARALLEL_FOR_IF(Kernel::threadSafe(*m_dataWS, *outputWS, pixelAdj.get()))
162 for (int i = 0; i < numSpec; ++i) {
164 if (!spectrumInfo.hasDetectors(i)) {
165 g_log.warning() << "Workspace index " << i << " (SpectrumIndex = " << m_dataWS->getSpectrum(i).getSpectrumNo()
166 << ") has no detector assigned to it - discarding\n";
167 continue;
168 }
169 // Skip if we have a monitor or if the detector is masked.
170 if (spectrumInfo.isMonitor(i) || spectrumInfo.isMasked(i))
171 continue;
172
173 // get the bins that are included inside the RadiusCut/WaveCutcut off, those
174 // to calculate for
175 // const size_t wavStart = waveLengthCutOff(i);
176 const size_t wavStart =
177 helper.waveLengthCutOff(m_dataWS, spectrumInfo, getProperty("RadiusCut"), getProperty("WaveCut"), i);
178 if (wavStart >= m_dataWS->y(i).size()) {
179 // all the spectra in this detector are out of range
180 continue;
181 }
182
183 const size_t numWavbins = m_dataWS->y(i).size() - wavStart;
184 // make just one call to new to reduce CPU overhead on each thread, access
185 // to these
186 // three "arrays" is via iterators
187 HistogramData::HistogramY _noDirectUseStorage_(3 * numWavbins);
188 // normalization term
189 auto norms = _noDirectUseStorage_.begin();
190 // the error on these weights, it contributes to the error calculation on
191 // the output workspace
192 auto normETo2s = norms + numWavbins;
193 // the Q values calculated from input wavelength workspace
194 auto QIn = normETo2s + numWavbins;
195
196 // the weighting for this input spectrum that is added to the normalization
197 calculateNormalization(wavStart, i, pixelAdj, wavePixelAdj, binNorms, binNormEs, norms, normETo2s);
198
199 // now read the data from the input workspace, calculate Q for each bin
200 convertWavetoQ(spectrumInfo, i, doGravity, wavStart, QIn, getProperty("ExtraLength"));
201
202 // Pointers to the counts data and it's error
203 auto YIn = m_dataWS->y(i).cbegin() + wavStart;
204 auto EIn = m_dataWS->e(i).cbegin() + wavStart;
205
206 // Pointers to the QResolution data. Note that the xdata was initially the
207 // same, hence
208 // the same indexing applies to the y values of m_dataWS and qResolution
209 // If we want to use it set it to the correct value, else to YIN, although
210 // that does not matter, as
211 // we won't use it
212 auto QResIn = useQResolution ? (qResolution->y(i).cbegin() + wavStart) : YIn;
213
214 // when finding the output Q bin remember that the input Q bins (from the
215 // convert to wavelength) start high and reduce
216 auto loc = QOut.cend();
217 // sum the Q contributions from each individual spectrum into the output
218 // array
219 const auto end = m_dataWS->y(i).cend();
220 for (; YIn != end; ++YIn, ++EIn, ++QIn, ++norms, ++normETo2s) {
221 // find the output bin that each input y-value will fall into, remembering
222 // there is one more bin boundary than bins
223 getQBinPlus1(QOut, *QIn, loc);
224 // ignore counts that are out of the output range
225 if ((loc != QOut.begin()) && (loc != QOut.end())) {
226 // the actual Q-bin to add something to
227 const size_t bin = loc - QOut.begin() - 1;
228 PARALLEL_CRITICAL(q1d_counts_sum) {
229 YOut[bin] += *YIn;
230 normSum[bin] += *norms;
231 // these are the errors squared which will be summed and square rooted
232 // at the end
233 EOutTo2[bin] += (*EIn) * (*EIn);
234 normError2[bin] += *normETo2s;
235 if (useQResolution) {
236 auto QBin = (QOut[bin + 1] - QOut[bin]);
237 // Here we need to take into account the Bin width and the count
238 // weigthing. The
239 // formula should be YIN* sqrt(QResIn^2 + (QBin/sqrt(12))^2)
240 qResolutionOut[bin] += (*YIn) * std::sqrt((*QResIn) * (*QResIn) + QBin * QBin / 12.0);
241 }
242 }
243 }
244
245 // Increment the QResolution iterator
246 if (useQResolution) {
247 ++QResIn;
248 }
249 }
250
251 PARALLEL_CRITICAL(q1d_spectra_map) {
252 progress.report("Computing I(Q)");
253 // Add up the detector IDs in the output spectrum at workspace index 0
254 const auto &inSpec = m_dataWS->getSpectrum(i);
255 auto &outSpec = outputWS->getSpectrum(0);
256 outSpec.addDetectorIDs(inSpec.getDetectorIDs());
257 }
258
260 }
262
263 if (useQResolution) {
264 // The number of Q (x)_ values is N, while the number of DeltaQ values is
265 // N-1,
266 // Richard Heenan suggested to duplicate the last entry of DeltaQ
267 auto countsIterator = YOut.cbegin();
268 auto qResolutionIterator = qResolutionOut.begin();
269 for (; countsIterator != YOut.end(); ++countsIterator, ++qResolutionIterator) {
270 // Divide by the counts of the Qbin, if the counts are 0, the the
271 // qresolution will also be 0
272 if ((*countsIterator) > 0.0) {
273 *qResolutionIterator = (*qResolutionIterator) / (*countsIterator);
274 }
275 }
276 outputWS->setPointStandardDeviations(0, std::move(qResolutionOut));
277 }
278
279 bool doOutputParts = getProperty("OutputParts");
280 if (doOutputParts) {
281 MatrixWorkspace_sptr ws_sumOfCounts = WorkspaceFactory::Instance().create(outputWS);
282 ws_sumOfCounts->setSharedX(0, outputWS->sharedX(0));
283 // Copy now as YOut is modified in normalize
284 ws_sumOfCounts->mutableY(0) = YOut;
285 ws_sumOfCounts->setSharedDx(0, outputWS->sharedDx(0));
286 ws_sumOfCounts->setFrequencyVariances(0, outputWS->e(0));
287
288 MatrixWorkspace_sptr ws_sumOfNormFactors = WorkspaceFactory::Instance().create(outputWS);
289 ws_sumOfNormFactors->setSharedX(0, outputWS->sharedX(0));
290 ws_sumOfNormFactors->mutableY(0) = normSum;
291 ws_sumOfNormFactors->setSharedDx(0, outputWS->sharedDx(0));
292 ws_sumOfNormFactors->setFrequencyVariances(0, normError2);
293
294 helper.outputParts(this, ws_sumOfCounts, ws_sumOfNormFactors);
295 }
296
297 progress.report("Normalizing I(Q)");
298 // finally divide the number of counts in each output Q bin by its weighting
299 normalize(normSum, normError2, YOut, EOutTo2);
300
301 setProperty("OutputWorkspace", outputWS);
302}
303
309API::MatrixWorkspace_sptr Q1D2::setUpOutputWorkspace(const std::vector<double> &binParams) const {
310 // Calculate the output binning
311 std::vector<double> xAxisTmp;
312 VectorHelper::createAxisFromRebinParams(binParams, xAxisTmp);
313 HistogramData::BinEdges XOut(std::move(xAxisTmp));
314
315 // Create output workspace. On all but rank 0 this is a temporary workspace.
316 Indexing::IndexInfo indexInfo(1);
317 indexInfo.setSpectrumDefinitions(std::vector<SpectrumDefinition>(1));
318 auto outputWS = create<MatrixWorkspace>(*m_dataWS, indexInfo, XOut);
319 outputWS->getAxis(0)->unit() = UnitFactory::Instance().create("MomentumTransfer");
320 outputWS->setYUnitLabel("1/cm");
321
322 outputWS->setDistribution(true);
323
324 outputWS->getSpectrum(0).clearDetectorIDs();
325 outputWS->getSpectrum(0).setSpectrumNo(1);
326
327 return outputWS;
328}
329
347void Q1D2::calculateNormalization(const size_t wavStart, const size_t wsIndex,
348 const API::MatrixWorkspace_const_sptr &pixelAdj,
349 const API::MatrixWorkspace_const_sptr &wavePixelAdj, double const *const binNorms,
350 double const *const binNormEs, HistogramData::HistogramY::iterator norm,
351 HistogramData::HistogramY::iterator normETo2) const {
352 double detectorAdj, detAdjErr;
353 pixelWeight(pixelAdj, wsIndex, detectorAdj, detAdjErr);
354 // use that the normalization array ends at the start of the error array
355 for (auto n = norm, e = normETo2; n != normETo2; ++n, ++e) {
356 *n = detectorAdj;
357 *e = detAdjErr * detAdjErr;
358 }
359
360 if (binNorms && binNormEs) {
361 if (wavePixelAdj)
362 // pass the iterator for the wave pixel Adj dependent
363 addWaveAdj(binNorms + wavStart, binNormEs + wavStart, norm, normETo2, wavePixelAdj->y(wsIndex).begin() + wavStart,
364 wavePixelAdj->e(wsIndex).begin() + wavStart);
365 else
366 addWaveAdj(binNorms + wavStart, binNormEs + wavStart, norm, normETo2);
367 }
368 normToMask(wavStart, wsIndex, norm, normETo2);
369}
370
382void Q1D2::pixelWeight(const API::MatrixWorkspace_const_sptr &pixelAdj, const size_t wsIndex, double &weight,
383 double &error) const {
384 const auto &detectorInfo = m_dataWS->detectorInfo();
385 const V3D samplePos = detectorInfo.samplePosition();
386
387 if (m_doSolidAngle) {
388 const int numberOfCylinderSlices = getProperty("SolidAngleNumberOfCylinderSlices");
389 weight = 0.0;
390 for (const auto detID : m_dataWS->getSpectrum(wsIndex).getDetectorIDs()) {
391 const auto index = detectorInfo.indexOf(detID);
392 if (!detectorInfo.isMasked(index))
393 weight += detectorInfo.detector(index).solidAngle({samplePos, numberOfCylinderSlices});
394 }
395 } else
396 weight = 1.0;
397
398 if (weight < 1e-200) {
399 throw std::logic_error("Invalid (zero or negative) solid angle for one detector");
400 }
401 // this input multiplies up the adjustment if it exists
402 if (pixelAdj) {
403 weight *= pixelAdj->readY(wsIndex)[0];
404 error = weight * pixelAdj->readE(wsIndex)[0];
405 } else {
406 error = 0.0;
407 }
408}
409
422void Q1D2::addWaveAdj(const double *c, const double *Dc, HistogramData::HistogramY::iterator bInOut,
423 HistogramData::HistogramY::iterator e2InOut) const {
424 // normalize by the wavelength dependent correction, keeping the percentage
425 // errors the same
426 // the error when a = b*c, the formula for Da, the error on a, in terms of Db,
427 // etc. is (Da/a)^2 = (Db/b)^2 + (Dc/c)^2
428 //(Da)^2 = ((Db*a/b)^2 + (Dc*a/c)^2) = (Db*c)^2 + (Dc*b)^2
429 // the variable names relate to those above as: existing values (b=bInOut)
430 // multiplied by the additional errors (Dc=binNormEs), existing errors
431 // (Db=sqrt(e2InOut)) times new factor (c=binNorms)
432
433 // use the fact that error array follows straight after the normalization
434 // array
435 const auto end = e2InOut;
436 for (; bInOut != end; ++e2InOut, ++c, ++Dc, ++bInOut) {
437 // first the error
438 *e2InOut = ((*e2InOut) * (*c) * (*c)) + ((*Dc) * (*Dc) * (*bInOut) * (*bInOut));
439 // now the actual calculation a = b*c
440 *bInOut = (*bInOut) * (*c);
441 }
442}
459void Q1D2::addWaveAdj(const double *c, const double *Dc, HistogramData::HistogramY::iterator bInOut,
460 HistogramData::HistogramY::iterator e2InOut,
461 HistogramData::HistogramY::const_iterator wavePixelAdjData,
462 HistogramData::HistogramE::const_iterator wavePixelAdjError) const {
463 // normalize by the wavelength dependent correction, keeping the percentage
464 // errors the same
465 // the error when a = b*c*e, the formula for Da, the error on a, in terms of
466 // Db, etc. is
467 // (Da/a)^2 = (Db/b)^2 + (Dc/c)^2 + (De/e)^2
468 //(Da)^2 = ((Db*a/b)^2 + (Dc*a/c)^2) + (De * a/e)^2
469 // But: a/b = c*e; a/c = b*e; a/e = b*c;
470 // So:
471 // (Da)^2 = (c*e*Db)^2 + (b*e*Dc)^2 + (b*c*De)^2
472 //
473 // Consider:
474 // Da = Error (e2InOut)
475 // Db^2 = PixelDependentError (e2InOut)
476 // b = PixelDependentValue (bInOut)
477 // c = WaveDependentValue (c)
478 // Dc = WaveDependentError (Dc)
479 // e = PixelWaveDependentValue (wavePixelAdjData)
480 // De = PiexlWaveDependentError (wavePixelAdjError)
481
482 // use the fact that error array follows straight after the normalization
483 // array
484 const auto end = e2InOut;
485 for (; bInOut != end; ++e2InOut, ++c, ++Dc, ++bInOut, ++wavePixelAdjData, ++wavePixelAdjError) {
486 // first the error
487 *e2InOut = ((*e2InOut) * (*c) * (*c) * (*wavePixelAdjData) * (*wavePixelAdjData)) +
488 ((*Dc) * (*Dc) * (*bInOut) * (*bInOut) * (*wavePixelAdjData) * (*wavePixelAdjData)) +
489 ((*wavePixelAdjError) * (*wavePixelAdjError) * (*c) * (*c) * (*bInOut) * (*bInOut));
490 // now the actual calculation a = b*c*e : Pixel * Wave * PixelWave
491 *bInOut = (*bInOut) * (*c) * (*wavePixelAdjData);
492 }
493}
494
504void Q1D2::normToMask(const size_t offSet, const size_t wsIndex, const HistogramData::HistogramY::iterator theNorms,
505 const HistogramData::HistogramY::iterator errorSquared) const {
506 // if any bins are masked it is normally a small proportion
507 if (m_dataWS->hasMaskedBins(wsIndex)) {
508 // Get a reference to the list of masked bins
509 const MatrixWorkspace::MaskList &mask = m_dataWS->maskedBins(wsIndex);
510 // Now iterate over the list, adjusting the weights for the affected bins
511 MatrixWorkspace::MaskList::const_iterator it;
512 for (it = mask.begin(); it != mask.end(); ++it) {
513 size_t outBin = it->first;
514 if (outBin < offSet) {
515 // this masked bin wasn't in the range being delt with anyway
516 continue;
517 }
518 outBin -= offSet;
519 // The weight for this masked bin is 1 - the degree to which this bin is
520 // masked
521 const double factor = 1.0 - (it->second);
522 *(theNorms + outBin) *= factor;
523 *(errorSquared + outBin) *= factor * factor;
524 }
525 }
526}
527
541void Q1D2::convertWavetoQ(const SpectrumInfo &spectrumInfo, const size_t wsInd, const bool doGravity,
542 const size_t offset, HistogramData::HistogramY::iterator Qs, const double extraLength) const {
543 static const double FOUR_PI = 4.0 * M_PI;
544
545 // wavelengths (lamda) to be converted to Q
546 auto waves = m_dataWS->x(wsInd).cbegin() + offset;
547 // going from bin boundaries to bin centered x-values the size goes down one
548 const auto end = m_dataWS->x(wsInd).end() - 1;
549 if (doGravity) {
550 GravitySANSHelper grav(spectrumInfo, wsInd, extraLength);
551 for (; waves != end; ++Qs, ++waves) {
552 // the HistogramValidator at the start should ensure that we have one more
553 // bin on the input wavelengths
554 const double lambda = 0.5 * (*(waves + 1) + (*waves));
555 // as the fall under gravity is wavelength dependent sin theta is now
556 // different for each bin with each detector
557 const double sinTheta = grav.calcSinTheta(lambda);
558 // Now we're ready to go to Q
559 *Qs = FOUR_PI * sinTheta / lambda;
560 }
561 } else {
562 // Calculate the Q values for the current spectrum, using Q =
563 // 4*pi*sin(theta)/lambda
564 const double factor = 2.0 * FOUR_PI * sin(spectrumInfo.twoTheta(wsInd) * 0.5);
565 for (; waves != end; ++Qs, ++waves) {
566 // the HistogramValidator at the start should ensure that we have one more
567 // bin on the input wavelengths
568 *Qs = factor / (*(waves + 1) + (*waves));
569 }
570 }
571}
585void Q1D2::getQBinPlus1(const HistogramData::HistogramX &OutQs, const double QToFind,
586 HistogramData::HistogramX::const_iterator &loc) const {
587 if (loc != OutQs.end()) {
588 while (loc != OutQs.begin()) {
589 if ((QToFind >= *(loc - 1)) && (QToFind < *loc)) {
590 return;
591 }
592 --loc;
593 }
594 if (QToFind < *loc) {
595 // QToFind is outside the array leave loc == OutQs.begin()
596 return;
597 }
598 } else // loc == OutQs.end()
599 {
600 if (OutQs.empty() || QToFind > *(loc - 1)) {
601 // outside the array leave loc == OutQs.end()
602 return;
603 }
604 }
605
606 // we are lost, normally the order of the Q values means we only get here on
607 // the first iteration. It's slow
608 loc = std::lower_bound(OutQs.begin(), OutQs.end(), QToFind);
609}
610
621void Q1D2::normalize(const HistogramData::HistogramY &normSum, const HistogramData::HistogramE &normError2,
622 HistogramData::HistogramY &counts, HistogramData::HistogramE &errors) const {
623 for (size_t k = 0; k < counts.size(); ++k) {
624 // the normalisation is a = b/c where b = counts c =normalistion term
625 const double c = normSum[k];
626 const double a = counts[k] /= c;
627 // when a = b/c, the formula for Da, the error on a, in terms of Db, etc. is
628 // (Da/a)^2 = (Db/b)^2 + (Dc/c)^2
629 //(Da)^2 = ((Db/b)^2 + (Dc/c)^2)*(b^2/c^2) = ((Db/c)^2 + (b*Dc/c^2)^2) =
630 //(Db^2 + (b*Dc/c)^2)/c^2 = (Db^2 + (Dc*a)^2)/c^2
631 // this will work as long as c>0, but then the above formula above can't
632 // deal with 0 either
633 const double aOverc = a / c;
634 errors[k] = std::sqrt(errors[k] / (c * c) + normError2[k] * aOverc * aOverc);
635 }
636}
637} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
const std::vector< double > * lambda
double error
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.
Definition Algorithm.h:76
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.
Kernel::Logger & g_log
Definition Algorithm.h:422
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.
Definition Progress.h:25
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.
Definition Q1D2.cpp:504
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.
Definition Q1D2.cpp:347
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...
Definition Q1D2.cpp:621
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...
Definition Q1D2.cpp:382
Q1D2()
Default constructor.
Definition Q1D2.cpp:44
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 ...
Definition Q1D2.cpp:541
API::MatrixWorkspace_sptr setUpOutputWorkspace(const std::vector< double > &binParams) const
Creates the output workspace, its size, units, etc.
Definition Q1D2.cpp:309
API::MatrixWorkspace_const_sptr m_dataWS
the experimental workspace with counts across the detector
Definition Q1D2.h:46
void init() override
Initialisation code.
Definition Q1D2.cpp:46
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...
Definition Q1D2.cpp:585
void exec() override
Execution code.
Definition Q1D2.cpp:118
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.
Definition Q1D2.cpp:422
Helper class for the Q1D and Qxy algorithms.
Definition Qhelper.h:20
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...
Definition Qhelper.cpp:150
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.
Definition Qhelper.cpp:183
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.
Definition Qhelper.cpp:29
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.
Definition Logger.cpp:145
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
Class for 3D vectors.
Definition V3D.h:34
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 > &params, 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.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54