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