Mantid
Loading...
Searching...
No Matches
NormaliseToMonitor.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 +
20#include "MantidHistogramData/Histogram.h"
26#include "MantidTypes/SpectrumDefinition.h"
27
28#include <cfloat>
29#include <numeric>
30
31using namespace Mantid::API;
32using namespace Mantid::DataObjects;
33using namespace Mantid::HistogramData;
35
36namespace Mantid::Algorithms {
37
38// Method of complex validator class
39// method checks if the property is enabled
41 int sp_id = algo->getProperty(SpectraNum);
42 // if there is spectra number set to normalize by, nothing else can be
43 // selected;
44 if (sp_id > 0) {
45 is_enabled = false;
46 return false;
47 } else {
48 is_enabled = true;
49 }
50
51 // is there the ws property, which describes monitors ws. It also disables the
52 // monitors ID property
54 if (monitorsWS) {
55 is_enabled = false;
56 } else {
57 is_enabled = true;
58 }
59 return is_enabled;
60}
61
62// method checks if other properties have changed and these changes affected
63// MonID property
64bool MonIDPropChanger::isConditionChanged(const IPropertyManager *algo, const std::string &changedPropName) const {
65 UNUSED_ARG(changedPropName);
66 // is enabled is based on other properties:
67 if (!is_enabled)
68 return false;
69 // read monitors list from the input workspace
71 return monitorIdReader(inputWS);
72}
73
74// function which modifies the allowed values for the list of monitors.
75bool MonIDPropChanger::applyChanges(const IPropertyManager *algo, const std::string &propName) {
76 auto *piProp = dynamic_cast<Kernel::PropertyWithValue<int> *>(algo->getPointerToProperty(propName));
77 if (!piProp) {
78 throw(std::invalid_argument("modify allowed value has been called on wrong property"));
79 }
80
81 if (iExistingAllowedValues.empty()) {
83 int spectra_max(-1);
84 if (inputWS) {
85 // let's assume that detectors IDs correspond to spectraID --
86 // not always the case but often. TODO: should be fixed
87 spectra_max = static_cast<int>(inputWS->getNumberHistograms()) + 1;
88 }
89 piProp->replaceValidator(std::make_shared<Kernel::BoundedValidator<int>>(-1, spectra_max));
90 } else {
91 piProp->replaceValidator(std::make_shared<Kernel::ListValidator<int>>(iExistingAllowedValues));
92 }
93 return true;
94}
95
96// read the monitors list from the workspace and try to do it once for any
97// particular ws;
99 // no workspace
100 if (!inputWS)
101 return false;
102
103 // no instrument
104 Geometry::Instrument_const_sptr pInstr = inputWS->getInstrument();
105 if (!pInstr)
106 return false;
107
108 // are these monitors really there?
109 std::vector<detid_t> monitorIDList = pInstr->getMonitors();
110 {
111 const auto &specInfo = inputWS->spectrumInfo();
112 std::set<detid_t> idsInWorkspace;
113 size_t i = 0;
114 // Loop over spectra, but finish early if we find everything
115 while (i < specInfo.size() && idsInWorkspace.size() < monitorIDList.size()) {
116 if (specInfo.isMonitor(i))
117 idsInWorkspace.insert(specInfo.detector(i).getID());
118 ++i;
119 }
120 monitorIDList = std::vector<detid_t>(idsInWorkspace.begin(), idsInWorkspace.end());
121 }
122
123 if (monitorIDList.empty()) {
124 if (iExistingAllowedValues.empty()) {
125 return false;
126 } else {
128 return true;
129 }
130 }
131
132 // are known values the same as the values we have just identified?
133 if (iExistingAllowedValues.size() != monitorIDList.size()) {
135 iExistingAllowedValues.assign(monitorIDList.begin(), monitorIDList.end());
136 return true;
137 }
138 // the monitor list has the same size as before. Is it equivalent to the
139 // existing one?
140 bool values_redefined = false;
141 for (size_t i = 0; i < monitorIDList.size(); i++) {
142 if (iExistingAllowedValues[i] != monitorIDList[i]) {
143 values_redefined = true;
144 iExistingAllowedValues[i] = monitorIDList[i];
145 }
146 }
147 return values_redefined;
148}
149
150bool spectrumDefinitionsMatchTimeIndex(const SpectrumDefinition &specDef, const size_t timeIndex) {
151 return std::none_of(specDef.cbegin(), specDef.cend(),
152 [timeIndex](const auto &spec) { return spec.second != timeIndex; });
153}
154
155// Register with the algorithm factory
156DECLARE_ALGORITHM(NormaliseToMonitor)
157
158using namespace Kernel;
159using namespace API;
160using std::size_t;
161
163 // Must be histograms OR one count per bin
164 // Must be raw counts
165 auto validatorHistSingle = std::make_shared<CompositeValidator>(CompositeRelation::OR);
166 validatorHistSingle->add<HistogramValidator>();
167 validatorHistSingle->add<SingleCountValidator>();
168 auto validator = std::make_shared<CompositeValidator>();
169 validator->add(validatorHistSingle);
170 validator->add<RawCountValidator>();
171
172 declareProperty(std::make_unique<WorkspaceProperty<>>("InputWorkspace", "", Direction::Input, validator),
173 "Name of the input workspace. Must be a non-distribution histogram.");
174
175 declareProperty(std::make_unique<WorkspaceProperty<>>("OutputWorkspace", "", Direction::Output),
176 "Name to use for the output workspace");
177 // should be any spectrum number, but named this property MonitorSpectrum to
178 // keep compatibility with previous scripts
179 // Can either set a spectrum within the workspace to be the monitor
180 // spectrum.....
181 declareProperty("MonitorSpectrum", -1,
182 "The spectrum number within the InputWorkspace you want to "
183 "normalize by (It can be a monitor spectrum or a spectrum "
184 "responsible for a group of detectors or monitors)",
186
187 // Or take monitor ID to identify the spectrum one wish to use or
188 declareProperty("MonitorID", -1,
189 "The MonitorID (detector ID), which defines the monitor's data "
190 "within the InputWorkspace. Will be overridden by the values "
191 "correspondent to MonitorSpectrum field if one is provided "
192 "in the field above.\n"
193 "If workspace do not have monitors, the MonitorID can refer "
194 "to empty data and the field then can accepts any MonitorID "
195 "within the InputWorkspace.");
196 // set up the validator, which would verify if spectrum is correct
197 setPropertySettings("MonitorID",
198 std::make_unique<MonIDPropChanger>("InputWorkspace", "MonitorSpectrum", "MonitorWorkspace"));
199
200 // ...or provide it in a separate workspace (note: optional WorkspaceProperty)
201 declareProperty(std::make_unique<WorkspaceProperty<>>("MonitorWorkspace", "", Direction::Input,
202 PropertyMode::Optional, validator),
203 "A workspace containing one or more spectra to normalize the "
204 "InputWorkspace by.");
205 setPropertySettings("MonitorWorkspace", std::make_unique<Kernel::EnabledWhenProperty>("MonitorSpectrum", IS_DEFAULT));
206
207 declareProperty("MonitorWorkspaceIndex", 0,
208 "The index of the spectrum within the MonitorWorkspace(2 "
209 "(0<=ind<=nHistograms in MonitorWorkspace) you want to "
210 "normalize by\n"
211 "(usually related to the index, responsible for the "
212 "monitor's data but can be any).\n"
213 "If no value is provided in this field, '''InputWorkspace''' "
214 "will be normalized by first spectra (with index 0)",
216 setPropertySettings("MonitorWorkspaceIndex",
217 std::make_unique<Kernel::EnabledWhenProperty>("MonitorSpectrum", IS_DEFAULT));
218
219 // If users set either of these optional properties two things happen
220 // 1) normalization is by an integrated count instead of bin-by-bin
221 // 2) if the value is within the range of X's in the spectrum it crops the
222 // spectrum
223 declareProperty("IntegrationRangeMin", EMPTY_DBL(),
224 "If set, normalization will be by integrated count from this "
225 "minimum x value");
226 declareProperty("IntegrationRangeMax", EMPTY_DBL(),
227 "If set, normalization will be by integrated count up to "
228 "this maximum x value");
229 declareProperty("IncludePartialBins", false,
230 "If true and an integration range is set then partial bins at either \n"
231 "end of the integration range are also included");
232
233 declareProperty(std::make_unique<WorkspaceProperty<>>("NormFactorWS", "", Direction::Output, PropertyMode::Optional),
234 "Name of the workspace, containing the normalization factor.\n"
235 "If this name is empty, normalization workspace is not returned. If the "
236 "name coincides with the output workspace name, _normFactor suffix is "
237 "added to this name");
238}
239
241 // Get the input workspace
242 const MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace");
243 MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace");
244 // First check the inputs
245 checkProperties(inputWS);
246
247 bool isSingleCountWorkspace = false;
248 try {
249 isSingleCountWorkspace = (!inputWS->isHistogramData()) && (inputWS->blocksize() == 1);
250 } catch (std::length_error &) {
251 // inconsistent bin size, not a single count workspace
252 isSingleCountWorkspace = false;
253 }
254
255 // See if the normalization with integration properties are set.
256 const bool integrate = setIntegrationProps(isSingleCountWorkspace);
257
258 if (integrate)
259 normaliseByIntegratedCount(inputWS, outputWS, isSingleCountWorkspace);
260 else
261 normaliseBinByBin(inputWS, outputWS);
262
263 setProperty("OutputWorkspace", outputWS);
264 std::string norm_ws_name = getPropertyValue("NormFactorWS");
265 if (!norm_ws_name.empty()) {
266 std::string out_name = getPropertyValue("OutputWorkspace");
267 if (out_name == norm_ws_name) {
268 // if the normalization factor workspace name coincides with output
269 // workspace name, add _normFactor suffix to this name
270 norm_ws_name = norm_ws_name + "_normFactor";
271 auto pProp = (this->getPointerToProperty("NormFactorWS"));
272 pProp->setValue(norm_ws_name);
273 }
274 if (!integrate)
276 setProperty("NormFactorWS", m_monitor);
277 }
278}
279
287 const std::vector<std::size_t> &workspaceIndexes) {
288 auto childAlg = createChildAlgorithm("ExtractSpectra");
289 childAlg->setProperty<MatrixWorkspace_sptr>("InputWorkspace", ws);
290 childAlg->setProperty("WorkspaceIndexList", workspaceIndexes);
291 childAlg->executeAsChildAlg();
292 MatrixWorkspace_sptr outWS = childAlg->getProperty("OutputWorkspace");
293 return outWS;
294}
295
299std::map<std::string, std::string> NormaliseToMonitor::validateInputs() {
300 std::map<std::string, std::string> issues;
301 // Check where the monitor spectrum should come from
302 const Property *monSpecProp = getProperty("MonitorSpectrum");
303 const Property *monIDProp = getProperty("MonitorID");
304 MatrixWorkspace_const_sptr monWS = getProperty("MonitorWorkspace");
305 // something has to be set
306 if (monSpecProp->isDefault() && !monWS && monIDProp->isDefault()) {
307 const std::string mess("Either MonitorSpectrum, MonitorID or "
308 "MonitorWorkspace has to be provided.");
309 issues["MonitorSpectrum"] = mess;
310 issues["MonitorID"] = mess;
311 issues["MonitorWorkspace"] = mess;
312 }
313
314 const double intMin = getProperty("IntegrationRangeMin");
315 const double intMax = getProperty("IntegrationRangeMax");
316 if (!isEmpty(intMin) && !isEmpty(intMax)) {
317 if (intMin > intMax) {
318 issues["IntegrationRangeMin"] = "Range minimum set to a larger value than maximum.";
319 issues["IntegrationRangeMax"] = "Range maximum set to a smaller value than minimum.";
320 }
321 }
322
323 if (monWS && monSpecProp->isDefault()) {
324 const int monIndex = getProperty("MonitorWorkspaceIndex");
325 if (monIndex < 0) {
326 issues["MonitorWorkspaceIndex"] = "A workspace index cannot be negative.";
327 } else if (monWS->getNumberHistograms() <= static_cast<size_t>(monIndex)) {
328 issues["MonitorWorkspaceIndex"] = "The MonitorWorkspace must contain the MonitorWorkspaceIndex.";
329 }
330 MatrixWorkspace_const_sptr inWS = getProperty("InputWorkspace");
331 if (monWS->getInstrument()->getName() != inWS->getInstrument()->getName()) {
332 issues["MonitorWorkspace"] = "The Input and Monitor workspaces must come "
333 "from the same instrument.";
334 }
335 if (monWS->getAxis(0)->unit()->unitID() != inWS->getAxis(0)->unit()->unitID()) {
336 issues["MonitorWorkspace"] = "The Input and Monitor workspaces must have the same unit";
337 }
338 }
339
340 return issues;
341}
342
347
348 // Check where the monitor spectrum should come from
349 Property const *monSpec = getProperty("MonitorSpectrum");
350 MatrixWorkspace_sptr monWS = getProperty("MonitorWorkspace");
351 Property const *monID = getProperty("MonitorID");
352 // Is the monitor spectrum within the main input workspace
353 const bool inWS = !monSpec->isDefault();
354 m_scanInput = inputWorkspace->detectorInfo().isScanning();
355 // Or is it in a separate workspace
356 bool sepWS{monWS};
357 if (m_scanInput && sepWS)
358 throw std::runtime_error("Can not currently use a separate monitor "
359 "workspace with a detector scan input workspace.");
360 // or monitor ID
361 bool monIDs = !monID->isDefault();
362 // something has to be set
363 // One and only one of these properties should have been set
364 // input from separate workspace is overwritten by monitor spectrum
365 if (inWS && sepWS) {
366 g_log.information("Both input workspace MonitorSpectrum number and monitor "
367 "workspace are specified. Ignoring Monitor Workspace");
368 sepWS = false;
369 }
370 // input from detector ID is rejected in favor of monitor sp
371 if (inWS && monIDs) {
372 g_log.information("Both input workspace MonitorSpectrum number and "
373 "detector ID are specified. Ignoring Detector ID");
374 monIDs = false;
375 }
376 // separate ws takes over detectorID (this logic is duplicated within
377 // getInWSMonitorSpectrum)
378 if (sepWS && monIDs) {
379 g_log.information("Both input MonitorWorkspace and detector ID are "
380 "specified. Ignoring Detector ID");
381 }
382
383 // Do a check for common binning and store
384 m_commonBins = inputWorkspace->isCommonBins();
385
386 // Check the monitor spectrum or workspace and extract into new workspace
387 m_monitor = sepWS ? getMonitorWorkspace(inputWorkspace) : getInWSMonitorSpectrum(inputWorkspace);
388
389 // Check that the 'monitor' spectrum actually relates to a monitor - warn if
390 // not
391 try {
392 const auto &monitorSpecInfo = m_monitor->spectrumInfo();
393 for (const auto workspaceIndex : m_workspaceIndexes)
394 if (!monitorSpecInfo.isMonitor(workspaceIndex))
395 g_log.warning() << "The spectrum N: " << workspaceIndex << " in MonitorWorkspace does not refer to a monitor.\n"
396 << "Continuing with normalization regardless.";
398 g_log.warning("Unable to check if the spectrum provided relates to a "
399 "monitor - the instrument is not fully specified.\n "
400 "Continuing with normalization regardless.");
401 g_log.warning() << "Error was: " << e.what() << "\n";
402 if (m_scanInput)
403 throw std::runtime_error("Can not continue, spectrum can not be obtained "
404 "for monitor workspace, but the input workspace "
405 "has a detector scan.");
406 }
407}
408
417 // this is the index of the spectra within the workspace and we need to
418 // identify it either from DetID or from SpecID
419 // size_t spectra_num(-1);
420 // try monitor spectrum. If it is specified, it overrides everything
421 int monitorSpec = getProperty("MonitorSpectrum");
422 if (monitorSpec < 0) {
423 // Get hold of the monitor spectrum through detector ID
424 int monitorID = getProperty("MonitorID");
425 if (monitorID < 0) {
426 throw std::runtime_error("Both MonitorSpectrum and MonitorID can not be negative");
427 }
428 // set spectra of detector's ID of one selected monitor ID
429 std::vector<detid_t> detID(1, monitorID);
430 // got the index of correspondent spectra (should be only one).
431 auto indexList = inputWorkspace->getIndicesFromDetectorIDs(detID);
432 if (indexList.empty()) {
433 throw std::runtime_error("Can not find spectra, corresponding to the requested monitor ID");
434 }
435 if (indexList.size() > 1 && !m_scanInput) {
436 throw std::runtime_error("More then one spectrum corresponds to the "
437 "requested monitor ID. This is unexpected in a "
438 "non-scanning workspace.");
439 }
440 m_workspaceIndexes = indexList;
441 } else { // monitor spectrum is specified.
442 if (m_scanInput)
443 throw std::runtime_error("For a scanning input workspace the monitor ID "
444 "must be provided. Normalisation can not be "
445 "performed to a spectrum.");
446 const SpectraAxis *axis = dynamic_cast<const SpectraAxis *>(inputWorkspace->getAxis(1));
447 if (!axis) {
448 throw std::runtime_error("Cannot retrieve monitor spectrum - spectrum "
449 "numbers not attached to workspace");
450 }
451 auto specs = axis->getSpectraIndexMap();
452 if (!specs.count(monitorSpec)) {
453 throw std::runtime_error("Input workspace does not contain spectrum "
454 "number given for MonitorSpectrum");
455 }
456 m_workspaceIndexes = std::vector<size_t>(1, specs[monitorSpec]);
457 }
458 return inputWorkspace;
459}
460
466 MatrixWorkspace_sptr monitorWS = getProperty("MonitorWorkspace");
467 const int wsID = getProperty("MonitorWorkspaceIndex");
468 m_workspaceIndexes = std::vector<size_t>(1, wsID);
469 // In this case we need to test whether the bins in the monitor workspace
470 // match
471 m_commonBins = (m_commonBins && WorkspaceHelpers::matchingBins(inputWorkspace, monitorWS, true));
472 // Copy the monitor spectrum because it will get changed
473 return monitorWS;
474}
475
489bool NormaliseToMonitor::setIntegrationProps(const bool isSingleCountWorkspace) {
490 m_integrationMin = getProperty("IntegrationRangeMin");
491 m_integrationMax = getProperty("IntegrationRangeMax");
492
493 // Check if neither of these have been changed from their defaults
494 // (EMPTY_DBL())
495 if ((isEmpty(m_integrationMin) && isEmpty(m_integrationMax)) && !isSingleCountWorkspace) {
496 // Nothing has been set so the user doesn't want to use integration so let's
497 // move on
498 return false;
499 }
500 // Yes integration is going to be used...
501
502 // Now check the end X values are within the X value range of the workspace
503 if ((isEmpty(m_integrationMin) || m_integrationMin < m_monitor->x(0).front()) && !isSingleCountWorkspace) {
504 g_log.warning() << "Integration range minimum set to workspace min: " << m_integrationMin << '\n';
505 m_integrationMin = m_monitor->x(0).front();
506 }
507 if ((isEmpty(m_integrationMax) || m_integrationMax > m_monitor->x(0).back()) && !isSingleCountWorkspace) {
508 g_log.warning() << "Integration range maximum set to workspace max: " << m_integrationMax << '\n';
509 m_integrationMax = m_monitor->x(0).back();
510 }
511
512 // Return indicating that these properties should be used
513 return true;
514}
515
524 MatrixWorkspace_sptr &outputWorkspace,
525 const bool isSingleCountWorkspace) {
527
528 // If single counting no need to integrate, monitor already guaranteed to be a
529 // single count
530 if (!isSingleCountWorkspace) {
531 // Add up all the bins so it's just effectively a series of values with
532 // errors
533 auto integrate = createChildAlgorithm("Integration");
534 integrate->setProperty<MatrixWorkspace_sptr>("InputWorkspace", m_monitor);
535 integrate->setProperty("RangeLower", m_integrationMin);
536 integrate->setProperty("RangeUpper", m_integrationMax);
537 integrate->setProperty<bool>("IncludePartialBins", getProperty("IncludePartialBins"));
538 integrate->executeAsChildAlg();
539 m_monitor = integrate->getProperty("OutputWorkspace");
540 }
541
542 EventWorkspace_sptr inputEvent = std::dynamic_pointer_cast<EventWorkspace>(inputWorkspace);
543
544 if (inputEvent) {
545 // Run the divide algorithm explicitly to enable progress reporting
546 auto divide = createChildAlgorithm("Divide", 0.0, 1.0);
547 divide->setProperty<MatrixWorkspace_sptr>("LHSWorkspace", inputWorkspace);
548 divide->setProperty<MatrixWorkspace_sptr>("RHSWorkspace", m_monitor);
549 divide->setProperty<MatrixWorkspace_sptr>("OutputWorkspace", outputWorkspace);
550 divide->executeAsChildAlg();
551
552 // Get back the result
553 outputWorkspace = divide->getProperty("OutputWorkspace");
554 } else {
555 performHistogramDivision(inputWorkspace, outputWorkspace);
556 }
557}
558
569 MatrixWorkspace_sptr &outputWorkspace) {
570 if (outputWorkspace != inputWorkspace)
571 outputWorkspace = inputWorkspace->clone();
572
573 size_t monitorWorkspaceIndex = 0;
574
575 Progress prog(this, 0.0, 1.0, m_workspaceIndexes.size());
576 const auto &specInfo = inputWorkspace->spectrumInfo();
577 for (const auto workspaceIndex : m_workspaceIndexes) {
578 // Errors propagated according to
579 // http://docs.mantidproject.org/nightly/concepts/ErrorPropagation.html#error-propagation
580 // This is similar to that in MantidAlgorithms::Divide
581
582 prog.report("Performing normalisation");
583
584 size_t timeIndex = 0;
585 if (m_scanInput)
586 timeIndex = specInfo.spectrumDefinition(workspaceIndex)[0].second;
587
588 const auto newYFactor = 1.0 / m_monitor->histogram(monitorWorkspaceIndex).y()[0];
589 const auto divisorError = m_monitor->histogram(monitorWorkspaceIndex).e()[0];
590 const double yErrorFactor = pow(divisorError * newYFactor, 2);
591 monitorWorkspaceIndex++;
592
593 PARALLEL_FOR_IF(Kernel::threadSafe(*outputWorkspace))
594 for (int64_t i = 0; i < int64_t(outputWorkspace->getNumberHistograms()); ++i) {
596 const auto &specDef = specInfo.spectrumDefinition(i);
597
598 if (!spectrumDefinitionsMatchTimeIndex(specDef, timeIndex))
599 continue;
600
601 auto hist = outputWorkspace->histogram(i);
602 auto &yValues = hist.mutableY();
603 auto &eValues = hist.mutableE();
604
605 for (size_t j = 0; j < yValues.size(); ++j) {
606 eValues[j] = newYFactor * sqrt(eValues[j] * eValues[j] + yValues[j] * yValues[j] * yErrorFactor);
607 yValues[j] *= newYFactor;
608 }
609
610 outputWorkspace->setHistogram(i, hist);
612 }
614 }
615}
616
622 MatrixWorkspace_sptr &outputWorkspace) {
623 EventWorkspace_sptr inputEvent = std::dynamic_pointer_cast<EventWorkspace>(inputWorkspace);
624
625 // Only create output workspace if different to input one
626 if (outputWorkspace != inputWorkspace) {
627 if (inputEvent) {
628 outputWorkspace = inputWorkspace->clone();
629 } else
630 outputWorkspace = create<MatrixWorkspace>(*inputWorkspace);
631 }
632 auto outputEvent = std::dynamic_pointer_cast<EventWorkspace>(outputWorkspace);
633
634 const auto &inputSpecInfo = inputWorkspace->spectrumInfo();
635 const auto &monitorSpecInfo = m_monitor->spectrumInfo();
636
637 const auto specLength = inputWorkspace->blocksize();
638 for (auto &workspaceIndex : m_workspaceIndexes) {
639 // Get hold of the monitor spectrum
640 const auto &monX = m_monitor->binEdges(workspaceIndex);
641 auto monY = m_monitor->counts(workspaceIndex);
642 auto monE = m_monitor->countStandardDeviations(workspaceIndex);
643 size_t timeIndex = 0;
644 if (m_scanInput)
645 timeIndex = monitorSpecInfo.spectrumDefinition(workspaceIndex)[0].second;
646 // Calculate the overall normalization just the once if bins are all
647 // matching
648 if (m_commonBins)
649 this->normalisationFactor(monX, monY, monE);
650
651 const size_t numHists = inputWorkspace->getNumberHistograms();
652 // Flag set when a division by 0 is found
653 bool hasZeroDivision = false;
654 Progress prog(this, 0.0, 1.0, numHists);
655 // Loop over spectra
656 PARALLEL_FOR_IF(Kernel::threadSafe(*inputWorkspace, *outputWorkspace, *m_monitor))
657 for (int64_t i = 0; i < int64_t(numHists); ++i) {
659 prog.report();
660
661 const auto &specDef = inputSpecInfo.spectrumDefinition(i);
662 if (!spectrumDefinitionsMatchTimeIndex(specDef, timeIndex))
663 continue;
664
665 const auto &X = inputWorkspace->binEdges(i);
666 // If not rebinning, just point to our monitor spectra, otherwise create
667 // new vectors
668
669 auto Y = (m_commonBins ? monY : Counts(specLength));
670 auto E = (m_commonBins ? monE : CountStandardDeviations(specLength));
671
672 if (!m_commonBins) {
673 // ConvertUnits can give X vectors of all zeros - skip these, they
674 // cause
675 // problems
676 if (X.back() == 0.0 && X.front() == 0.0)
677 continue;
678 // Rebin the monitor spectrum to match the binning of the current data
679 // spectrum
680 VectorHelper::rebinHistogram(monX.rawData(), monY.mutableRawData(), monE.mutableRawData(), X.rawData(),
681 Y.mutableRawData(), E.mutableRawData(), false);
682 // Recalculate the overall normalization factor
683 this->normalisationFactor(X, Y, E);
684 }
685
686 if (inputEvent) {
687 // --- EventWorkspace ---
688 EventList &outEL = outputEvent->getSpectrum(i);
689 outEL.divide(X.rawData(), Y.mutableRawData(), E.mutableRawData());
690 } else {
691 // --- Workspace2D ---
692 auto &YOut = outputWorkspace->mutableY(i);
693 auto &EOut = outputWorkspace->mutableE(i);
694 const auto &inY = inputWorkspace->y(i);
695 const auto &inE = inputWorkspace->e(i);
696 outputWorkspace->setSharedX(i, inputWorkspace->sharedX(i));
697
698 // The code below comes more or less straight out of Divide.cpp
699 for (size_t k = 0; k < specLength; ++k) {
700 // Get the input Y's
701 const double leftY = inY[k];
702 const double rightY = Y[k];
703
704 if (rightY == 0.0) {
705 hasZeroDivision = true;
706 }
707
708 // Calculate result and store in local variable to avoid overwriting
709 // original data if output workspace is same as one of the input
710 // ones
711 const double newY = leftY / rightY;
712
713 if (fabs(rightY) > 1.0e-12 && fabs(newY) > 1.0e-12) {
714 const double lhsFactor = (inE[k] < 1.0e-12 || fabs(leftY) < 1.0e-12) ? 0.0 : pow((inE[k] / leftY), 2);
715 const double rhsFactor = E[k] < 1.0e-12 ? 0.0 : pow((E[k] / rightY), 2);
716 EOut[k] = std::abs(newY) * sqrt(lhsFactor + rhsFactor);
717 }
718
719 // Now store the result
720 YOut[k] = newY;
721 } // end Workspace2D case
722 } // end loop over current spectrum
723
725 } // end loop over spectra
727
728 if (hasZeroDivision) {
729 g_log.warning() << "Division by zero in some of the bins.\n";
730 }
731 if (inputEvent)
732 outputEvent->clearMRU();
733 }
734}
735
744void NormaliseToMonitor::normalisationFactor(const BinEdges &X, Counts &Y, CountStandardDeviations &E) {
745 const double monitorSum = std::accumulate(Y.begin(), Y.end(), 0.0);
746 const double range = X.back() - X.front();
747 auto specLength = Y.size();
748
749 auto &yNew = Y.mutableRawData();
750 auto &eNew = E.mutableRawData();
751
752 for (size_t j = 0; j < specLength; ++j) {
753 const double factor = range / ((X[j + 1] - X[j]) * monitorSum);
754 yNew[j] *= factor;
755 eNew[j] *= factor;
756 }
757}
758
759} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
#define fabs(x)
Definition Matrix.cpp:22
#define PARALLEL_START_INTERRUPT_REGION
Begins a block to skip processing is the algorithm has been interupted Note the end of the block if n...
#define PARALLEL_END_INTERRUPT_REGION
Ends a block to skip processing is the algorithm has been interupted Note the start of the block if n...
#define PARALLEL_FOR_IF(condition)
Empty definitions - to enable set your complier to enable openMP.
#define PARALLEL_CHECK_INTERRUPT_REGION
Adds a check after a Parallel region to see if it was interupted.
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
Definition System.h:48
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
Kernel::Property * getPointerToProperty(const std::string &name) const override
Get a property by name.
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
virtual std::shared_ptr< Algorithm > createChildAlgorithm(const std::string &name, const double startProgress=-1., const double endProgress=-1., const bool enableLogging=true, const int &version=-1)
Create a Child Algorithm.
Kernel::Logger & g_log
Definition Algorithm.h:422
static bool isEmpty(const NumT toCheck)
checks that the value was not set by users, uses the value in empty double/int.
A validator which checks that a workspace contains histogram data (the default) or point data as requ...
Helper class for reporting progress from algorithms.
Definition Progress.h:25
A validator which checks that a workspace contains raw counts in its bins.
SingleCountValidator : This validator checks that there is only a single entry per spectrum,...
Class to represent the spectra axis of a workspace.
Definition SpectraAxis.h:31
spec2index_map getSpectraIndexMap() const
Returns a map where spectra is the key and index is the value This is used for efficient search of sp...
A property class for workspaces.
bool applyChanges(const Mantid::Kernel::IPropertyManager *algo, const std::string &propName) override
Overload this virtual function in order to modify the current property based on changes to other prop...
bool monitorIdReader(const API::MatrixWorkspace_const_sptr &inputWS) const
bool isConditionChanged(const Mantid::Kernel::IPropertyManager *algo, const std::string &changedPropName="") const override
to verify if the properties, this one depends on have changed or other special condition occurs which...
bool isEnabled(const Mantid::Kernel::IPropertyManager *algo) const override
Is the property to be shown as "enabled" in the GUI.
void performHistogramDivision(const API::MatrixWorkspace_sptr &inputWorkspace, API::MatrixWorkspace_sptr &outputWorkspace)
This performs a similar operation to divide, but is a separate algorithm so that the correct spectra ...
bool m_commonBins
Whether the input workspace has common bins.
double m_integrationMax
The upper bound of the integration range.
void normalisationFactor(const HistogramData::BinEdges &X, HistogramData::Counts &Y, HistogramData::CountStandardDeviations &E)
Calculates the overall normalization factor.
void normaliseBinByBin(const API::MatrixWorkspace_sptr &inputWorkspace, API::MatrixWorkspace_sptr &outputWorkspace)
Carries out the bin-by-bin normalization.
void exec() override
Virtual method - must be overridden by concrete algorithm.
void normaliseByIntegratedCount(const API::MatrixWorkspace_sptr &inputWorkspace, API::MatrixWorkspace_sptr &outputWorkspace, const bool isSingleCountWorkspace)
Carries out a normalization based on the integrated count of the monitor over a range.
void init() override
Virtual method - must be overridden by concrete algorithm.
API::MatrixWorkspace_sptr getInWSMonitorSpectrum(const API::MatrixWorkspace_sptr &inputWorkspace)
Checks and retrieves the requested spectrum out of the input workspace.
double m_integrationMin
The lower bound of the integration range.
API::MatrixWorkspace_sptr m_monitor
A single spectrum workspace containing the monitor.
std::map< std::string, std::string > validateInputs() override
Validates input properties.
API::MatrixWorkspace_sptr getMonitorWorkspace(const API::MatrixWorkspace_sptr &inputWorkspace)
Checks and retrieves the monitor spectrum out of the input workspace.
void checkProperties(const API::MatrixWorkspace_sptr &inputWorkspace)
Makes sure that the input properties are set correctly.
bool setIntegrationProps(const bool isSingleCountWorkspace)
Sets the maximum and minimum X values of the monitor spectrum to use for integration.
API::MatrixWorkspace_sptr extractMonitorSpectra(const API::MatrixWorkspace_sptr &ws, const std::vector< size_t > &workspaceIndexes)
Pulls the monitor spectra out of a larger workspace.
A class for holding :
Definition EventList.h:57
void divide(const double value, const double error=0.0) override
Divide the weights in this event list by a scalar with an (optional) error.
BoundedValidator is a validator that requires the values to be between upper or lower bounds,...
Exception for when an item is not found in a collection.
Definition Exception.h:145
const char * what() const noexcept override
Writes out the range and limits.
Interface to PropertyManager.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void setPropertySettings(const std::string &name, std::unique_ptr< IPropertySettings > settings)
virtual Property * getPointerToProperty(const std::string &name) const =0
Get a pointer to property by name.
virtual TypedValue getProperty(const std::string &name) const =0
Get the value of a property.
ListValidator is a validator that requires the value of a property to be one of a defined list of pos...
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
void information(const std::string &msg)
Logs at information level.
Definition Logger.cpp:136
void report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
The concrete, templated class for properties.
Base class for properties.
Definition Property.h:94
virtual bool isDefault() const =0
Overriden function that returns if property has the same value that it was initialised with,...
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
bool spectrumDefinitionsMatchTimeIndex(const SpectrumDefinition &specDef, const size_t timeIndex)
std::shared_ptr< EventWorkspace > EventWorkspace_sptr
shared pointer to the EventWorkspace class
std::shared_ptr< const Instrument > Instrument_const_sptr
Shared pointer to an const instrument object.
void MANTID_KERNEL_DLL rebinHistogram(const std::vector< double > &xold, const std::vector< double > &yold, const std::vector< double > &eold, const std::vector< double > &xnew, std::vector< double > &ynew, std::vector< double > &enew, bool addition)
Rebins histogram data according to a new output X array.
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.
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition EmptyValues.h:42
static bool matchingBins(const std::shared_ptr< const MatrixWorkspace > &ws1, const std::shared_ptr< const MatrixWorkspace > &ws2, const bool firstOnly=false)
Checks whether the bins (X values) of two workspace are the same.
@ InOut
Both an input & output workspace.
Definition Property.h:55
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54