13#include "MantidHistogramData/Histogram.h"
19#include <gsl/gsl_errno.h>
21#include <boost/lexical_cast.hpp>
29using namespace Kernel;
31using namespace HistogramData;
32using namespace DataObjects;
39 "Workspace containing the input data");
41 "The name to give the output workspace");
44 "A comma separated list of first bin boundary, width, last bin boundary. "
46 "this can be followed by a comma and more widths and last boundary "
48 "Optionally this can also be a single number, which is the bin width. "
49 "In this case, the boundary of binning will be determined by minimum and "
51 "values among all events, or previous binning boundary, in case of event "
53 "non-event Workspace, respectively. Negative width values indicate "
54 "logarithmic binning. ");
63 std::map<std::string, std::string> helpMessages;
67 std::vector<double> rbParams =
getProperty(
"Params");
70 }
catch (std::exception &err) {
71 helpMessages[
"Params"] = err.what();
86 HistogramData::BinEdges XValues_new(0);
90 const auto nHists =
static_cast<int>(inputW->getNumberHistograms());
94 if (inputW->axes() > 1)
95 outputW->replaceAxis(1, std::unique_ptr<Axis>(inputW->getAxis(1)->clone(outputW.get())));
96 outputW->setDistribution(
true);
101 if (!inputW->isDistribution()) {
102 g_log.
debug() <<
"Converting the input workspace to a distribution\n";
110 }
catch (std::exception &) {
121 g_log.
debug() <<
"Converting the input and output workspaces _from_ distributions\n";
127 outputW->setDistribution(
false);
133 for (
int i = 0; i < nHists; ++i) {
134 if (inputW->hasMaskedBins(i))
140 for (
int i = 0; i < outputW->axes(); ++i) {
141 outputW->getAxis(i)->unit() = inputW->getAxis(i)->unit();
154 const HistogramData::BinEdges &XValues_new,
156 g_log.
debug() <<
"Preparing to calculate y-values using splines and estimate errors\n";
159 gsl_error_handler_t *old_handler = gsl_set_error_handler(
nullptr);
161 const auto histnumber =
static_cast<int>(inputW->getNumberHistograms());
162 Progress prog(
this, 0.0, 1.0, histnumber);
163 for (
int hist = 0; hist < histnumber; ++hist) {
167 outputW->setHistogram(hist,
cubicInterpolation(inputW->histogram(hist), XValues_new));
168 }
catch (std::exception &ex) {
169 g_log.
error() <<
"Error in rebin function: " << ex.what() <<
'\n';
174 outputW->setBinEdges(hist, XValues_new);
179 gsl_set_error_handler(old_handler);
209 const auto &yOld = oldHistogram.y();
211 const size_t size_old = yOld.size();
213 throw std::runtime_error(
"Empty spectrum found, aborting!");
215 const size_t size_new = xNew.size() - 1;
218 auto xCensOld = oldHistogram.points();
221 Points xCensNew(size_new);
226 size_t oldIn1 = std::lower_bound(xCensOld.begin(), xCensOld.end(), xCensNew.front()) - xCensOld.begin();
229 if (std::abs(xCensOld.front() - xCensNew.front()) < 1e-8 * (xCensOld.back() - xCensOld.front())) {
232 xCensNew.mutableRawData().front() = xCensOld.front();
236 size_t oldIn2 = std::lower_bound(xCensOld.begin(), xCensOld.end(), xCensNew.back()) - xCensOld.begin();
237 if (oldIn2 == size_old) {
240 if (std::abs(xCensOld.back() - xCensNew.back()) < 1e-8 * (xCensOld.back() - xCensOld.front())) {
241 oldIn2 = size_old - 1;
243 xCensNew.mutableRawData().back() = xCensOld.back();
249 bool goodRangeLow(
false), goodRangeHigh(
false), canInterpol(
false);
262 if (oldIn2 < size_old - 1) {
264 goodRangeHigh =
true;
266 if (oldIn2 >= size_old) {
271 const auto &xOld = oldHistogram.x();
272 const auto &eOld = oldHistogram.e();
283 throw std::invalid_argument(std::string(
"At least one x-value to interpolate to is outside the "
284 "range of the original data.\n") +
285 "original data range: " + boost::lexical_cast<std::string>(xOld.front()) +
" to " +
286 boost::lexical_cast<std::string>(xOld.back()) +
"\n" +
287 "range to try to interpolate to " + boost::lexical_cast<std::string>(xNew.front()) +
288 " to " + boost::lexical_cast<std::string>(xNew.back()));
294 Histogram newHistogram{xNew, Frequencies(xNew.size() - 1)};
296 auto &yNew = newHistogram.mutableY();
297 auto &eNew = newHistogram.mutableE();
299 if ((!goodRangeLow) || (!goodRangeHigh)) {
301 "the boundary of the input data, these points will "
302 "have slightly less accuracy\n";
306 const size_t nPoints = oldIn2 - oldIn1 + 1;
307 std::span<double const> xSpan(xCensOld.cbegin() + oldIn1, nPoints);
308 std::span<double const> ySpan(yOld.cbegin() + oldIn1, nPoints);
309 std::span<double const> xNewSpan(xCensNew.cbegin(), xCensNew.cend());
311 std::transform(xCensNew.cbegin(), xCensNew.cend(), eNew.begin(),
312 [
this, &xCensOld, &eOld](
double x) { return this->estimateError(xCensOld, eOld, x); });
325 Histogram newHistogram{xNew, Frequencies(xNew.size() - 1)};
326 auto &yNew = newHistogram.mutableY();
327 auto &eNew = newHistogram.mutableE();
329 yNew.assign(yNew.size(), oldHistogram.y().front());
331 const auto &xPointData = oldHistogram.points();
332 const auto &eOld = oldHistogram.e();
335 std::transform(xNew.cbegin(), xNew.cend() - 1, eNew.begin(),
336 [&](
double x) { return estimateError(xPointData, eOld, x); });
356 const size_t indAbove = std::lower_bound(xsOld.begin(), xsOld.end(), xNew) - xsOld.begin();
361 return esOld.front();
364 if (indAbove >= esOld.size()) {
369 const double error1 = esOld[indAbove];
372 double weight1 = xsOld[indAbove] - xNew;
375 if (weight1 < 1e-100) {
380 weight1 = 1 / weight1;
384 const double error2 = esOld[indAbove - 1];
385 double weight2 = xNew - xsOld[indAbove - 1];
386 if (weight2 < 1e-100) {
391 weight2 = 1 / weight2;
393 return (weight1 * error1 + weight2 * error2) / (weight1 + weight2);
#define DECLARE_ALGORITHM(classname)
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.
Helper class for reporting progress from algorithms.
A property class for workspaces.
void outputYandEValues(const API::MatrixWorkspace_const_sptr &inputW, const HistogramData::BinEdges &XValues_new, const API::MatrixWorkspace_sptr &outputW)
Calls the interpolation function for each histogram in the workspace.
void exec() override
Executes the rebin algorithm.
HistogramData::Histogram noInterpolation(const HistogramData::Histogram &oldHistogram, const HistogramData::BinEdges &xNew) const
This can be used whenever the original spectrum is filled with only one value.
std::map< std::string, std::string > validateInputs() override
Overwrites the parent (Rebin) validateInputs Avoids all bother about binning modes and powers.
double estimateError(const HistogramData::Points &xsOld, const HistogramData::HistogramE &esOld, const double xNew) const
Estimates the error on each interpolated point by assuming it is similar to the errors in near by inp...
HistogramData::Histogram cubicInterpolation(const HistogramData::Histogram &oldHistogram, const HistogramData::BinEdges &xNew) const
Uses cubic splines to interpolate the mean rate of change of the integral over the inputed data bins ...
void init() override
Overwrites the parent (Rebin) init method These properties will be declares instead.
void propagateMasks(const API::MatrixWorkspace_const_sptr &inputWS, const API::MatrixWorkspace_sptr &outputWS, const int hist, const bool IgnoreBinErrors=false)
Takes the masks in the input workspace and apportions the weights into the new bins that overlap with...
static std::vector< double > rebinParamsFromInput(const std::vector< double > &inParams, const API::MatrixWorkspace &inputWS, Kernel::Logger &logger, const std::string &binModeName="Default")
Return the rebin parameters from a user input.
Support for a property that holds an array of values.
static std::vector< Y > getSplinedYValues(std::span< X const > newX, std::span< X const > x, std::span< Y const > y)
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void debug(const std::string &msg)
Logs at debug level.
void error(const std::string &msg)
Logs at error 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.
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
Kernel::Logger g_log("DetermineSpinStateOrder")
void MANTID_KERNEL_DLL convertToBinCentre(const std::vector< double > &bin_edges, std::vector< double > &bin_centres)
Convert an array of bin boundaries to bin center values.
bool MANTID_KERNEL_DLL isConstantValue(const std::vector< double > &arra)
Assess if all the values in the vector are equal or if there are some different values.
int MANTID_KERNEL_DLL createAxisFromRebinParams(const std::vector< double > ¶ms, std::vector< double > &xnew, const bool resize_xnew=true, const bool full_bins_only=false, const double xMinHint=std::nan(""), const double xMaxHint=std::nan(""), const bool useReverseLogarithmic=false, const double power=-1)
Creates a new output X array given a 'standard' set of rebinning parameters.
static void makeDistribution(const MatrixWorkspace_sptr &workspace, const bool forwards=true)
Divides the data in a workspace by the bin width to make it a distribution.
@ Input
An input workspace.
@ Output
An output workspace.