20#include "MantidHistogramData/Histogram.h"
26#include "MantidTypes/SpectrumDefinition.h"
79 throw(std::invalid_argument(
"modify allowed value has been called on wrong property"));
88 spectra_max =
static_cast<int>(inputWS->getNumberHistograms()) + 1;
110 std::vector<detid_t> monitorIDList = pInstr->getMonitorIDs();
112 const auto &specInfo = inputWS->spectrumInfo();
113 std::set<detid_t> idsInWorkspace;
116 while (i < specInfo.size() && idsInWorkspace.size() < monitorIDList.size()) {
117 if (specInfo.isMonitor(i))
118 idsInWorkspace.insert(specInfo.detector(i).getID());
121 monitorIDList = std::vector<detid_t>(idsInWorkspace.begin(), idsInWorkspace.end());
124 if (monitorIDList.empty()) {
141 bool values_redefined =
false;
142 for (
size_t i = 0; i < monitorIDList.size(); i++) {
144 values_redefined =
true;
148 return values_redefined;
152 return std::none_of(specDef.cbegin(), specDef.cend(),
153 [timeIndex](
const auto &spec) { return spec.second != timeIndex; });
159using namespace Kernel;
166 auto validatorHistSingle = std::make_shared<CompositeValidator>(CompositeRelation::OR);
169 auto validator = std::make_shared<CompositeValidator>();
170 validator->add(validatorHistSingle);
174 "Name of the input workspace. Must be a non-distribution histogram.");
177 "Name to use for the output workspace");
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)",
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.");
199 std::make_unique<MonIDPropChanger>(
"InputWorkspace",
"MonitorSpectrum",
"MonitorWorkspace"));
204 "A workspace containing one or more spectra to normalize the "
205 "InputWorkspace by.");
209 "The index of the spectrum within the MonitorWorkspace(2 "
210 "(0<=ind<=nHistograms in MonitorWorkspace) you want to "
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)",
218 std::make_unique<Kernel::EnabledWhenProperty>(
"MonitorSpectrum",
IS_DEFAULT));
225 "If set, normalization will be by integrated count from this "
228 "If set, normalization will be by integrated count up to "
229 "this maximum x value");
231 "If true and an integration range is set then partial bins at either \n"
232 "end of the integration range are also included");
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");
248 bool isSingleCountWorkspace =
false;
250 isSingleCountWorkspace = (!inputWS->isHistogramData()) && (inputWS->blocksize() == 1);
251 }
catch (std::length_error &) {
253 isSingleCountWorkspace =
false;
266 if (!norm_ws_name.empty()) {
268 if (out_name == norm_ws_name) {
271 norm_ws_name = norm_ws_name +
"_normFactor";
273 pProp->setValue(norm_ws_name);
288 const std::vector<std::size_t> &workspaceIndexes) {
291 childAlg->setProperty(
"WorkspaceIndexList", workspaceIndexes);
292 childAlg->executeAsChildAlg();
301 std::map<std::string, std::string> issues;
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;
315 const double intMin =
getProperty(
"IntegrationRangeMin");
316 const double intMax =
getProperty(
"IntegrationRangeMax");
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.";
325 const int monIndex =
getProperty(
"MonitorWorkspaceIndex");
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.";
332 if (monWS->getInstrument()->getName() != inWS->getInstrument()->getName()) {
333 issues[
"MonitorWorkspace"] =
"The Input and Monitor workspaces must come "
334 "from the same instrument.";
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";
355 m_scanInput = inputWorkspace->detectorInfo().isScanning();
359 throw std::runtime_error(
"Can not currently use a separate monitor "
360 "workspace with a detector scan input workspace.");
367 g_log.
information(
"Both input workspace MonitorSpectrum number and monitor "
368 "workspace are specified. Ignoring Monitor Workspace");
372 if (inWS && monIDs) {
374 "detector ID are specified. Ignoring Detector ID");
379 if (sepWS && monIDs) {
381 "specified. Ignoring Detector ID");
393 const auto &monitorSpecInfo =
m_monitor->spectrumInfo();
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.");
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.");
423 if (monitorSpec < 0) {
427 throw std::runtime_error(
"Both MonitorSpectrum and MonitorID can not be negative");
430 std::vector<detid_t> detID(1, monitorID);
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");
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.");
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.");
449 throw std::runtime_error(
"Cannot retrieve monitor spectrum - spectrum "
450 "numbers not attached to workspace");
453 if (!specs.count(monitorSpec)) {
454 throw std::runtime_error(
"Input workspace does not contain spectrum "
455 "number given for MonitorSpectrum");
459 return inputWorkspace;
468 const int wsID =
getProperty(
"MonitorWorkspaceIndex");
526 const bool isSingleCountWorkspace) {
531 if (!isSingleCountWorkspace) {
538 integrate->setProperty<
bool>(
"IncludePartialBins",
getProperty(
"IncludePartialBins"));
539 integrate->executeAsChildAlg();
540 m_monitor = integrate->getProperty(
"OutputWorkspace");
543 EventWorkspace_sptr inputEvent = std::dynamic_pointer_cast<EventWorkspace>(inputWorkspace);
551 divide->executeAsChildAlg();
554 outputWorkspace = divide->getProperty(
"OutputWorkspace");
571 if (outputWorkspace != inputWorkspace)
572 outputWorkspace = inputWorkspace->clone();
574 size_t monitorWorkspaceIndex = 0;
577 const auto &specInfo = inputWorkspace->spectrumInfo();
583 prog.
report(
"Performing normalisation");
585 size_t timeIndex = 0;
587 timeIndex = specInfo.spectrumDefinition(workspaceIndex)[0].second;
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++;
595 for (int64_t i = 0; i < int64_t(outputWorkspace->getNumberHistograms()); ++i) {
597 const auto &specDef = specInfo.spectrumDefinition(i);
602 auto hist = outputWorkspace->histogram(i);
603 auto &yValues = hist.mutableY();
604 auto &eValues = hist.mutableE();
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;
611 outputWorkspace->setHistogram(i, hist);
624 EventWorkspace_sptr inputEvent = std::dynamic_pointer_cast<EventWorkspace>(inputWorkspace);
627 if (outputWorkspace != inputWorkspace) {
629 outputWorkspace = inputWorkspace->clone();
631 outputWorkspace = create<MatrixWorkspace>(*inputWorkspace);
633 auto outputEvent = std::dynamic_pointer_cast<EventWorkspace>(outputWorkspace);
635 const auto &inputSpecInfo = inputWorkspace->spectrumInfo();
636 const auto &monitorSpecInfo =
m_monitor->spectrumInfo();
638 const auto specLength = inputWorkspace->blocksize();
641 const auto &monX =
m_monitor->binEdges(workspaceIndex);
643 auto monY =
m_monitor->counts(workspaceIndex);
644 auto monE =
m_monitor->countStandardDeviations(workspaceIndex);
645 size_t timeIndex = 0;
647 timeIndex = monitorSpecInfo.spectrumDefinition(workspaceIndex)[0].second;
653 const size_t numHists = inputWorkspace->getNumberHistograms();
655 bool hasZeroDivision =
false;
656 Progress prog(
this, 0.0, 1.0, numHists);
659 for (int64_t i = 0; i < int64_t(numHists); ++i) {
663 const auto &specDef = inputSpecInfo.spectrumDefinition(i);
667 const auto &
X = inputWorkspace->binEdges(i);
672 auto E = (
m_commonBins ? monE : CountStandardDeviations(specLength));
678 if (
X.back() == 0.0 &&
X.front() == 0.0)
685 E.mutableRawData(),
false);
692 EventList &outEL = outputEvent->getSpectrum(i);
694 outEL.
divide(
X, std::as_const(
Y), std::as_const(E));
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));
704 for (
size_t k = 0; k < specLength; ++k) {
706 const double leftY = inY[k];
707 const double rightY =
Y[k];
710 hasZeroDivision =
true;
716 const double newY = leftY / rightY;
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);
733 if (hasZeroDivision) {
734 g_log.
warning() <<
"Division by zero in some of the bins.\n";
737 outputEvent->clearMRU();
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();
754 auto &yNew =
Y.mutableRawData();
755 auto &eNew = E.mutableRawData();
757 for (
size_t j = 0; j < specLength; ++j) {
758 const double factor = range / ((
X[j + 1] -
X[j]) * monitorSum);
#define DECLARE_ALGORITHM(classname)
#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 ...
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.
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.
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.
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.
std::string MonitorWorkspaceProp
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...
std::vector< int > iExistingAllowedValues
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.
std::vector< size_t > m_workspaceIndexes
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.
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.
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.
void information(const std::string &msg)
Logs at information level.
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.
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.
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.
@ Input
An input workspace.
@ Output
An output workspace.