18#include "MantidHistogramData/Histogram.h"
31using namespace Kernel;
33using namespace DataObjects;
34using namespace HistogramData;
41 "The input workspace to integrate.");
43 "The output workspace with the results of the integration.");
48 auto mustBePositive = std::make_shared<BoundedValidator<int>>();
49 mustBePositive->setLower(0);
50 declareProperty(
"StartWorkspaceIndex", 0, mustBePositive,
"Index of the first spectrum to integrate.");
53 "If true then partial bins from the beginning and end of the "
54 "input range are also included in the integration.");
56 "A list of lower integration limits (as X values).");
58 "A list of upper integration limits (as X values).");
71 return (
left <
right) && (std::abs(
left -
right) > 1 * std::numeric_limits<double>::epsilon());
87 int minWsIndex =
getProperty(
"StartWorkspaceIndex");
91 const bool incPartBins =
getProperty(
"IncludePartialBins");
93 const std::vector<double> minRanges =
getProperty(
"RangeLowerList");
95 const std::vector<double> maxRanges =
getProperty(
"RangeUpperList");
100 const auto numberOfSpectra =
static_cast<int>(localworkspace->getNumberHistograms());
103 if (minWsIndex >= numberOfSpectra) {
104 g_log.
warning(
"StartWorkspaceIndex out of range! Set to 0.");
108 maxWsIndex = numberOfSpectra - 1;
109 if (maxWsIndex > numberOfSpectra - 1 || maxWsIndex < minWsIndex) {
110 g_log.
warning(
"EndWorkspaceIndex out of range! Set to max workspace index.");
111 maxWsIndex = numberOfSpectra - 1;
113 auto rangeListCheck = [minWsIndex, maxWsIndex](
const std::vector<double> &list,
const char *
name) {
114 if (!list.empty() && list.size() !=
static_cast<size_t>(maxWsIndex - minWsIndex) + 1) {
115 std::ostringstream sout;
116 sout <<
name <<
" has " << list.size() <<
" values but it should contain " << maxWsIndex - minWsIndex + 1 <<
'\n';
117 throw std::runtime_error(sout.str());
120 rangeListCheck(minRanges,
"RangeLowerList");
121 rangeListCheck(maxRanges,
"RangeUpperList");
123 double progressStart = 0.0;
126 EventWorkspace_sptr eventInputWS = std::dynamic_pointer_cast<EventWorkspace>(localworkspace);
128 if (eventInputWS !=
nullptr) {
130 if (!minRanges.empty() || !maxRanges.empty()) {
131 throw std::runtime_error(
"Range lists not supported for EventWorkspaces.");
134 double evntMinRange =
isEmpty(minRange) ? eventInputWS->getEventXMin() : minRange;
135 double evntMaxRange =
isEmpty(maxRange) ? eventInputWS->getEventXMax() : maxRange;
141 minRange = std::numeric_limits<double>::lowest();
146 MatrixWorkspace_sptr outputWorkspace = create<Workspace2D>(*localworkspace, maxWsIndex - minWsIndex + 1, BinEdges(2));
147 auto rebinned_input = std::dynamic_pointer_cast<const RebinnedOutput>(localworkspace);
148 auto rebinned_output = std::dynamic_pointer_cast<RebinnedOutput>(outputWorkspace);
152 const bool axisIsText = localworkspace->getAxis(1)->isText();
153 const bool axisIsNumeric = localworkspace->getAxis(1)->isNumeric();
157 for (
int i = minWsIndex; i <= maxWsIndex; ++i) {
160 const int outWI = i - minWsIndex;
166 newAxis->
setLabel(outWI, localworkspace->getAxis(1)->label(i));
167 }
else if (axisIsNumeric) {
170 newAxis->
setValue(outWI, (*(localworkspace->getAxis(1)))(i));
174 auto &outSpec = outputWorkspace->getSpectrum(outWI);
176 const auto &inSpec = localworkspace->getSpectrum(i);
179 outSpec.copyInfoFrom(inSpec);
184 Fin = &rebinned_input->readF(i);
186 Fout = &rebinned_output->dataF(outWI);
188 const double lowerLimit = minRanges.empty() ? minRange : std::max(minRange, minRanges[outWI]);
189 const double upperLimit = maxRanges.empty() ? maxRange : std::min(maxRange, maxRanges[outWI]);
191 if (upperLimit < lowerLimit) {
192 std::ostringstream sout;
193 sout <<
"Upper integration limit " << upperLimit <<
" for workspace index " << i
194 <<
" smaller than the lower limit " << lowerLimit <<
". Setting integral to zero.\n";
200 integrateSpectrum(inSpec, outSpec, Fin, Fout, lowerLimit, upperLimit, incPartBins);
207 if (rebinned_output) {
208 rebinned_output->finalize(
false);
219 const std::vector<double> *Fin, std::vector<double> *Fout,
const double lowerLimit,
220 const double upperLimit,
const bool incPartBins) {
222 const auto &
X = inSpec.
x();
223 const auto &
Y = inSpec.
y();
224 const auto &E = inSpec.
e();
227 MantidVec::const_iterator lowit, highit;
233 outSpec.
dataX()[0] = lowerLimit;
234 outSpec.
dataX()[1] = upperLimit;
240 lowit = std::lower_bound(
X.begin(),
X.end(), lowerLimit,
tolerant_less());
246 highit = std::upper_bound(lowit,
X.end(), upperLimit,
tolerant_less());
250 if (lowit ==
X.end() || highit ==
X.begin())
257 auto distmin = std::distance(
X.begin(), lowit);
258 auto distmax = std::distance(
X.begin(), highit);
266 auto is_distrib = inSpec.
yMode() == HistogramData::Histogram::YMode::Frequencies;
267 if (distmax <= distmin) {
273 sumF = std::accumulate(Fin->begin() + distmin, Fin->begin() + distmax, 0.0);
275 Fnor =
static_cast<double>(
276 std::count_if(Fin->begin() + distmin, Fin->begin() + distmax, [](
double f) { return f != 0.; }));
278 Fmin = (*Fin)[distmin - 1];
279 Fmax = (*Fin)[
static_cast<std::size_t
>(distmax) < Fin->size() ? distmax : Fin->size() - 1];
284 sumY = std::accumulate(
Y.begin() + distmin,
Y.begin() + distmax, 0.0);
289 std::vector<double> widths(
X.size());
291 std::adjacent_difference(lowit, highit + 1, widths.begin());
292 sumY = std::inner_product(
Y.begin() + distmin,
Y.begin() + distmax, widths.begin() + 1, 0.0);
293 sumE = std::inner_product(E.begin() + distmin, E.begin() + distmax, widths.begin() + 1, 0.0, std::plus<double>(),
300 if ((distmax <= distmin) && (distmin > 0) && (highit <
X.end() - 1)) {
302 const double lower_bin = *lowit;
303 const double prev_bin = *(lowit - 1);
304 double fraction = (upperLimit - lowerLimit);
306 fraction /= (lower_bin - prev_bin);
308 const MantidVec::size_type val_index = distmin - 1;
309 sumY +=
Y[val_index] * fraction;
310 const double eval = E[val_index];
311 sumE += eval * eval * fraction * fraction;
313 sumF += Fmin * fraction;
319 const double lower_bin = *lowit;
320 const double prev_bin = *(lowit - 1);
321 double fraction = (lower_bin - lowerLimit);
323 fraction /= (lower_bin - prev_bin);
325 const MantidVec::size_type val_index = distmin - 1;
326 sumY +=
Y[val_index] * fraction;
327 const double eval = E[val_index];
328 sumE += eval * eval * fraction * fraction;
330 sumF += Fmin * fraction;
335 if (highit <
X.end() - 1) {
336 const double upper_bin = *highit;
337 const double next_bin = *(highit + 1);
338 double fraction = (upperLimit - upper_bin);
340 fraction /= (next_bin - upper_bin);
342 sumY +=
Y[distmax] * fraction;
343 const double eval = E[distmax];
344 sumE += eval * eval * fraction * fraction;
346 sumF += Fmax * fraction;
353 outSpec.
mutableX()[0] = lowit ==
X.end() ? *(lowit - 1) : *(lowit);
360 (*Fout)[0] = sumF / Fnor;
368 double minRange,
double maxRange) {
369 bool childLog =
g_log.
is(Logger::Priority::PRIO_DEBUG);
371 childAlg->setProperty(
"InputWorkspace",
workspace);
372 std::ostringstream binParams;
373 binParams << minRange <<
"," << maxRange - minRange <<
"," << maxRange;
374 childAlg->setPropertyValue(
"Params", binParams.str());
375 childAlg->setProperty(
"PreserveEvents",
false);
376 childAlg->executeAsChildAlg();
377 return childAlg->getProperty(
"OutputWorkspace");
389 if (temp->id() ==
"RebinnedOutput") {
394 std::string outName =
"_" + temp->getName() +
"_clean";
395 alg->setProperty(
"OutputWorkspace", outName);
396 alg->setProperty(
"NaNValue", 0.0);
397 alg->setProperty(
"NaNError", 0.0);
398 alg->setProperty(
"InfinityValue", 0.0);
399 alg->setProperty(
"InfinityError", 0.0);
400 alg->executeAsChildAlg();
401 temp = alg->getProperty(
"OutputWorkspace");
403 std::dynamic_pointer_cast<RebinnedOutput>(temp)->unfinalize();
407 if (!temp->isHistogramData()) {
410 std::string outName =
"_" + temp->getName() +
"_histogram";
411 alg->setProperty(
"OutputWorkspace", outName);
412 alg->executeAsChildAlg();
413 temp = alg->getProperty(
"OutputWorkspace");
414 temp->setDistribution(
true);
421 std::map<std::string, std::string> issues;
424 const std::vector<double> minRanges =
getProperty(
"RangeLowerList");
425 const std::vector<double> maxRanges =
getProperty(
"RangeUpperList");
426 if (!minRanges.empty() && !maxRanges.empty() && minRanges.size() != maxRanges.size()) {
427 issues[
"RangeLowerList"] =
"RangeLowerList has different number of values as RangeUpperList.";
430 for (
size_t i = 0; i < minRanges.size(); ++i) {
431 const auto x = minRanges[i];
432 if (!
isEmpty(maxRange) &&
x > maxRange) {
433 issues[
"RangeLowerList"] =
"RangeLowerList has a value greater than RangeUpper.";
435 }
else if (!maxRanges.empty() &&
x > maxRanges[i]) {
436 issues[
"RangeLowerList"] =
"RangeLowerList has a value greater than the "
437 "corresponding one in RangeUpperList.";
442 if (std::any_of(maxRanges.cbegin(), maxRanges.cend(), [minRange](
const auto x) { return x < minRange; })) {
443 issues[
"RangeUpperList"] =
"RangeUpperList has a value lower than RangeLower.";
#define DECLARE_ALGORITHM(classname)
IPeaksWorkspace_sptr workspace
#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.
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
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.
A "spectrum" is an object that holds the data for a particular spectrum, in particular:
HistogramData::Histogram::YMode yMode() const
HistogramData::HistogramY & mutableY() &
const HistogramData::HistogramX & x() const
virtual const HistogramData::HistogramE & e() const
virtual const HistogramData::HistogramY & y() const
HistogramData::HistogramX & mutableX() &
HistogramData::HistogramE & mutableE() &
virtual MantidVec & dataX()=0
Class to represent a numeric axis of a workspace.
void setValue(const std::size_t &index, const double &value) override
Set the value at a specific index.
Helper class for reporting progress from algorithms.
Class to represent a text axis of a workspace.
void setLabel(const std::size_t &index, const std::string &lbl)
Set the label at the given index.
A property class for workspaces.
std::map< std::string, std::string > validateInputs() override
Method checking errors on ALL the inputs, before execution.
void init() override
Initialisation method.
void integrateSpectrum(const API::ISpectrum &inSpec, API::ISpectrum &outSpec, const std::vector< double > *Fin, std::vector< double > *Fout, double lowerLimit, double upperLimit, bool incPartBins)
Integrate a single spectrum between the supplied limits.
API::MatrixWorkspace_sptr getInputWorkspace()
Get the input workspace.
void exec() override
Executes the algorithm.
API::MatrixWorkspace_sptr rangeFilterEventWorkspace(const API::MatrixWorkspace_sptr &workspace, double minRange, double maxRange)
Uses rebin to reduce event workspaces to a single bin histogram.
const std::string name() const override
Algorithm's name for identification overriding a virtual method.
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 warning(const std::string &msg)
Logs at warning level.
bool is(int level) const
Returns true if at least the given log level is set.
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::shared_ptr< EventWorkspace > EventWorkspace_sptr
shared pointer to the EventWorkspace class
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 int EMPTY_INT() noexcept
Returns what we consider an "empty" integer within a property.
std::vector< double > MantidVec
typedef for the data storage used in Mantid matrix workspaces
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Std-style comparision function object (satisfies the requirements of Compare)
bool operator()(const double &left, const double &right) const
@ Input
An input workspace.
@ Output
An output workspace.
Functor to accumulate a sum of squares.
Functor giving the product of the squares of the arguments.