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).");
72 return (
left <
right) && (std::abs(
left -
right) > 1 * std::numeric_limits<double>::epsilon());
88 int minWsIndex =
getProperty(
"StartWorkspaceIndex");
92 const bool incPartBins =
getProperty(
"IncludePartialBins");
94 const std::vector<double> minRanges =
getProperty(
"RangeLowerList");
96 const std::vector<double> maxRanges =
getProperty(
"RangeUpperList");
101 const auto numberOfSpectra =
static_cast<int>(localworkspace->getNumberHistograms());
104 if (minWsIndex >= numberOfSpectra) {
105 g_log.
warning(
"StartWorkspaceIndex out of range! Set to 0.");
109 maxWsIndex = numberOfSpectra - 1;
110 if (maxWsIndex > numberOfSpectra - 1 || maxWsIndex < minWsIndex) {
111 g_log.
warning(
"EndWorkspaceIndex out of range! Set to max workspace index.");
112 maxWsIndex = numberOfSpectra - 1;
114 auto rangeListCheck = [minWsIndex, maxWsIndex](
const std::vector<double> &list,
const char *
name) {
115 if (!list.empty() && list.size() !=
static_cast<size_t>(maxWsIndex - minWsIndex) + 1) {
116 std::ostringstream sout;
117 sout <<
name <<
" has " << list.size() <<
" values but it should contain " << maxWsIndex - minWsIndex + 1 <<
'\n';
118 throw std::runtime_error(sout.str());
121 rangeListCheck(minRanges,
"RangeLowerList");
122 rangeListCheck(maxRanges,
"RangeUpperList");
124 double progressStart = 0.0;
127 EventWorkspace_sptr eventInputWS = std::dynamic_pointer_cast<EventWorkspace>(localworkspace);
129 if (eventInputWS !=
nullptr) {
131 if (!minRanges.empty() || !maxRanges.empty()) {
132 throw std::runtime_error(
"Range lists not supported for EventWorkspaces.");
135 double evntMinRange =
isEmpty(minRange) ? eventInputWS->getEventXMin() : minRange;
136 double evntMaxRange =
isEmpty(maxRange) ? eventInputWS->getEventXMax() : maxRange;
142 minRange = std::numeric_limits<double>::lowest();
147 MatrixWorkspace_sptr outputWorkspace = create<Workspace2D>(*localworkspace, maxWsIndex - minWsIndex + 1, BinEdges(2));
148 auto rebinned_input = std::dynamic_pointer_cast<const RebinnedOutput>(localworkspace);
149 auto rebinned_output = std::dynamic_pointer_cast<RebinnedOutput>(outputWorkspace);
153 const bool axisIsText = localworkspace->getAxis(1)->isText();
154 const bool axisIsNumeric = localworkspace->getAxis(1)->isNumeric();
158 for (
int i = minWsIndex; i <= maxWsIndex; ++i) {
161 const int outWI = i - minWsIndex;
167 newAxis->
setLabel(outWI, localworkspace->getAxis(1)->label(i));
168 }
else if (axisIsNumeric) {
171 newAxis->
setValue(outWI, (*(localworkspace->getAxis(1)))(i));
175 auto &outSpec = outputWorkspace->getSpectrum(outWI);
177 const auto &inSpec = localworkspace->getSpectrum(i);
180 outSpec.copyInfoFrom(inSpec);
185 Fin = &rebinned_input->readF(i);
187 Fout = &rebinned_output->dataF(outWI);
189 const double lowerLimit = minRanges.empty() ? minRange : std::max(minRange, minRanges[outWI]);
190 const double upperLimit = maxRanges.empty() ? maxRange : std::min(maxRange, maxRanges[outWI]);
192 if (upperLimit < lowerLimit) {
193 std::ostringstream sout;
194 sout <<
"Upper integration limit " << upperLimit <<
" for workspace index " << i
195 <<
" smaller than the lower limit " << lowerLimit <<
". Setting integral to zero.\n";
201 integrateSpectrum(inSpec, outSpec, Fin, Fout, lowerLimit, upperLimit, incPartBins);
208 if (rebinned_output) {
209 rebinned_output->finalize(
false);
220 const std::vector<double> *Fin, std::vector<double> *Fout,
const double lowerLimit,
221 const double upperLimit,
const bool incPartBins) {
223 const auto &
X = inSpec.
x();
224 const auto &
Y = inSpec.
y();
225 const auto &E = inSpec.
e();
228 MantidVec::const_iterator lowit, highit;
234 outSpec.
dataX()[0] = lowerLimit;
235 outSpec.
dataX()[1] = upperLimit;
241 lowit = std::lower_bound(
X.begin(),
X.end(), lowerLimit,
tolerant_less());
247 highit = std::upper_bound(lowit,
X.end(), upperLimit,
tolerant_less());
251 if (lowit ==
X.end() || highit ==
X.begin())
258 auto distmin = std::distance(
X.begin(), lowit);
259 auto distmax = std::distance(
X.begin(), highit);
267 auto is_distrib = inSpec.
yMode() == HistogramData::Histogram::YMode::Frequencies;
268 if (distmax <= distmin) {
274 sumF = std::accumulate(Fin->cbegin() + distmin, Fin->cbegin() + distmax, 0.0);
276 Fnor =
static_cast<double>(
277 std::count_if(Fin->begin() + distmin, Fin->begin() + distmax, [](
double f) { return f != 0.; }));
279 Fmin = (*Fin)[distmin - 1];
280 Fmax = (*Fin)[
static_cast<std::size_t
>(distmax) < Fin->size() ? distmax : Fin->size() - 1];
285 sumY = std::accumulate(
Y.cbegin() + distmin,
Y.cbegin() + distmax, 0.0);
290 std::vector<double> widths(
X.size());
292 std::adjacent_difference(lowit, highit + 1, widths.begin());
293 sumY = std::inner_product(
Y.begin() + distmin,
Y.begin() + distmax, widths.begin() + 1, 0.0);
294 sumE = std::inner_product(E.begin() + distmin, E.begin() + distmax, widths.begin() + 1, 0.0, std::plus<double>(),
301 if ((distmax <= distmin) && (distmin > 0) && (highit <
X.end() - 1)) {
303 const double lower_bin = *lowit;
304 const double prev_bin = *(lowit - 1);
305 double fraction = (upperLimit - lowerLimit);
307 fraction /= (lower_bin - prev_bin);
309 const MantidVec::size_type val_index = distmin - 1;
310 sumY +=
Y[val_index] * fraction;
311 const double eval = E[val_index];
312 sumE += eval * eval * fraction * fraction;
314 sumF += Fmin * fraction;
320 const double lower_bin = *lowit;
321 const double prev_bin = *(lowit - 1);
322 double fraction = (lower_bin - lowerLimit);
324 fraction /= (lower_bin - prev_bin);
326 const MantidVec::size_type val_index = distmin - 1;
327 sumY +=
Y[val_index] * fraction;
328 const double eval = E[val_index];
329 sumE += eval * eval * fraction * fraction;
331 sumF += Fmin * fraction;
336 if (highit <
X.end() - 1) {
337 const double upper_bin = *highit;
338 const double next_bin = *(highit + 1);
339 double fraction = (upperLimit - upper_bin);
341 fraction /= (next_bin - upper_bin);
343 sumY +=
Y[distmax] * fraction;
344 const double eval = E[distmax];
345 sumE += eval * eval * fraction * fraction;
347 sumF += Fmax * fraction;
354 outSpec.
mutableX()[0] = lowit ==
X.end() ? *(lowit - 1) : *(lowit);
372 double minRange,
double maxRange) {
373 bool childLog =
g_log.
is(Logger::Priority::PRIO_DEBUG);
375 childAlg->setProperty(
"InputWorkspace",
workspace);
376 std::ostringstream binParams;
377 binParams << minRange <<
"," << maxRange - minRange <<
"," << maxRange;
378 childAlg->setPropertyValue(
"Params", binParams.str());
379 childAlg->setProperty(
"PreserveEvents",
false);
380 childAlg->executeAsChildAlg();
381 return childAlg->getProperty(
"OutputWorkspace");
393 if (temp->id() ==
"RebinnedOutput") {
398 std::string outName =
"_" + temp->getName() +
"_clean";
399 alg->setProperty(
"OutputWorkspace", outName);
400 alg->setProperty(
"NaNValue", 0.0);
401 alg->setProperty(
"NaNError", 0.0);
402 alg->setProperty(
"InfinityValue", 0.0);
403 alg->setProperty(
"InfinityError", 0.0);
404 alg->executeAsChildAlg();
405 temp = alg->getProperty(
"OutputWorkspace");
407 std::dynamic_pointer_cast<RebinnedOutput>(temp)->unfinalize();
411 if (!temp->isHistogramData()) {
414 std::string outName =
"_" + temp->getName() +
"_histogram";
415 alg->setProperty(
"OutputWorkspace", outName);
416 alg->executeAsChildAlg();
417 temp = alg->getProperty(
"OutputWorkspace");
418 temp->setDistribution(
true);
425 std::map<std::string, std::string> issues;
428 const std::vector<double> minRanges =
getProperty(
"RangeLowerList");
429 const std::vector<double> maxRanges =
getProperty(
"RangeUpperList");
430 if (!minRanges.empty() && !maxRanges.empty() && minRanges.size() != maxRanges.size()) {
431 issues[
"RangeLowerList"] =
"RangeLowerList has different number of values as RangeUpperList.";
434 for (
size_t i = 0; i < minRanges.size(); ++i) {
435 const auto x = minRanges[i];
436 if (!
isEmpty(maxRange) &&
x > maxRange) {
437 issues[
"RangeLowerList"] =
"RangeLowerList has a value greater than RangeUpper.";
439 }
else if (!maxRanges.empty() &&
x > maxRanges[i]) {
440 issues[
"RangeLowerList"] =
"RangeLowerList has a value greater than the "
441 "corresponding one in RangeUpperList.";
446 if (std::any_of(maxRanges.cbegin(), maxRanges.cend(), [minRange](
const auto x) { return x < minRange; })) {
447 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.