12#include <boost/algorithm/string.hpp>
35 const bool resize_xnew,
const bool full_bins_only,
const double xMinHint,
36 const double xMaxHint,
const bool useReverseLogarithmic,
const double power) {
37 std::vector<double>
tmp;
38 const std::vector<double> &fullParams = [¶ms, &
tmp, xMinHint, xMaxHint]() {
39 if (params.size() == 1) {
40 if (std::isnan(xMinHint) || std::isnan(xMaxHint)) {
41 throw std::runtime_error(
"createAxisFromRebinParams: xMinHint and "
42 "xMaxHint must be supplied if params "
43 "contains only the bin width.");
46 tmp = {xMinHint, params.front(), xMaxHint};
51 int ibound(2), istep(1), inew(1);
53 auto ibounds =
static_cast<int>(fullParams.size());
54 int isteps = ibounds - 1;
58 double lastBinCoef(0.25);
66 double xcurr = fullParams[0];
70 xnew.emplace_back(xcurr);
74 bool isPower = power > 0 && power <= 1;
76 while ((ibound <= ibounds) && (istep <= isteps)) {
78 bool isLogBin = (fullParams[istep] < 0.0);
79 bool isReverseLogBin = isLogBin && useReverseLogarithmic;
80 double alpha = std::fabs(fullParams[istep]);
82 if (isReverseLogBin && xcurr == fullParams[ibound - 2]) {
84 xcurr = fullParams[ibound];
88 xs = fullParams[istep];
90 if (useReverseLogarithmic) {
93 double x0 = fullParams[ibound - 2];
94 double step = x0 + fullParams[ibound] - xcurr;
99 xs = xcurr *
fabs(fullParams[istep]);
102 xs = fullParams[istep] * std::pow(currDiv, -power);
106 if (
fabs(xs) == 0.0) {
108 throw std::runtime_error(
"Invalid binning step provided! Can't create binning axis.");
109 }
else if (!std::isfinite(xs)) {
110 throw std::runtime_error(
"An infinite or NaN value was found in the binning parameters.");
113 if ((!isReverseLogBin && xcurr + xs * (1.0 + lastBinCoef) <= fullParams[ibound]) ||
114 (isReverseLogBin && xcurr + 2 * xs >= fullParams[ibound - 2])) {
120 if (!isReverseLogBin) {
127 xcurr = fullParams[ibound];
131 xcurr = fullParams[ibound];
137 xnew.emplace_back(xcurr);
140 std::sort(xnew.begin(), xnew.end());
163void rebin(
const std::vector<double> &xold,
const std::vector<double> &yold,
const std::vector<double> &eold,
164 const std::vector<double> &xnew, std::vector<double> &ynew, std::vector<double> &enew,
bool distribution,
167 const size_t size_xold = xold.size();
168 if (size_xold != (yold.size() + 1) || size_xold != (eold.size() + 1))
169 throw std::runtime_error(
"rebin: old y and error vectors should be of same "
170 "size & 1 shorter than x");
171 const size_t size_xnew = xnew.size();
172 if (size_xnew != (ynew.size() + 1) || size_xnew != (enew.size() + 1))
173 throw std::runtime_error(
"rebin: new y and error vectors should be of same "
174 "size & 1 shorter than x");
176 size_t size_yold = yold.size();
177 size_t size_ynew = ynew.size();
181 std::fill(ynew.begin(), ynew.end(), 0.0);
182 std::fill(enew.begin(), enew.end(), 0.0);
185 size_t iold = 0, inew = 0;
188 while ((inew < size_ynew) && (iold < size_yold)) {
189 double xo_low = xold[iold];
190 double xo_high = xold[iold + 1];
191 double xn_low = xnew[inew];
192 double xn_high = xnew[inew + 1];
193 if (xn_high <= xo_low)
195 else if (xo_high <= xn_low)
200 double delta = xo_high < xn_high ? xo_high : xn_high;
201 delta -= xo_low > xn_low ? xo_low : xn_low;
202 width = xo_high - xo_low;
203 if ((
delta <= 0.0) || (width <= 0.0)) {
215 ynew[inew] += yold[iold] *
delta;
217 enew[inew] += eold[iold] * eold[iold] *
delta * width;
223 ynew[inew] += yold[iold] *
delta / width;
226 enew[inew] += eold[iold] * eold[iold] *
delta / width;
228 if (xn_high > xo_high) {
243 for (
size_t i = 0; i < size_ynew; ++i) {
245 width = xnew[i + 1] - xnew[i];
248 enew[i] = sqrt(enew[i]) / width;
250 throw std::invalid_argument(
"rebin: Invalid output X array, contains consecutive X values");
256 using pf = double (*)(double);
258 std::transform(enew.begin(), enew.end(), enew.begin(), uf);
280void rebinHistogram(
const std::vector<double> &xold,
const std::vector<double> &yold,
const std::vector<double> &eold,
281 const std::vector<double> &xnew, std::vector<double> &ynew, std::vector<double> &enew,
284 const size_t size_yold = yold.size();
285 if (xold.size() != (size_yold + 1) || size_yold != eold.size())
286 throw std::runtime_error(
"rebin: y and error vectors should be of same size & 1 shorter than x");
287 const size_t size_ynew = ynew.size();
288 if (xnew.size() != (size_ynew + 1) || size_ynew != enew.size())
289 throw std::runtime_error(
"rebin: y and error vectors should be of same size & 1 shorter than x");
293 ynew.assign(size_ynew, 0.0);
294 enew.assign(size_ynew, 0.0);
298 size_t iold = 0, inew = 0;
300 if (xnew.front() > xold.front()) {
301 auto it = std::upper_bound(xold.cbegin(), xold.cend(), xnew.front());
302 if (it == xold.end())
305 iold = std::distance(xold.begin(), it) - 1;
307 auto it = std::upper_bound(xnew.cbegin(), xnew.cend(), xold.front());
308 if (it == xnew.cend())
311 inew = std::distance(xnew.cbegin(), it) - 1;
315 double oneOverWidth, overlap;
319 for (; iold < size_yold; ++iold) {
320 double xold_of_iold_p_1 = xold[iold + 1];
322 if (xold_of_iold_p_1 <= xnew[inew + 1]) {
323 ynew[inew] += yold[iold];
325 enew[inew] += temp * temp;
327 if (xold_of_iold_p_1 == xnew[inew + 1])
330 double xold_of_iold = xold[iold];
332 oneOverWidth = 1. / (xold_of_iold_p_1 - xold_of_iold);
333 frac = yold[iold] * oneOverWidth;
335 fracE = temp * temp * oneOverWidth;
338 while (inew < size_ynew && xnew[inew + 1] <= xold_of_iold_p_1) {
339 overlap = xnew[inew + 1] - std::max(xnew[inew], xold_of_iold);
340 ynew[inew] += frac * overlap;
341 enew[inew] += fracE * overlap;
346 if (inew == size_ynew)
350 overlap = xold_of_iold_p_1 - xnew[inew];
351 ynew[inew] += frac * overlap;
352 enew[inew] += fracE * overlap;
360 using pf = double (*)(double);
362 std::transform(enew.begin(), enew.end(), enew.begin(), uf);
373 const std::vector<double>::size_type npoints = bin_edges.size();
374 if (bin_centres.size() != npoints) {
375 bin_centres.resize(npoints);
381 std::adjacent_difference(bin_edges.begin(), bin_edges.end(), bin_centres.begin(),
SimpleAverage<double>());
385 bin_centres.erase(bin_centres.begin());
405 const auto n = bin_centers.size();
413 bin_edges.resize(
n + 1);
418 bin_edges[0] = bin_centers[0] - 0.5;
419 bin_edges[1] = bin_centers[0] + 0.5;
423 for (
size_t i = 0; i <
n - 1; ++i) {
424 bin_edges[i + 1] = 0.5 * (bin_centers[i] + bin_centers[i + 1]);
427 bin_edges[0] = bin_centers[0] - (bin_edges[1] - bin_centers[0]);
429 bin_edges[
n] = bin_centers[
n - 1] + (bin_centers[
n - 1] - bin_edges[
n - 1]);
445 return static_cast<size_t>(
index);
447 throw std::out_of_range(
"indexOfValue - value out of range");
451 if (bin_centers.empty()) {
452 throw std::out_of_range(
"indexOfValue - vector is empty");
454 if (bin_centers.size() == 1) {
456 if (
value < bin_centers[0] - 0.5 ||
value > bin_centers[0] + 0.5) {
462 const size_t n = bin_centers.size();
463 const double firstBinLowEdge = bin_centers[0] - 0.5 * (bin_centers[1] - bin_centers[0]);
464 const double lastBinHighEdge = bin_centers[
n - 1] + 0.5 * (bin_centers[
n - 1] - bin_centers[
n - 2]);
465 if (value < firstBinLowEdge || value > lastBinHighEdge) {
468 const auto it = std::lower_bound(bin_centers.begin(), bin_centers.end(),
value);
469 if (it == bin_centers.end()) {
470 return static_cast<int>(
n - 1);
472 size_t binIndex = std::distance(bin_centers.begin(), it);
474 value < bin_centers[binIndex - 1] + 0.5 * (bin_centers[binIndex] - bin_centers[binIndex - 1])) {
477 return static_cast<int>(binIndex);
491 if (bin_edges.empty()) {
492 throw std::out_of_range(
"indexOfValue - vector is empty");
494 if (bin_edges.size() == 1) {
495 throw std::out_of_range(
"indexOfValue - requires at least two bin edges");
497 if (
value < bin_edges.front()) {
498 throw std::out_of_range(
"indexOfValue - value out of range");
500 const auto it = std::lower_bound(bin_edges.begin(), bin_edges.end(),
value);
501 if (it == bin_edges.end()) {
502 throw std::out_of_range(
"indexOfValue - value out of range");
505 size_t edgeIndex = std::distance(bin_edges.begin(), it);
520 auto i = arra.cbegin();
522 if (i == arra.cend()) {
529 for (; val != val;) {
531 if (i == arra.cend()) {
538 for (; i != arra.cend(); ++i) {
556 std::vector<NumT> values;
558 using split_vector_type = std::vector<std::string>;
559 split_vector_type strs;
561 boost::split(strs, listString, boost::is_any_of(
", "));
562 for (
auto &str : strs) {
565 std::stringstream oneNumber(str);
568 values.emplace_back(num);
584 assert(bins.size() >= 2);
586 assert(bins.size() <
static_cast<size_t>(std::numeric_limits<int>::max()));
588 if (
value < bins.front())
597 auto it = std::upper_bound(bins.begin(), bins.end() - 1,
value) - 1;
598 assert(it >= bins.begin());
600 return static_cast<int>(it - bins.begin());
618double runAverage(
size_t index,
size_t startIndex,
size_t endIndex,
const double halfWidth,
619 const std::vector<double> &input, std::vector<double>
const *
const binBndrs) {
622 double weight0(0), weight1(0), start(0.0), end(0.0);
630 auto &rBndrs = *binBndrs;
633 double binC = 0.5 * (rBndrs[
index + 1] + rBndrs[
index]);
634 start = binC - halfWidth;
635 end = binC + halfWidth;
636 if (start <= rBndrs[startIndex]) {
644 if (end >= rBndrs[endIndex]) {
646 end = rBndrs[endIndex];
649 weight1 = (end - rBndrs[
iEnd]) / (rBndrs[
iEnd + 1] - rBndrs[
iEnd]);
653 weight0 = (end - start) / (rBndrs[
iStart] - rBndrs[
iStart - 1]);
656 auto iHalfWidth =
static_cast<size_t>(halfWidth);
658 if (startIndex + iHalfWidth >
index)
673 avrg += input[
iStart - 1] * weight0;
674 if (
iEnd != endIndex)
675 avrg += input[
iEnd] * weight1;
677 double div = end - start;
681 return avrg / (end - start);
686 return avrg / double(ic);
716void smoothInRange(
const std::vector<double> &input, std::vector<double> &output,
const double avrgInterval,
717 std::vector<double>
const *
const binBndrs,
size_t startIndex,
size_t endIndex,
718 std::vector<double> *
const outBins) {
721 endIndex = input.size();
722 if (endIndex > input.size())
723 endIndex = input.size();
725 if (endIndex <= startIndex) {
730 size_t max_size = input.size();
732 if (binBndrs->size() != max_size + 1) {
733 throw std::invalid_argument(
"Array of bin boundaries, "
734 "if present, have to be one bigger then the input array");
738 size_t length = endIndex - startIndex;
739 output.resize(length);
741 double halfWidth = avrgInterval / 2;
743 if (std::floor(halfWidth) * 2 - avrgInterval > 1.e-6) {
744 halfWidth = std::floor(halfWidth) + 1;
749 outBins->resize(length + 1);
753 for (
size_t i = startIndex; i < endIndex; i++) {
755 binSize = binBndrs->operator[](i + 1) - binBndrs->operator[](i);
757 output[i - startIndex] = runAverage(i, startIndex, endIndex, halfWidth, input, binBndrs) * binSize;
758 if (outBins && binBndrs) {
759 outBins->operator[](i - startIndex) = binBndrs->operator[](i);
762 if (outBins && binBndrs) {
763 outBins->operator[](endIndex - startIndex) = binBndrs->operator[](endIndex);
double value
The value of the point.
std::map< DeltaEMode::Type, std::string > index
#define DLLExport
Definitions of the DLLImport compiler directives for MSVC.
MANTID_KERNEL_DLL void smoothInRange(const std::vector< double > &input, std::vector< double > &output, double avrgInterval, std::vector< double > const *const binBndrs=nullptr, size_t startIndex=0, size_t endIndex=0, std::vector< double > *const outBins=nullptr)
Basic running average of input vector within specified range, considering variable bin-boundaries if ...
template DLLExport std::vector< int32_t > splitStringIntoVector< int32_t >(std::string listString)
Declare all version of this.
template DLLExport std::vector< double > splitStringIntoVector< double >(std::string listString)
size_t MANTID_KERNEL_DLL indexOfValueFromCenters(const std::vector< double > &bin_centers, const double value)
Gets the bin of a value from a vector of bin centers and throws exception if out of range.
template DLLExport std::vector< std::string > splitStringIntoVector< std::string >(std::string listString)
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.
template DLLExport std::vector< float > splitStringIntoVector< float >(std::string listString)
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.
MANTID_KERNEL_DLL int getBinIndex(const std::vector< double > &bins, const double value)
Return the index into a vector of bin boundaries for a particular X value.
MANTID_KERNEL_DLL std::vector< NumT > splitStringIntoVector(std::string listString)
Take a string of comma or space-separated values, and splits it into a vector of doubles.
size_t MANTID_KERNEL_DLL indexOfValueFromEdges(const std::vector< double > &bin_edges, const double value)
Gets the bin of a value from a vector of bin edges.
template DLLExport std::vector< int64_t > splitStringIntoVector< int64_t >(std::string listString)
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.
void MANTID_KERNEL_DLL rebin(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 distribution, bool addition=false)
Rebins data according to a new output X array.
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.
void MANTID_KERNEL_DLL convertToBinBoundary(const std::vector< double > &bin_centers, std::vector< double > &bin_edges)
Convert an array of bin centers to bin boundary values.
template DLLExport std::vector< size_t > splitStringIntoVector< size_t >(std::string listString)
int MANTID_KERNEL_DLL indexOfValueFromCentersNoThrow(const std::vector< double > &bin_centers, const double value)
Gets the bin of a value from a vector of bin centers and returns -1 if out of range.
A binary functor to compute the simple average of 2 numbers.