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 HistogramData::BinEdges XOut(0);
312 static_cast<void>(VectorHelper::createAxisFromRebinParams(binParams, XOut.mutableRawData()));
313
314 // Create output workspace. On all but rank 0 this is a temporary workspace.
315 Indexing::IndexInfo indexInfo(1);
316 indexInfo.setSpectrumDefinitions(std::vector<SpectrumDefinition>(1));
317 auto outputWS = create<MatrixWorkspace>(*m_dataWS, indexInfo, XOut);
318 outputWS->getAxis(0)->unit() = UnitFactory::Instance().create("MomentumTransfer");
319 outputWS->setYUnitLabel("1/cm");
320
321 outputWS->setDistribution(true);
322
323 outputWS->getSpectrum(0).clearDetectorIDs();
324 outputWS->getSpectrum(0).setSpectrumNo(1);
325
326 return outputWS;
327}
328
346void Q1D2::calculateNormalization(const size_t wavStart, const size_t wsIndex,
347 const API::MatrixWorkspace_const_sptr &pixelAdj,
348 const API::MatrixWorkspace_const_sptr &wavePixelAdj, double const *const binNorms,
349 double const *const binNormEs, HistogramData::HistogramY::iterator norm,
350 HistogramData::HistogramY::iterator normETo2) const {
351 double detectorAdj, detAdjErr;
352 pixelWeight(pixelAdj, wsIndex, detectorAdj, detAdjErr);
353 // use that the normalization array ends at the start of the error array
354 for (auto n = norm, e = normETo2; n != normETo2; ++n, ++e) {
355 *n = detectorAdj;
356 *e = detAdjErr * detAdjErr;
357 }
358
359 if (binNorms && binNormEs) {
360 if (wavePixelAdj)
361 // pass the iterator for the wave pixel Adj dependent
362 addWaveAdj(binNorms + wavStart, binNormEs + wavStart, norm, normETo2, wavePixelAdj->y(wsIndex).begin() + wavStart,
363 wavePixelAdj->e(wsIndex).begin() + wavStart);
364 else
365 addWaveAdj(binNorms + wavStart, binNormEs + wavStart, norm, normETo2);
366 }
367 normToMask(wavStart, wsIndex, norm, normETo2);
368}
369
381void Q1D2::pixelWeight(const API::MatrixWorkspace_const_sptr &pixelAdj, const size_t wsIndex, double &weight,
382 double &error) const {
383 const auto &detectorInfo = m_dataWS->detectorInfo();
384 const V3D samplePos = detectorInfo.samplePosition();
385
386 if (m_doSolidAngle) {
387 const int numberOfCylinderSlices = getProperty("SolidAngleNumberOfCylinderSlices");
388 weight = 0.0;
389 for (const auto detID : m_dataWS->getSpectrum(wsIndex).getDetectorIDs()) {
390 const auto index = detectorInfo.indexOf(detID);
391 if (!detectorInfo.isMasked(index))
392 weight += detectorInfo.detector(index).solidAngle({samplePos, numberOfCylinderSlices});
393 }
394 } else
395 weight = 1.0;
396
397 if (weight < 1e-200) {
398 throw std::logic_error("Invalid (zero or negative) solid angle for one detector");
399 }
400 // this input multiplies up the adjustment if it exists
401 if (pixelAdj) {
402 weight *= pixelAdj->readY(wsIndex)[0];
403 error = weight * pixelAdj->readE(wsIndex)[0];
404 } else {
405 error = 0.0;
406 }
407}
408
421void Q1D2::addWaveAdj(const double *c, const double *Dc, HistogramData::HistogramY::iterator bInOut,
422 HistogramData::HistogramY::iterator e2InOut) const {
423 // normalize by the wavelength dependent correction, keeping the percentage
424 // errors the same
425 // the error when a = b*c, the formula for Da, the error on a, in terms of Db,
426 // etc. is (Da/a)^2 = (Db/b)^2 + (Dc/c)^2
427 //(Da)^2 = ((Db*a/b)^2 + (Dc*a/c)^2) = (Db*c)^2 + (Dc*b)^2
428 // the variable names relate to those above as: existing values (b=bInOut)
429 // multiplied by the additional errors (Dc=binNormEs), existing errors
430 // (Db=sqrt(e2InOut)) times new factor (c=binNorms)
431
432 // use the fact that error array follows straight after the normalization
433 // array
434 const auto end = e2InOut;
435 for (; bInOut != end; ++e2InOut, ++c, ++Dc, ++bInOut) {
436 // first the error
437 *e2InOut = ((*e2InOut) * (*c) * (*c)) + ((*Dc) * (*Dc) * (*bInOut) * (*bInOut));
438 // now the actual calculation a = b*c
439 *bInOut = (*bInOut) * (*c);
440 }
441}
458void Q1D2::addWaveAdj(const double *c, const double *Dc, HistogramData::HistogramY::iterator bInOut,
459 HistogramData::HistogramY::iterator e2InOut,
460 HistogramData::HistogramY::const_iterator wavePixelAdjData,
461 HistogramData::HistogramE::const_iterator wavePixelAdjError) const {
462 // normalize by the wavelength dependent correction, keeping the percentage
463 // errors the same
464 // the error when a = b*c*e, the formula for Da, the error on a, in terms of
465 // Db, etc. is
466 // (Da/a)^2 = (Db/b)^2 + (Dc/c)^2 + (De/e)^2
467 //(Da)^2 = ((Db*a/b)^2 + (Dc*a/c)^2) + (De * a/e)^2
468 // But: a/b = c*e; a/c = b*e; a/e = b*c;
469 // So:
470 // (Da)^2 = (c*e*Db)^2 + (b*e*Dc)^2 + (b*c*De)^2
471 //
472 // Consider:
473 // Da = Error (e2InOut)
474 // Db^2 = PixelDependentError (e2InOut)
475 // b = PixelDependentValue (bInOut)
476 // c = WaveDependentValue (c)
477 // Dc = WaveDependentError (Dc)
478 // e = PixelWaveDependentValue (wavePixelAdjData)
479 // De = PiexlWaveDependentError (wavePixelAdjError)
480
481 // use the fact that error array follows straight after the normalization
482 // array
483 const auto end = e2InOut;
484 for (; bInOut != end; ++e2InOut, ++c, ++Dc, ++bInOut, ++wavePixelAdjData, ++wavePixelAdjError) {
485 // first the error
486 *e2InOut = ((*e2InOut) * (*c) * (*c) * (*wavePixelAdjData) * (*wavePixelAdjData)) +
487 ((*Dc) * (*Dc) * (*bInOut) * (*bInOut) * (*wavePixelAdjData) * (*wavePixelAdjData)) +
488 ((*wavePixelAdjError) * (*wavePixelAdjError) * (*c) * (*c) * (*bInOut) * (*bInOut));
489 // now the actual calculation a = b*c*e : Pixel * Wave * PixelWave
490 *bInOut = (*bInOut) * (*c) * (*wavePixelAdjData);
491 }
492}
493
503void Q1D2::normToMask(const size_t offSet, const size_t wsIndex, const HistogramData::HistogramY::iterator theNorms,
504 const HistogramData::HistogramY::iterator errorSquared) const {
505 // if any bins are masked it is normally a small proportion
506 if (m_dataWS->hasMaskedBins(wsIndex)) {
507 // Get a reference to the list of masked bins
508 const MatrixWorkspace::MaskList &mask = m_dataWS->maskedBins(wsIndex);
509 // Now iterate over the list, adjusting the weights for the affected bins
510 MatrixWorkspace::MaskList::const_iterator it;
511 for (it = mask.begin(); it != mask.end(); ++it) {
512 size_t outBin = it->first;
513 if (outBin < offSet) {
514 // this masked bin wasn't in the range being delt with anyway
515 continue;
516 }
517 outBin -= offSet;
518 // The weight for this masked bin is 1 - the degree to which this bin is
519 // masked
520 const double factor = 1.0 - (it->second);
521 *(theNorms + outBin) *= factor;
522 *(errorSquared + outBin) *= factor * factor;
523 }
524 }
525}
526
540void Q1D2::convertWavetoQ(const SpectrumInfo &spectrumInfo, const size_t wsInd, const bool doGravity,
541 const size_t offset, HistogramData::HistogramY::iterator Qs, const double extraLength) const {
542 static const double FOUR_PI = 4.0 * M_PI;
543
544 // wavelengths (lamda) to be converted to Q
545 auto waves = m_dataWS->x(wsInd).cbegin() + offset;
546 // going from bin boundaries to bin centered x-values the size goes down one
547 const auto end = m_dataWS->x(wsInd).end() - 1;
548 if (doGravity) {
549 GravitySANSHelper grav(spectrumInfo, wsInd, extraLength);
550 for (; waves != end; ++Qs, ++waves) {
551 // the HistogramValidator at the start should ensure that we have one more
552 // bin on the input wavelengths
553 const double lambda = 0.5 * (*(waves + 1) + (*waves));
554 // as the fall under gravity is wavelength dependent sin theta is now
555 // different for each bin with each detector
556 const double sinTheta = grav.calcSinTheta(lambda);
557 // Now we're ready to go to Q
558 *Qs = FOUR_PI * sinTheta / lambda;
559 }
560 } else {
561 // Calculate the Q values for the current spectrum, using Q =
562 // 4*pi*sin(theta)/lambda
563 const double factor = 2.0 * FOUR_PI * sin(spectrumInfo.twoTheta(wsInd) * 0.5);
564 for (; waves != end; ++Qs, ++waves) {
565 // the HistogramValidator at the start should ensure that we have one more
566 // bin on the input wavelengths
567 *Qs = factor / (*(waves + 1) + (*waves));
568 }
569 }
570}
584void Q1D2::getQBinPlus1(const HistogramData::HistogramX &OutQs, const double QToFind,
585 HistogramData::HistogramX::const_iterator &loc) const {
586 if (loc != OutQs.end()) {
587 while (loc != OutQs.begin()) {
588 if ((QToFind >= *(loc - 1)) && (QToFind < *loc)) {
589 return;
590 }
591 --loc;
592 }
593 if (QToFind < *loc) {
594 // QToFind is outside the array leave loc == OutQs.begin()
595 return;
596 }
597 } else // loc == OutQs.end()
598 {
599 if (OutQs.empty() || QToFind > *(loc - 1)) {
600 // outside the array leave loc == OutQs.end()
601 return;
602 }
603 }
604
605 // we are lost, normally the order of the Q values means we only get here on
606 // the first iteration. It's slow
607 loc = std::lower_bound(OutQs.begin(), OutQs.end(), QToFind);
608}
609
620void Q1D2::normalize(const HistogramData::HistogramY &normSum, const HistogramData::HistogramE &normError2,
621 HistogramData::HistogramY &counts, HistogramData::HistogramE &errors) const {
622 for (size_t k = 0; k < counts.size(); ++k) {
623 // the normalisation is a = b/c where b = counts c =normalistion term
624 const double c = normSum[k];
625 const double a = counts[k] /= c;
626 // when a = b/c, the formula for Da, the error on a, in terms of Db, etc. is
627 // (Da/a)^2 = (Db/b)^2 + (Dc/c)^2
628 //(Da)^2 = ((Db/b)^2 + (Dc/c)^2)*(b^2/c^2) = ((Db/c)^2 + (b*Dc/c^2)^2) =
629 //(Db^2 + (b*Dc/c)^2)/c^2 = (Db^2 + (Dc*a)^2)/c^2
630 // this will work as long as c>0, but then the above formula above can't
631 // deal with 0 either
632 const double aOverc = a / c;
633 errors[k] = std::sqrt(errors[k] / (c * c) + normError2[k] * aOverc * aOverc);
634 }
635}
636} // 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:503
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:346
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:620
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:381
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:540
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:584
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:421
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
int 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