28using namespace Kernel;
30using namespace DataObjects;
40bool validateSingleMatrixWorkspace(std::map<std::string, std::string> &validationOutput,
const MatrixWorkspace &ws,
41 const int minIndex,
const int maxIndex,
const std::vector<int> &indices) {
43 const auto numSpectra =
static_cast<int>(ws.getNumberHistograms());
45 if (minIndex >= numSpectra) {
46 validationOutput[
"StartWorkspaceIndex"] =
"Selected minimum workspace index is greater than available "
53 if (maxIndex >= numSpectra) {
54 validationOutput[
"EndWorkspaceIndex"] =
"Selected maximum workspace index is greater than available "
61 if (std::any_of(indices.cbegin(), indices.cend(),
62 [numSpectra](
const auto index) { return (index >= numSpectra) || (index < 0); })) {
63 validationOutput[
"ListOfWorkspaceIndices"] =
"One or more indices out of range of available spectra.";
76void validateWorkspaceName(std::map<std::string, std::string> &validationOutput,
const std::string &name,
77 const int minIndex,
const int maxIndex,
const std::vector<int> &indices) {
79 if (!ads.doesExist(name))
81 auto wsGroup = ads.retrieveWS<WorkspaceGroup>(name);
85 for (
const auto &item : *wsGroup) {
86 auto matrixWs = std::dynamic_pointer_cast<MatrixWorkspace>(item);
88 validationOutput[
"InputWorkspace"] =
"Input group contains an invalid workspace type at item " +
92 if (!validateSingleMatrixWorkspace(validationOutput, *matrixWs, minIndex, maxIndex, indices)) {
105 std::make_shared<CommonBinsValidator>()),
106 "The workspace containing the spectra to be summed.");
108 "The name of the workspace to be created as the output of the algorithm. "
109 " A workspace of this name will be created and stored in the Analysis "
112 auto mustBePositive = std::make_shared<BoundedValidator<int>>();
113 mustBePositive->setLower(0);
114 declareProperty(
"StartWorkspaceIndex", 0, mustBePositive,
"The first Workspace index to be included in the summing");
116 "The last Workspace index to be included in the summing");
119 "A list of workspace indices as a string with ranges, for "
120 "example: 5-10,15,20-23. \n"
121 "Optional: if not specified, then the "
122 "Start/EndWorkspaceIndex fields are used alone. "
123 "If specified, the range and the list are combined (without "
124 "duplicating indices). For example, a range of 10 to 20 and "
125 "a list '12,15,26,28' gives '10-20,26,28'.");
127 declareProperty(
"IncludeMonitors",
true,
"Whether to include monitor spectra in the summation.");
130 "Instead of the usual spectra sum, calculate the weighted "
131 "sum. This has the form: \n"
133 "\\times\\Sigma(Signal_i/Error_i^2)/\\Sigma(1/Error_i^2)`\n "
134 "This property is ignored for event workspace.\n"
135 "The sums are defined for :math:`Error_i != 0` only, so the "
136 "values with zero error are dropped from the summation. To "
137 "estimate the number of dropped values see the "
141 "If enabled floating point special values such as NaN or Inf"
142 " are removed before the spectra are summed.");
145 "For unnormalized data one should multiply the weighted sum "
146 "by the number of spectra contributing to the bin.");
150 "Normalize the output workspace to the fractional area for "
151 "RebinnedOutput workspaces.");
161 std::map<std::string, std::string> validationOutput;
164 const int minIndex =
getProperty(
"StartWorkspaceIndex");
165 const int maxIndex =
getProperty(
"EndWorkspaceIndex");
166 if (minIndex > maxIndex) {
167 validationOutput[
"StartWorkspaceIndex"] =
"Selected minimum workspace "
168 "index is greater than selected "
169 "maximum workspace index.";
170 validationOutput[
"EndWorkspaceIndex"] =
"Selected maximum workspace index "
171 "is lower than selected minimum "
174 const std::vector<int> indices =
getProperty(
"ListOfWorkspaceIndices");
176 validateSingleMatrixWorkspace(validationOutput, *singleWs, minIndex, maxIndex, indices);
178 validateWorkspaceName(validationOutput,
getPropertyValue(
"InputWorkspace"), minIndex, maxIndex, indices);
181 return validationOutput;
207 size_t numSpectra(0);
220 outputWorkspace = create<EventWorkspace>(*eventW, 1, eventW->binEdges(0));
231 auto &outSpec = outputWorkspace->getSpectrum(0);
234 outSpec.setSharedX(localworkspace->sharedX(0));
238 outSpec.clearDetectorIDs();
240 if (localworkspace->id() ==
"RebinnedOutput") {
251 auto &YError = outSpec.mutableE();
252 std::transform(YError.begin(), YError.end(), YError.begin(), (double (*)(
double))std::sqrt);
256 outputWorkspace->mutableRun().addProperty(
"NumAllSpectra",
int(numSpectra),
"",
true);
257 outputWorkspace->mutableRun().addProperty(
"NumMaskSpectra",
int(numMasked),
"",
true);
258 outputWorkspace->mutableRun().addProperty(
"NumZeroSpectra",
int(numZeros),
"",
true);
269 const std::vector<int> indices_list =
getProperty(
"ListOfWorkspaceIndices");
270 m_indices.insert(indices_list.begin(), indices_list.end());
278 maxIndex =
static_cast<int>(numberOfSpectra - 1);
283 for (
int i = minIndex; i <= maxIndex; i++)
284 m_indices.insert(
static_cast<size_t>(i));
299 size_t totalSpec = localworkspace->getNumberHistograms();
303 if (
index < totalSpec) {
304 temp = localworkspace->getSpectrum(
index).getSpectrumNo();
329 std::string outName =
"_" + wksp->getName() +
"_clean";
330 alg->setProperty(
"OutputWorkspace", outName);
331 alg->setProperty(
"NaNValue", 0.0);
332 alg->setProperty(
"NaNError", 0.0);
333 alg->setProperty(
"InfinityValue", 0.0);
334 alg->setProperty(
"InfinityError", 0.0);
335 alg->executeAsChildAlg();
336 return alg->getProperty(
"OutputWorkspace");
342size_t applyWeight(
const size_t numSpectra, HistogramData::HistogramY &
y, std::vector<double> &weights,
343 const std::vector<size_t> &nZeros,
const bool multiplyByNumSpec) {
345 if (multiplyByNumSpec) {
346 std::transform(weights.begin(), weights.end(), nZeros.begin(), weights.begin(),
347 [numSpectra](
const double weight,
const size_t nzero) {
348 if (numSpectra > nzero) {
349 return static_cast<double>(numSpectra - nzero) / weight;
355 std::transform(weights.begin(), weights.end(), nZeros.begin(), weights.begin(),
356 [numSpectra](
const double weight,
const size_t nzero) {
357 if (numSpectra > nzero) {
369 return std::accumulate(nZeros.begin(), nZeros.end(),
size_t(0));
374bool useSpectrum(
const SpectrumInfo &spectrumInfo,
const size_t wsIndex,
const bool keepMonitors,
size_t &numMasked) {
375 if (spectrumInfo.hasDetectors(wsIndex)) {
377 if (!keepMonitors && spectrumInfo.isMonitor(wsIndex))
380 if (spectrumInfo.isMasked(wsIndex)) {
400 size_t &numMasked,
size_t &numZeros) {
402 auto localworkspace = replaceSpecialValues();
405 auto &outSpec = outputWorkspace->getSpectrum(0);
406 auto &YSum = outSpec.mutableY();
407 auto &YErrorSum = outSpec.mutableE();
409 std::vector<double> Weight;
410 std::vector<size_t> nZeros;
411 if (m_calculateWeightedSum) {
412 Weight.assign(YSum.size(), 0.);
413 nZeros.assign(YSum.size(), 0);
416 const auto &spectrumInfo = localworkspace->spectrumInfo();
418 for (
const auto wsIndex : m_indices) {
419 if (!useSpectrum(spectrumInfo, wsIndex, m_keepMonitors, numMasked))
423 const auto &YValues = localworkspace->y(wsIndex);
424 const auto &YErrors = localworkspace->e(wsIndex);
426 if (m_calculateWeightedSum) {
428 for (
size_t yIndex = 0; yIndex < m_yLength; ++yIndex) {
429 const double yErrorsVal = YErrors[yIndex];
430 if (std::isnormal(yErrorsVal)) {
431 const double errsq = yErrorsVal * yErrorsVal;
432 YErrorSum[yIndex] += errsq;
433 Weight[yIndex] += 1. / errsq;
434 YSum[yIndex] += YValues[yIndex] / errsq;
441 std::transform(YErrorSum.begin(), YErrorSum.end(), YErrors.begin(), YErrorSum.begin(),
442 [](
const double accum,
const double yerrorSpec) { return accum + yerrorSpec * yerrorSpec; });
446 outSpec.addDetectorIDs(localworkspace->getSpectrum(wsIndex).getDetectorIDs());
451 if (m_calculateWeightedSum) {
452 numZeros = applyWeight(numSpectra, YSum, Weight, nZeros, m_multiplyByNumSpec);
469 size_t &numMasked,
size_t &numZeros) {
473 auto localworkspace = replaceSpecialValues();
481 auto isFinalized = inWS->isFinalized();
484 auto &outSpec = outputWorkspace->getSpectrum(0);
485 auto &YSum = outSpec.mutableY();
486 auto &YErrorSum = outSpec.mutableE();
487 auto &FracSum = outWS->dataF(0);
489 std::vector<double> Weight;
490 std::vector<size_t> nZeros;
491 if (m_calculateWeightedSum) {
492 Weight.assign(YSum.size(), 0);
493 nZeros.assign(YSum.size(), 0);
496 const auto &spectrumInfo = localworkspace->spectrumInfo();
498 for (
const auto wsIndex : m_indices) {
499 if (!useSpectrum(spectrumInfo, wsIndex, m_keepMonitors, numMasked))
504 const auto &YValues = localworkspace->y(wsIndex);
505 const auto &YErrors = localworkspace->e(wsIndex);
506 const auto &FracArea = inWS->readF(wsIndex);
508 if (m_calculateWeightedSum) {
509 for (
size_t yIndex = 0; yIndex < m_yLength; ++yIndex) {
510 const double yErrorsVal = YErrors[yIndex];
511 const double fracVal = (isFinalized ? FracArea[yIndex] : 1.0);
512 if (std::isnormal(yErrorsVal)) {
513 const double errsq = yErrorsVal * yErrorsVal * fracVal * fracVal;
514 YErrorSum[yIndex] += errsq;
515 Weight[yIndex] += 1. / errsq;
516 YSum[yIndex] += YValues[yIndex] * fracVal / errsq;
522 for (
size_t yIndex = 0; yIndex < m_yLength; ++yIndex) {
523 const double fracVal = (isFinalized ? FracArea[yIndex] : 1.0);
524 YSum[yIndex] += YValues[yIndex] * fracVal;
525 YErrorSum[yIndex] += YErrors[yIndex] * YErrors[yIndex] * fracVal * fracVal;
529 std::transform(FracSum.begin(), FracSum.end(), FracArea.begin(), FracSum.begin(), std::plus<double>());
532 outSpec.addDetectorIDs(localworkspace->getSpectrum(wsIndex).getDetectorIDs());
537 if (m_calculateWeightedSum) {
538 numZeros = applyWeight(numSpectra, YSum, Weight, nZeros, m_multiplyByNumSpec);
544 auto useFractionalArea = getProperty(
"UseFractionalArea");
545 if (useFractionalArea) {
560 size_t &numMasked,
size_t &numZeros) {
565 EventWorkspace_sptr outputEventWorkspace = std::dynamic_pointer_cast<EventWorkspace>(outputWorkspace);
566 EventList &outputEL = outputEventWorkspace->getSpectrum(0);
570 const auto &spectrumInfo = inputWorkspace->spectrumInfo();
572 for (
const auto i : m_indices) {
573 if (spectrumInfo.hasDetectors(i)) {
575 if (!m_keepMonitors && spectrumInfo.isMonitor(i))
578 if (spectrumInfo.isMasked(i)) {
586 const EventList &inputEL = inputWorkspace->getSpectrum(i);
587 if (inputEL.
empty()) {
#define DECLARE_ALGORITHM(classname)
std::map< DeltaEMode::Type, std::string > index
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
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.
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
static bool isEmpty(const NumT toCheck)
checks that the value was not set by users, uses the value in empty double/int.
void clearDetectorIDs()
Clear the detector IDs set.
void setSpectrumNo(specnum_t num)
Sets the the spectrum number of this spectrum.
Helper class for reporting progress from algorithms.
A property class for workspaces.
size_t m_yLength
Blocksize of the input workspace.
bool m_keepMonitors
Set true to keep monitors.
void execEvent(const API::MatrixWorkspace_sptr &outputWorkspace, API::Progress &progress, size_t &numSpectra, size_t &numMasked, size_t &numZeros)
Executes the algorithm.
void exec() override
Executes the algorithm.
std::map< std::string, std::string > validateInputs() override
Cross-input validation.
void determineIndices(const size_t numberOfSpectra)
bool m_replaceSpecialValues
Set true to remove special values before processing.
void doFractionalSum(const API::MatrixWorkspace_sptr &outputWorkspace, API::Progress &progress, size_t &numSpectra, size_t &numMasked, size_t &numZeros)
Handle logic for RebinnedOutput workspaces.
specnum_t m_outSpecNum
The output spectrum number.
specnum_t getOutputSpecNo(const API::MatrixWorkspace_const_sptr &localworkspace)
Determine the minimum spectrum No for summing.
bool m_calculateWeightedSum
void init() override
Initialisation method.
API::MatrixWorkspace_sptr replaceSpecialValues()
Calls an algorithm to replace special values within the workspace such as NaN or Inf to 0.
size_t m_numberOfSpectra
numberOfSpectra in the input
std::set< size_t > m_indices
Set of indices to sum.
void doSimpleSum(const API::MatrixWorkspace_sptr &outputWorkspace, API::Progress &progress, size_t &numSpectra, size_t &numMasked, size_t &numZeros)
Handle logic for Workspace2D workspaces.
bool empty() const
Much like stl containers, returns true if there is nothing in the event list.
Support for a property that holds an array of values.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void setPropertySettings(const std::string &name, std::unique_ptr< IPropertySettings > settings)
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.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::shared_ptr< const EventWorkspace > EventWorkspace_const_sptr
shared pointer to a const Workspace2D
std::shared_ptr< RebinnedOutput > RebinnedOutput_sptr
shared pointer to the RebinnedOutput class
std::shared_ptr< EventWorkspace > EventWorkspace_sptr
shared pointer to the EventWorkspace class
constexpr int EMPTY_INT() noexcept
Returns what we consider an "empty" integer within a property.
int32_t specnum_t
Typedef for a spectrum Number.
std::string to_string(const wide_integer< Bits, Signed > &n)
@ Input
An input workspace.
@ Output
An output workspace.