20#include "MantidHistogramData/Histogram.h"
26#include "MantidTypes/SpectrumDefinition.h"
78 throw(std::invalid_argument(
"modify allowed value has been called on wrong property"));
87 spectra_max =
static_cast<int>(inputWS->getNumberHistograms()) + 1;
109 std::vector<detid_t> monitorIDList = pInstr->getMonitors();
111 const auto &specInfo = inputWS->spectrumInfo();
112 std::set<detid_t> idsInWorkspace;
115 while (i < specInfo.size() && idsInWorkspace.size() < monitorIDList.size()) {
116 if (specInfo.isMonitor(i))
117 idsInWorkspace.insert(specInfo.detector(i).getID());
120 monitorIDList = std::vector<detid_t>(idsInWorkspace.begin(), idsInWorkspace.end());
123 if (monitorIDList.empty()) {
140 bool values_redefined =
false;
141 for (
size_t i = 0; i < monitorIDList.size(); i++) {
143 values_redefined =
true;
147 return values_redefined;
151 return std::none_of(specDef.cbegin(), specDef.cend(),
152 [timeIndex](
const auto &spec) { return spec.second != timeIndex; });
158using namespace Kernel;
165 auto validatorHistSingle = std::make_shared<CompositeValidator>(CompositeRelation::OR);
168 auto validator = std::make_shared<CompositeValidator>();
169 validator->add(validatorHistSingle);
173 "Name of the input workspace. Must be a non-distribution histogram.");
176 "Name to use for the output workspace");
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)",
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.");
198 std::make_unique<MonIDPropChanger>(
"InputWorkspace",
"MonitorSpectrum",
"MonitorWorkspace"));
203 "A workspace containing one or more spectra to normalize the "
204 "InputWorkspace by.");
208 "The index of the spectrum within the MonitorWorkspace(2 "
209 "(0<=ind<=nHistograms in MonitorWorkspace) you want to "
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)",
217 std::make_unique<Kernel::EnabledWhenProperty>(
"MonitorSpectrum",
IS_DEFAULT));
224 "If set, normalization will be by integrated count from this "
227 "If set, normalization will be by integrated count up to "
228 "this maximum x value");
230 "If true and an integration range is set then partial bins at either \n"
231 "end of the integration range are also included");
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");
247 bool isSingleCountWorkspace =
false;
249 isSingleCountWorkspace = (!inputWS->isHistogramData()) && (inputWS->blocksize() == 1);
250 }
catch (std::length_error &) {
252 isSingleCountWorkspace =
false;
265 if (!norm_ws_name.empty()) {
267 if (out_name == norm_ws_name) {
270 norm_ws_name = norm_ws_name +
"_normFactor";
272 pProp->setValue(norm_ws_name);
287 const std::vector<std::size_t> &workspaceIndexes) {
290 childAlg->setProperty(
"WorkspaceIndexList", workspaceIndexes);
291 childAlg->executeAsChildAlg();
300 std::map<std::string, std::string> issues;
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;
314 const double intMin =
getProperty(
"IntegrationRangeMin");
315 const double intMax =
getProperty(
"IntegrationRangeMax");
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.";
324 const int monIndex =
getProperty(
"MonitorWorkspaceIndex");
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.";
331 if (monWS->getInstrument()->getName() != inWS->getInstrument()->getName()) {
332 issues[
"MonitorWorkspace"] =
"The Input and Monitor workspaces must come "
333 "from the same instrument.";
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";
354 m_scanInput = inputWorkspace->detectorInfo().isScanning();
358 throw std::runtime_error(
"Can not currently use a separate monitor "
359 "workspace with a detector scan input workspace.");
366 g_log.
information(
"Both input workspace MonitorSpectrum number and monitor "
367 "workspace are specified. Ignoring Monitor Workspace");
371 if (inWS && monIDs) {
373 "detector ID are specified. Ignoring Detector ID");
378 if (sepWS && monIDs) {
380 "specified. Ignoring Detector ID");
392 const auto &monitorSpecInfo =
m_monitor->spectrumInfo();
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.");
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.");
422 if (monitorSpec < 0) {
426 throw std::runtime_error(
"Both MonitorSpectrum and MonitorID can not be negative");
429 std::vector<detid_t> detID(1, monitorID);
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");
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.");
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.");
448 throw std::runtime_error(
"Cannot retrieve monitor spectrum - spectrum "
449 "numbers not attached to workspace");
452 if (!specs.count(monitorSpec)) {
453 throw std::runtime_error(
"Input workspace does not contain spectrum "
454 "number given for MonitorSpectrum");
458 return inputWorkspace;
467 const int wsID =
getProperty(
"MonitorWorkspaceIndex");
525 const bool isSingleCountWorkspace) {
530 if (!isSingleCountWorkspace) {
537 integrate->setProperty<
bool>(
"IncludePartialBins",
getProperty(
"IncludePartialBins"));
538 integrate->executeAsChildAlg();
539 m_monitor = integrate->getProperty(
"OutputWorkspace");
542 EventWorkspace_sptr inputEvent = std::dynamic_pointer_cast<EventWorkspace>(inputWorkspace);
550 divide->executeAsChildAlg();
553 outputWorkspace = divide->getProperty(
"OutputWorkspace");
570 if (outputWorkspace != inputWorkspace)
571 outputWorkspace = inputWorkspace->clone();
573 size_t monitorWorkspaceIndex = 0;
576 const auto &specInfo = inputWorkspace->spectrumInfo();
582 prog.
report(
"Performing normalisation");
584 size_t timeIndex = 0;
586 timeIndex = specInfo.spectrumDefinition(workspaceIndex)[0].second;
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++;
594 for (int64_t i = 0; i < int64_t(outputWorkspace->getNumberHistograms()); ++i) {
596 const auto &specDef = specInfo.spectrumDefinition(i);
601 auto hist = outputWorkspace->histogram(i);
602 auto &yValues = hist.mutableY();
603 auto &eValues = hist.mutableE();
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;
610 outputWorkspace->setHistogram(i, hist);
623 EventWorkspace_sptr inputEvent = std::dynamic_pointer_cast<EventWorkspace>(inputWorkspace);
626 if (outputWorkspace != inputWorkspace) {
628 outputWorkspace = inputWorkspace->clone();
630 outputWorkspace = create<MatrixWorkspace>(*inputWorkspace);
632 auto outputEvent = std::dynamic_pointer_cast<EventWorkspace>(outputWorkspace);
634 const auto &inputSpecInfo = inputWorkspace->spectrumInfo();
635 const auto &monitorSpecInfo =
m_monitor->spectrumInfo();
637 const auto specLength = inputWorkspace->blocksize();
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;
645 timeIndex = monitorSpecInfo.spectrumDefinition(workspaceIndex)[0].second;
651 const size_t numHists = inputWorkspace->getNumberHistograms();
653 bool hasZeroDivision =
false;
654 Progress prog(
this, 0.0, 1.0, numHists);
657 for (int64_t i = 0; i < int64_t(numHists); ++i) {
661 const auto &specDef = inputSpecInfo.spectrumDefinition(i);
665 const auto &
X = inputWorkspace->binEdges(i);
670 auto E = (
m_commonBins ? monE : CountStandardDeviations(specLength));
676 if (
X.back() == 0.0 &&
X.front() == 0.0)
681 Y.mutableRawData(), E.mutableRawData(),
false);
688 EventList &outEL = outputEvent->getSpectrum(i);
689 outEL.
divide(
X.rawData(),
Y.mutableRawData(), E.mutableRawData());
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));
699 for (
size_t k = 0; k < specLength; ++k) {
701 const double leftY = inY[k];
702 const double rightY =
Y[k];
705 hasZeroDivision =
true;
711 const double newY = leftY / rightY;
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);
728 if (hasZeroDivision) {
729 g_log.
warning() <<
"Division by zero in some of the bins.\n";
732 outputEvent->clearMRU();
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();
749 auto &yNew =
Y.mutableRawData();
750 auto &eNew = E.mutableRawData();
752 for (
size_t j = 0; j < specLength; ++j) {
753 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.
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...
std::string MonitorWorkspaceProp
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.
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.
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(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.
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.