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"
26#include "MantidIndexing/IndexInfo.h"
33#include "MantidTypes/SpectrumDefinition.h"
34
35namespace Mantid::Algorithms {
36
37// Register the algorithm into the AlgorithmFactory
39
40using namespace Kernel;
41using namespace API;
42using namespace Geometry;
43using namespace DataObjects;
44
45Q1D2::Q1D2() : API::Algorithm(), m_dataWS(), m_doSolidAngle(false) {}
46
47void Q1D2::init() {
48 auto dataVal = std::make_shared<CompositeValidator>();
49 dataVal->add<WorkspaceUnitValidator>("Wavelength");
50 dataVal->add<HistogramValidator>();
51 dataVal->add<InstrumentValidator>();
52 dataVal->add<CommonBinsValidator>();
53 declareProperty(std::make_unique<WorkspaceProperty<>>("DetBankWorkspace", "", Direction::Input, dataVal),
54 "Particle counts as a function of wavelength");
55 declareProperty(std::make_unique<WorkspaceProperty<>>("OutputWorkspace", "", Direction::Output),
56 "Name of the workspace that will contain the result of the calculation");
57 declareProperty(std::make_unique<ArrayProperty<double>>("OutputBinning", std::make_shared<RebinParamsValidator>()),
58 "A comma separated list of first bin boundary, width, last bin boundary. "
59 "Optionally\n"
60 "this can be followed by a comma and more widths and last boundary "
61 "pairs.\n"
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>();
67 wavVal->add<WorkspaceUnitValidator>("Wavelength");
68 wavVal->add<HistogramValidator>();
70 std::make_unique<WorkspaceProperty<>>("WavelengthAdj", "", Direction::Input, PropertyMode::Optional, wavVal),
71 "Scaling to apply to each bin.\n"
72 "Must have the same number of bins as the DetBankWorkspace");
74 std::make_unique<WorkspaceProperty<>>("WavePixelAdj", "", Direction::Input, PropertyMode::Optional, dataVal),
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);
84
85 declareProperty("RadiusCut", 0.0, mustBePositive,
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.");
91
92 declareProperty("WaveCut", 0.0, mustBePositive,
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.");
98
99 declareProperty("OutputParts", false,
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+");
113 std::make_unique<WorkspaceProperty<>>("QResolution", "", Direction::Input, PropertyMode::Optional, dataVal),
114 "Workspace to calculate the Q resolution.\n");
115}
120 m_dataWS = getProperty("DetBankWorkspace");
121 MatrixWorkspace_const_sptr waveAdj = getProperty("WavelengthAdj");
122 MatrixWorkspace_const_sptr pixelAdj = getProperty("PixelAdj");
123 MatrixWorkspace_const_sptr wavePixelAdj = getProperty("WavePixelAdj");
124 MatrixWorkspace_const_sptr qResolution = getProperty("QResolution");
125
126 const bool doGravity = getProperty("AccountForGravity");
127 m_doSolidAngle = getProperty("SolidAngleWeighting");
128
129 // throws if we don't have common binning or another incompatibility
130 Qhelper helper;
131 helper.examineInput(m_dataWS, waveAdj, pixelAdj, qResolution);
132 // FIXME: how to examine the wavePixelAdj?
133 g_log.debug() << "All input workspaces were found to be valid\n";
134 // normalization as a function of wavelength (i.e. centers of x-value bins)
135 double const *const binNorms = waveAdj ? &(waveAdj->y(0)[0]) : nullptr;
136 // error on the wavelength normalization
137 double const *const binNormEs = waveAdj ? &(waveAdj->e(0)[0]) : nullptr;
138
139 // define the (large number of) data objects that are going to be used in all
140 // iterations of the loop below
141
142 // Flag to decide if Q Resolution is to be used
143 auto useQResolution = static_cast<bool>(qResolution);
144
145 // this will become the output workspace from this algorithm
146 MatrixWorkspace_sptr outputWS = setUpOutputWorkspace(getProperty("OutputBinning"));
147
148 auto &QOut = outputWS->x(0);
149 auto &YOut = outputWS->mutableY(0);
150 auto &EOutTo2 = outputWS->mutableE(0);
151 // normalisation that is applied to counts in each Q bin
152 HistogramData::HistogramY normSum(YOut.size(), 0.0);
153 // the error on the normalisation
154 HistogramData::HistogramE normError2(EOutTo2.size(), 0.0);
155 // the averaged Q resolution.
156 HistogramData::HistogramDx qResolutionOut(YOut.size(), 0.0);
157
158 const auto numSpec = static_cast<int>(m_dataWS->getNumberHistograms());
159 Progress progress(this, 0.05, 1.0, numSpec + 1);
160
161 const auto &spectrumInfo = m_dataWS->spectrumInfo();
162 PARALLEL_FOR_IF(Kernel::threadSafe(*m_dataWS, *outputWS, pixelAdj.get()))
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";
168 continue;
169 }
170 // Skip if we have a monitor or if the detector is masked.
171 if (spectrumInfo.isMonitor(i) || spectrumInfo.isMasked(i))
172 continue;
173
174 // get the bins that are included inside the RadiusCut/WaveCutcut off, those
175 // to calculate for
176 // const size_t wavStart = waveLengthCutOff(i);
177 const size_t wavStart =
178 helper.waveLengthCutOff(m_dataWS, spectrumInfo, getProperty("RadiusCut"), getProperty("WaveCut"), i);
179 if (wavStart >= m_dataWS->y(i).size()) {
180 // all the spectra in this detector are out of range
181 continue;
182 }
183
184 const size_t numWavbins = m_dataWS->y(i).size() - wavStart;
185 // make just one call to new to reduce CPU overhead on each thread, access
186 // to these
187 // three "arrays" is via iterators
188 HistogramData::HistogramY _noDirectUseStorage_(3 * numWavbins);
189 // normalization term
190 auto norms = _noDirectUseStorage_.begin();
191 // the error on these weights, it contributes to the error calculation on
192 // the output workspace
193 auto normETo2s = norms + numWavbins;
194 // the Q values calculated from input wavelength workspace
195 auto QIn = normETo2s + numWavbins;
196
197 // the weighting for this input spectrum that is added to the normalization
198 calculateNormalization(wavStart, i, pixelAdj, wavePixelAdj, binNorms, binNormEs, norms, normETo2s);
199
200 // now read the data from the input workspace, calculate Q for each bin
201 convertWavetoQ(spectrumInfo, i, doGravity, wavStart, QIn, getProperty("ExtraLength"));
202
203 // Pointers to the counts data and it's error
204 auto YIn = m_dataWS->y(i).cbegin() + wavStart;
205 auto EIn = m_dataWS->e(i).cbegin() + wavStart;
206
207 // Pointers to the QResolution data. Note that the xdata was initially the
208 // same, hence
209 // the same indexing applies to the y values of m_dataWS and qResolution
210 // If we want to use it set it to the correct value, else to YIN, although
211 // that does not matter, as
212 // we won't use it
213 auto QResIn = useQResolution ? (qResolution->y(i).cbegin() + wavStart) : YIn;
214
215 // when finding the output Q bin remember that the input Q bins (from the
216 // convert to wavelength) start high and reduce
217 auto loc = QOut.cend();
218 // sum the Q contributions from each individual spectrum into the output
219 // array
220 const auto end = m_dataWS->y(i).cend();
221 for (; YIn != end; ++YIn, ++EIn, ++QIn, ++norms, ++normETo2s) {
222 // find the output bin that each input y-value will fall into, remembering
223 // there is one more bin boundary than bins
224 getQBinPlus1(QOut, *QIn, loc);
225 // ignore counts that are out of the output range
226 if ((loc != QOut.begin()) && (loc != QOut.end())) {
227 // the actual Q-bin to add something to
228 const size_t bin = loc - QOut.begin() - 1;
229 PARALLEL_CRITICAL(q1d_counts_sum) {
230 YOut[bin] += *YIn;
231 normSum[bin] += *norms;
232 // these are the errors squared which will be summed and square rooted
233 // at the end
234 EOutTo2[bin] += (*EIn) * (*EIn);
235 normError2[bin] += *normETo2s;
236 if (useQResolution) {
237 auto QBin = (QOut[bin + 1] - QOut[bin]);
238 // Here we need to take into account the Bin width and the count
239 // weigthing. The
240 // formula should be YIN* sqrt(QResIn^2 + (QBin/sqrt(12))^2)
241 qResolutionOut[bin] += (*YIn) * std::sqrt((*QResIn) * (*QResIn) + QBin * QBin / 12.0);
242 }
243 }
244 }
245
246 // Increment the QResolution iterator
247 if (useQResolution) {
248 ++QResIn;
249 }
250 }
251
252 PARALLEL_CRITICAL(q1d_spectra_map) {
253 progress.report("Computing I(Q)");
254 // Add up the detector IDs in the output spectrum at workspace index 0
255 const auto &inSpec = m_dataWS->getSpectrum(i);
256 auto &outSpec = outputWS->getSpectrum(0);
257 outSpec.addDetectorIDs(inSpec.getDetectorIDs());
258 }
259
261 }
263
264 if (useQResolution) {
265 // The number of Q (x)_ values is N, while the number of DeltaQ values is
266 // N-1,
267 // Richard Heenan suggested to duplicate the last entry of DeltaQ
268 auto countsIterator = YOut.cbegin();
269 auto qResolutionIterator = qResolutionOut.begin();
270 for (; countsIterator != YOut.end(); ++countsIterator, ++qResolutionIterator) {
271 // Divide by the counts of the Qbin, if the counts are 0, the the
272 // qresolution will also be 0
273 if ((*countsIterator) > 0.0) {
274 *qResolutionIterator = (*qResolutionIterator) / (*countsIterator);
275 }
276 }
277 outputWS->setPointStandardDeviations(0, std::move(qResolutionOut));
278 }
279
280 bool doOutputParts = getProperty("OutputParts");
281 if (doOutputParts) {
282 MatrixWorkspace_sptr ws_sumOfCounts = WorkspaceFactory::Instance().create(outputWS);
283 ws_sumOfCounts->setSharedX(0, outputWS->sharedX(0));
284 // Copy now as YOut is modified in normalize
285 ws_sumOfCounts->mutableY(0) = YOut;
286 ws_sumOfCounts->setSharedDx(0, outputWS->sharedDx(0));
287 ws_sumOfCounts->setFrequencyVariances(0, outputWS->e(0));
288
289 MatrixWorkspace_sptr ws_sumOfNormFactors = WorkspaceFactory::Instance().create(outputWS);
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);
294
295 helper.outputParts(this, ws_sumOfCounts, ws_sumOfNormFactors);
296 }
297
298 progress.report("Normalizing I(Q)");
299 // finally divide the number of counts in each output Q bin by its weighting
300 normalize(normSum, normError2, YOut, EOutTo2);
301
302 setProperty("OutputWorkspace", outputWS);
303}
304
310API::MatrixWorkspace_sptr Q1D2::setUpOutputWorkspace(const std::vector<double> &binParams) const {
311 // Calculate the output binning
312 std::vector<double> xAxisTmp;
313 VectorHelper::createAxisFromRebinParams(binParams, xAxisTmp);
314 HistogramData::BinEdges XOut(std::move(xAxisTmp));
315
316 // Create output workspace. On all but rank 0 this is a temporary workspace.
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");
322
323 outputWS->setDistribution(true);
324
325 outputWS->getSpectrum(0).clearDetectorIDs();
326 outputWS->getSpectrum(0).setSpectrumNo(1);
327
328 return outputWS;
329}
330
348void Q1D2::calculateNormalization(const size_t wavStart, const size_t wsIndex,
349 const API::MatrixWorkspace_const_sptr &pixelAdj,
350 const API::MatrixWorkspace_const_sptr &wavePixelAdj, double const *const binNorms,
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);
355 // use that the normalization array ends at the start of the error array
356 for (auto n = norm, e = normETo2; n != normETo2; ++n, ++e) {
357 *n = detectorAdj;
358 *e = detAdjErr * detAdjErr;
359 }
360
361 if (binNorms && binNormEs) {
362 if (wavePixelAdj)
363 // pass the iterator for the wave pixel Adj dependent
364 addWaveAdj(binNorms + wavStart, binNormEs + wavStart, norm, normETo2, wavePixelAdj->y(wsIndex).begin() + wavStart,
365 wavePixelAdj->e(wsIndex).begin() + wavStart);
366 else
367 addWaveAdj(binNorms + wavStart, binNormEs + wavStart, norm, normETo2);
368 }
369 normToMask(wavStart, wsIndex, norm, normETo2);
370}
371
383void Q1D2::pixelWeight(const API::MatrixWorkspace_const_sptr &pixelAdj, const size_t wsIndex, double &weight,
384 double &error) const {
385 Geometry::ComponentInfo const &componentInfo = m_dataWS->componentInfo();
386 Geometry::DetectorInfo const &detectorInfo = m_dataWS->detectorInfo();
387 V3D const samplePos = componentInfo.samplePosition();
388
389 if (m_doSolidAngle) {
390 const int numberOfCylinderSlices = getProperty("SolidAngleNumberOfCylinderSlices");
391 weight = 0.0;
392 for (const auto detID : m_dataWS->getSpectrum(wsIndex).getDetectorIDs()) {
393 const auto index = detectorInfo.indexOf(detID);
394 if (!detectorInfo.isMasked(index))
395 weight += componentInfo.solidAngle(index, {samplePos, numberOfCylinderSlices});
396 }
397 } else
398 weight = 1.0;
399
400 if (weight < 1e-200) {
401 throw std::logic_error("Invalid (zero or negative) solid angle for one detector");
402 }
403 // this input multiplies up the adjustment if it exists
404 if (pixelAdj) {
405 weight *= pixelAdj->y(wsIndex)[0];
406 error = weight * pixelAdj->e(wsIndex)[0];
407 } else {
408 error = 0.0;
409 }
410}
411
424void Q1D2::addWaveAdj(const double *c, const double *Dc, HistogramData::HistogramY::iterator bInOut,
425 HistogramData::HistogramY::iterator e2InOut) const {
426 // normalize by the wavelength dependent correction, keeping the percentage
427 // errors the same
428 // the error when a = b*c, the formula for Da, the error on a, in terms of Db,
429 // etc. is (Da/a)^2 = (Db/b)^2 + (Dc/c)^2
430 //(Da)^2 = ((Db*a/b)^2 + (Dc*a/c)^2) = (Db*c)^2 + (Dc*b)^2
431 // the variable names relate to those above as: existing values (b=bInOut)
432 // multiplied by the additional errors (Dc=binNormEs), existing errors
433 // (Db=sqrt(e2InOut)) times new factor (c=binNorms)
434
435 // use the fact that error array follows straight after the normalization
436 // array
437 const auto end = e2InOut;
438 for (; bInOut != end; ++e2InOut, ++c, ++Dc, ++bInOut) {
439 // first the error
440 *e2InOut = ((*e2InOut) * (*c) * (*c)) + ((*Dc) * (*Dc) * (*bInOut) * (*bInOut));
441 // now the actual calculation a = b*c
442 *bInOut = (*bInOut) * (*c);
443 }
444}
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 {
465 // normalize by the wavelength dependent correction, keeping the percentage
466 // errors the same
467 // the error when a = b*c*e, the formula for Da, the error on a, in terms of
468 // Db, etc. is
469 // (Da/a)^2 = (Db/b)^2 + (Dc/c)^2 + (De/e)^2
470 //(Da)^2 = ((Db*a/b)^2 + (Dc*a/c)^2) + (De * a/e)^2
471 // But: a/b = c*e; a/c = b*e; a/e = b*c;
472 // So:
473 // (Da)^2 = (c*e*Db)^2 + (b*e*Dc)^2 + (b*c*De)^2
474 //
475 // Consider:
476 // Da = Error (e2InOut)
477 // Db^2 = PixelDependentError (e2InOut)
478 // b = PixelDependentValue (bInOut)
479 // c = WaveDependentValue (c)
480 // Dc = WaveDependentError (Dc)
481 // e = PixelWaveDependentValue (wavePixelAdjData)
482 // De = PiexlWaveDependentError (wavePixelAdjError)
483
484 // use the fact that error array follows straight after the normalization
485 // array
486 const auto end = e2InOut;
487 for (; bInOut != end; ++e2InOut, ++c, ++Dc, ++bInOut, ++wavePixelAdjData, ++wavePixelAdjError) {
488 // first the error
489 *e2InOut = ((*e2InOut) * (*c) * (*c) * (*wavePixelAdjData) * (*wavePixelAdjData)) +
490 ((*Dc) * (*Dc) * (*bInOut) * (*bInOut) * (*wavePixelAdjData) * (*wavePixelAdjData)) +
491 ((*wavePixelAdjError) * (*wavePixelAdjError) * (*c) * (*c) * (*bInOut) * (*bInOut));
492 // now the actual calculation a = b*c*e : Pixel * Wave * PixelWave
493 *bInOut = (*bInOut) * (*c) * (*wavePixelAdjData);
494 }
495}
496
506void Q1D2::normToMask(const size_t offSet, const size_t wsIndex, const HistogramData::HistogramY::iterator theNorms,
507 const HistogramData::HistogramY::iterator errorSquared) const {
508 // if any bins are masked it is normally a small proportion
509 if (m_dataWS->hasMaskedBins(wsIndex)) {
510 // Get a reference to the list of masked bins
511 const MatrixWorkspace::MaskList &mask = m_dataWS->maskedBins(wsIndex);
512 // Now iterate over the list, adjusting the weights for the affected bins
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) {
517 // this masked bin wasn't in the range being delt with anyway
518 continue;
519 }
520 outBin -= offSet;
521 // The weight for this masked bin is 1 - the degree to which this bin is
522 // masked
523 const double factor = 1.0 - (it->second);
524 *(theNorms + outBin) *= factor;
525 *(errorSquared + outBin) *= factor * factor;
526 }
527 }
528}
529
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;
546
547 // wavelengths (lamda) to be converted to Q
548 auto waves = m_dataWS->x(wsInd).cbegin() + offset;
549 // going from bin boundaries to bin centered x-values the size goes down one
550 const auto end = m_dataWS->x(wsInd).end() - 1;
551 if (doGravity) {
552 GravitySANSHelper grav(spectrumInfo, wsInd, extraLength);
553 for (; waves != end; ++Qs, ++waves) {
554 // the HistogramValidator at the start should ensure that we have one more
555 // bin on the input wavelengths
556 const double lambda = 0.5 * (*(waves + 1) + (*waves));
557 // as the fall under gravity is wavelength dependent sin theta is now
558 // different for each bin with each detector
559 const double sinTheta = grav.calcSinTheta(lambda);
560 // Now we're ready to go to Q
561 *Qs = FOUR_PI * sinTheta / lambda;
562 }
563 } else {
564 // Calculate the Q values for the current spectrum, using Q =
565 // 4*pi*sin(theta)/lambda
566 const double factor = 2.0 * FOUR_PI * sin(spectrumInfo.twoTheta(wsInd) * 0.5);
567 for (; waves != end; ++Qs, ++waves) {
568 // the HistogramValidator at the start should ensure that we have one more
569 // bin on the input wavelengths
570 *Qs = factor / (*(waves + 1) + (*waves));
571 }
572 }
573}
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)) {
592 return;
593 }
594 --loc;
595 }
596 if (QToFind < *loc) {
597 // QToFind is outside the array leave loc == OutQs.begin()
598 return;
599 }
600 } else // loc == OutQs.end()
601 {
602 if (OutQs.empty() || QToFind > *(loc - 1)) {
603 // outside the array leave loc == OutQs.end()
604 return;
605 }
606 }
607
608 // we are lost, normally the order of the Q values means we only get here on
609 // the first iteration. It's slow
610 loc = std::lower_bound(OutQs.begin(), OutQs.end(), QToFind);
611}
612
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) {
626 // the normalisation is a = b/c where b = counts c =normalistion term
627 const double c = normSum[k];
628 const double a = counts[k] /= c;
629 // when a = b/c, the formula for Da, the error on a, in terms of Db, etc. is
630 // (Da/a)^2 = (Db/b)^2 + (Dc/c)^2
631 //(Da)^2 = ((Db/b)^2 + (Dc/c)^2)*(b^2/c^2) = ((Db/c)^2 + (b*Dc/c^2)^2) =
632 //(Db^2 + (b*Dc/c)^2)/c^2 = (Db^2 + (Dc*a)^2)/c^2
633 // this will work as long as c>0, but then the above formula above can't
634 // deal with 0 either
635 const double aOverc = a / c;
636 errors[k] = std::sqrt(errors[k] / (c * c) + normError2[k] * aOverc * aOverc);
637 }
638}
639} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:547
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:426
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:506
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:348
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:623
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:383
Q1D2()
Default constructor.
Definition Q1D2.cpp:45
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:543
API::MatrixWorkspace_sptr setUpOutputWorkspace(const std::vector< double > &binParams) const
Creates the output workspace, its size, units, etc.
Definition Q1D2.cpp:310
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:47
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:587
void exec() override
Execution code.
Definition Q1D2.cpp:119
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:424
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
ComponentInfo : Provides a component centric view on to the instrument.
double solidAngle(const size_t componentIndex, const Geometry::SolidAngleParams &params) 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.
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:35
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:54
@ Output
An output workspace.
Definition Property.h:55