Unverified Commit f347da53 authored by DannyHindson's avatar DannyHindson Committed by GitHub
Browse files

Merge pull request #32014 from mantidproject/31747_iview_event_rebin

In-place rebinning in the instrument view
parents 7c738fc1 b08bb74f
......@@ -56,6 +56,7 @@ public:
const std::vector<std::string> seeAlso() const override {
return {"RebinToWorkspace", "Rebin2D", "Rebunch", "Regroup", "RebinByPulseTimes", "RebinByTimeAtSample"};
}
std::map<std::string, std::string> validateInputs() override;
static std::vector<double> rebinParamsFromInput(const std::vector<double> &inParams,
const API::MatrixWorkspace &inputWS, Kernel::Logger &logger);
......
......@@ -15,6 +15,7 @@
#include "MantidDataObjects/Workspace2D.h"
#include "MantidDataObjects/WorkspaceCreation.h"
#include "MantidKernel/ArrayProperty.h"
#include "MantidKernel/BoundedValidator.h"
#include "MantidKernel/RebinParamsValidator.h"
#include "MantidKernel/VectorHelper.h"
......@@ -49,8 +50,7 @@ using HistogramData::Exception::InvalidBinEdgesError;
std::vector<double> Rebin::rebinParamsFromInput(const std::vector<double> &inParams,
const API::MatrixWorkspace &inputWS, Kernel::Logger &logger) {
std::vector<double> rbParams;
// The validator only passes parameters with size 1, or 3xn. No need to check
// again here
// The validator only passes parameters with size 1, or 3xn. No need to check again here
if (inParams.size() >= 3) {
// Input are min, delta, max
rbParams = inParams;
......@@ -66,7 +66,7 @@ std::vector<double> Rebin::rebinParamsFromInput(const std::vector<double> &inPar
rbParams[2] = xmax;
if ((rbParams[1] < 0.) && (xmin < 0.) && (xmax > 0.)) {
std::stringstream msg;
msg << "Cannot create logorithmic binning that changes sign (xmin=" << xmin << ", xmax=" << xmax << ")";
msg << "Cannot create logarithmic binning that changes sign (xmin=" << xmin << ", xmax=" << xmax << ")";
throw std::runtime_error(msg.str());
}
}
......@@ -77,6 +77,48 @@ std::vector<double> Rebin::rebinParamsFromInput(const std::vector<double> &inPar
// Public methods
//---------------------------------------------------------------------------------------------
/// Validate that the input properties are sane.
std::map<std::string, std::string> Rebin::validateInputs() {
std::map<std::string, std::string> helpMessages;
if (existsProperty("Power") && !isDefault("Power")) {
const double power = getProperty("Power");
// attempt to roughly guess how many bins these parameters imply
double roughEstimate = 0;
if (!isDefault("Params")) {
const std::vector<double> params = getProperty("Params");
// Five significant places of the Euler-Mascheroni constant is probably more than enough for our needs
double eulerMascheroni = 0.57721;
// Params is check by the validator first, so we can assume it is in a correct format
for (size_t i = 0; i < params.size() - 2; i += 2) {
double upperLimit = params[i + 2];
double lowerLimit = params[i];
double factor = params[i + 1];
if (factor <= 0) {
helpMessages["Params"] = "Provided width value cannot be negative for inverse power binning.";
return helpMessages;
}
if (power == 1) {
roughEstimate += std::exp((upperLimit - lowerLimit) / factor - eulerMascheroni);
} else {
roughEstimate += std::pow(((upperLimit - lowerLimit) / factor) * (1 - power) + 1, 1 / (1 - power));
}
}
}
// Prevent the user form creating too many bins
if (roughEstimate > 10000) {
helpMessages["Power"] = "This binning is expected to give more than 10000 bins.";
}
}
return helpMessages;
}
/** Initialisation method. Declares properties to be used in algorithm.
*
*/
......@@ -88,31 +130,35 @@ void Rebin::init() {
declareProperty(std::make_unique<ArrayProperty<double>>("Params", std::make_shared<RebinParamsValidator>()),
"A comma separated list of first bin boundary, width, last bin boundary. "
"Optionally "
"this can be followed by a comma and more widths and last boundary "
"pairs. "
"Optionally this can also be a single number, which is the bin width. "
"In this case, the boundary of binning will be determined by minimum and "
"maximum TOF "
"values among all events, or previous binning boundary, in case of event "
"Workspace, or "
"non-event Workspace, respectively. Negative width values indicate "
"logarithmic binning. ");
"Optionally this can be followed by a comma and more widths and last boundary pairs. "
"Optionally this can also be a single number, which is the bin width. In this case, the boundary of "
"binning will be determined by minimum and maximum TOF values among all events, or previous binning "
"boundary, in case of event Workspace, or non-event Workspace, respectively. "
"Negative width values indicate logarithmic binning.");
declareProperty("PreserveEvents", true,
"Keep the output workspace as an EventWorkspace, "
"if the input has events. If the input and output EventWorkspace "
"names are the same, only the X bins are set, which is very quick. If "
"false, "
"then the workspace gets converted to a Workspace2D histogram.");
"Keep the output workspace as an EventWorkspace, if the input has events. If the input and output "
"EventWorkspace names are the same, only the X bins are set, which is very quick. If false, then the "
"workspace gets converted to a Workspace2D histogram.");
declareProperty("FullBinsOnly", false, "Omit the final bin if it's width is smaller than the step size");
declareProperty("FullBinsOnly", false, "Omit the final bin if its width is smaller than the step size");
declareProperty("IgnoreBinErrors", false,
"Ignore errors related to "
"zero/negative bin widths in "
"input/output workspaces. When ignored, the signal and "
"errors are set to zero");
"Ignore errors related to zero/negative bin widths in input/output workspaces. When ignored, the "
"signal and errors are set to zero");
declareProperty(
"UseReverseLogarithmic", false,
"For logarithmic intervals, the splitting starts from the end and goes back to the start, ie the bins are bigger "
"at the start getting exponentially smaller until they reach the end. For these bins, the FullBinsOnly flag is "
"ignored.");
auto powerValidator = std::make_shared<Mantid::Kernel::BoundedValidator<double>>();
powerValidator->setLower(0);
powerValidator->setUpper(1);
declareProperty("Power", 0., powerValidator,
"Splits the interval in bins which actual width is equal to requested width / (i ^ power); default "
"is linear. Power must be between 0 and 1.");
}
/** Executes the rebin algorithm
......@@ -140,11 +186,17 @@ void Rebin::exec() {
const auto histnumber = static_cast<int>(inputWS->getNumberHistograms());
bool fullBinsOnly = getProperty("FullBinsOnly");
bool useReverseLog = getProperty("UseReverseLogarithmic");
double power = getProperty("Power");
double xmin = 0.;
double xmax = 0.;
inputWS->getXMinMax(xmin, xmax);
HistogramData::BinEdges XValues_new(0);
// create new output X axis
static_cast<void>(
VectorHelper::createAxisFromRebinParams(rbParams, XValues_new.mutableRawData(), true, fullBinsOnly));
static_cast<void>(VectorHelper::createAxisFromRebinParams(rbParams, XValues_new.mutableRawData(), true, fullBinsOnly,
xmin, xmax, useReverseLog, power));
// Now, determine if the input workspace is actually an EventWorkspace
EventWorkspace_const_sptr eventInputWS = std::dynamic_pointer_cast<const EventWorkspace>(inputWS);
......
......@@ -194,6 +194,9 @@ public:
bool dist = rebindata->isDistribution();
TS_ASSERT(dist);
TS_ASSERT(checkBinWidthMonotonic(rebindata, false));
AnalysisDataService::Instance().remove("test_in1D");
AnalysisDataService::Instance().remove("test_out");
}
......@@ -490,6 +493,310 @@ public:
do_test_FullBinsOnly(params, yExpected, xExpected);
}
void test_reverseLogSimple() {
// Test UseReverseLogarithmic alone
Workspace2D_sptr test_1D = Create1DWorkspace(51);
test_1D->setDistribution(false);
AnalysisDataService::Instance().add("test_Rebin_revLog", test_1D);
Rebin rebin;
rebin.initialize();
rebin.setPropertyValue("InputWorkspace", "test_Rebin_revLog");
rebin.setPropertyValue("OutputWorkspace", "test_Rebin_revLog");
rebin.setPropertyValue("Params", "1, -1, 37");
rebin.setProperty("UseReverseLogarithmic", true);
TS_ASSERT_THROWS_NOTHING(rebin.execute());
MatrixWorkspace_sptr out = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("test_Rebin_revLog");
auto &outX = out->x(0);
TS_ASSERT_EQUALS(outX.size(), 6);
TS_ASSERT_DELTA(outX[0], 1, 1e-5);
TS_ASSERT_DELTA(outX[1], 22, 1e-5);
TS_ASSERT_DELTA(outX[2], 30, 1e-5);
TS_ASSERT_DELTA(outX[3], 34, 1e-5);
TS_ASSERT_DELTA(outX[4], 36, 1e-5);
TS_ASSERT_DELTA(outX[5], 37, 1e-5);
TS_ASSERT(checkBinWidthMonotonic(out, true));
AnalysisDataService::Instance().remove("test_Rebin_revLog");
}
void test_reverseLogDiffStep() {
// Test UseReverseLog with a different step than the usual -1
Workspace2D_sptr test_1D = Create1DWorkspace(51);
test_1D->setDistribution(false);
AnalysisDataService::Instance().add("test_Rebin_revLog", test_1D);
Rebin rebin;
rebin.initialize();
rebin.setPropertyValue("InputWorkspace", "test_Rebin_revLog");
rebin.setPropertyValue("OutputWorkspace", "test_Rebin_revLog");
rebin.setPropertyValue("Params", "1, -2, 42");
rebin.setProperty("UseReverseLogarithmic", true);
TS_ASSERT_THROWS_NOTHING(rebin.execute());
MatrixWorkspace_sptr out = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("test_Rebin_revLog");
auto &outX = out->x(0);
TS_ASSERT_EQUALS(outX.size(), 4);
TS_ASSERT_DELTA(outX[0], 1, 1e-5);
TS_ASSERT_DELTA(outX[1], 34, 1e-5);
TS_ASSERT_DELTA(outX[2], 40, 1e-5);
TS_ASSERT_DELTA(outX[3], 42, 1e-5);
TS_ASSERT(checkBinWidthMonotonic(out, true));
AnalysisDataService::Instance().remove("test_Rebin_revLog");
}
void test_reverseLogEdgeCase() {
// Check the case where the parameters given are so that the edges of the bins fall perfectly, and so no padding is
// needed
Workspace2D_sptr test_1D = Create1DWorkspace(51);
test_1D->setDistribution(false);
AnalysisDataService::Instance().add("test_Rebin_revLog", test_1D);
Rebin rebin;
rebin.initialize();
rebin.setPropertyValue("InputWorkspace", "test_Rebin_revLog");
rebin.setPropertyValue("OutputWorkspace", "test_Rebin_revLog");
rebin.setPropertyValue("Params", "1, -1, 16");
rebin.setProperty("UseReverseLogarithmic", true);
TS_ASSERT_THROWS_NOTHING(rebin.execute());
MatrixWorkspace_sptr out = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("test_Rebin_revLog");
auto &outX = out->x(0);
TS_ASSERT_EQUALS(outX.size(), 5);
TS_ASSERT_DELTA(outX[0], 1, 1e-5)
TS_ASSERT_DELTA(outX[1], 9, 1e-5);
TS_ASSERT_DELTA(outX[2], 13, 1e-5);
TS_ASSERT_DELTA(outX[3], 15, 1e-5);
TS_ASSERT_DELTA(outX[4], 16, 1e-5);
TS_ASSERT(checkBinWidthMonotonic(out, true));
AnalysisDataService::Instance().remove("test_Rebin_revLog");
}
void test_reverseLogAgainst() {
// Test UseReverseLogarithmic with a linear spacing before it
Workspace2D_sptr test_1D = Create1DWorkspace(51);
test_1D->setDistribution(false);
AnalysisDataService::Instance().add("test_Rebin_revLog", test_1D);
Rebin rebin;
rebin.initialize();
rebin.setPropertyValue("InputWorkspace", "test_Rebin_revLog");
rebin.setPropertyValue("OutputWorkspace", "test_Rebin_revLog");
rebin.setPropertyValue("Params", "1, 2, 5, -1, 100");
rebin.setProperty("UseReverseLogarithmic", true);
TS_ASSERT_THROWS_NOTHING(rebin.execute());
MatrixWorkspace_sptr out = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("test_Rebin_revLog");
auto &outX = out->x(0);
TS_ASSERT_EQUALS(outX.size(), 7); // 2 lin + 4 log
TS_ASSERT_DELTA(outX[0], 1, 1e-5);
TS_ASSERT_DELTA(outX[1], 3, 1e-5);
TS_ASSERT_DELTA(outX[2], 5, 1e-5);
TS_ASSERT_DELTA(outX[3], 65, 1e-5);
TS_ASSERT_DELTA(outX[4], 85, 1e-5);
TS_ASSERT_DELTA(outX[5], 95, 1e-5);
TS_ASSERT_DELTA(outX[6], 100, 1e-5);
AnalysisDataService::Instance().remove("test_Rebin_revLog");
}
void test_reverseLogBetween() {
// Test UseReverseLogarithmic between 2 linear binnings
Workspace2D_sptr test_1D = Create1DWorkspace(51);
test_1D->setDistribution(false);
AnalysisDataService::Instance().add("test_Rebin_revLog", test_1D);
Rebin rebin;
rebin.initialize();
rebin.setPropertyValue("InputWorkspace", "test_Rebin_revLog");
rebin.setPropertyValue("OutputWorkspace", "test_Rebin_revLog");
rebin.setPropertyValue("Params", "1, 2, 5, -1, 100, 2, 110");
rebin.setProperty("UseReverseLogarithmic", true);
TS_ASSERT_THROWS_NOTHING(rebin.execute());
MatrixWorkspace_sptr out = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("test_Rebin_revLog");
auto &outX = out->x(0);
TS_ASSERT_EQUALS(outX.size(), 12);
TS_ASSERT_DELTA(outX[0], 1, 1e-5);
TS_ASSERT_DELTA(outX[1], 3, 1e-5);
TS_ASSERT_DELTA(outX[2], 5, 1e-5);
TS_ASSERT_DELTA(outX[3], 65, 1e-5);
TS_ASSERT_DELTA(outX[4], 85, 1e-5);
TS_ASSERT_DELTA(outX[5], 95, 1e-5);
TS_ASSERT_DELTA(outX[6], 100, 1e-5);
TS_ASSERT_DELTA(outX[7], 102, 1e-5);
TS_ASSERT_DELTA(outX[11], 110, 1e-5);
AnalysisDataService::Instance().remove("test_Rebin_revLog");
}
void test_reverseLogFullBinsOnly() {
// Test UseReverseLogarithmic with the FullBinsOnly option checked. It should not change anything from the non
// checked version.
Workspace2D_sptr test_1D = Create1DWorkspace(51);
test_1D->setDistribution(false);
AnalysisDataService::Instance().add("test_Rebin_revLog", test_1D);
Rebin rebin;
rebin.initialize();
rebin.setPropertyValue("InputWorkspace", "test_Rebin_revLog");
rebin.setPropertyValue("OutputWorkspace", "test_Rebin_revLog");
rebin.setPropertyValue("Params", "1, -1, 37");
rebin.setProperty("UseReverseLogarithmic", true);
rebin.setProperty("FullBinsOnly", true);
TS_ASSERT_THROWS_NOTHING(rebin.execute());
MatrixWorkspace_sptr out = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("test_Rebin_revLog");
auto &outX = out->x(0);
TS_ASSERT_EQUALS(outX.size(), 6);
TS_ASSERT_DELTA(outX[0], 1, 1e-5);
TS_ASSERT_DELTA(outX[1], 22, 1e-5);
TS_ASSERT_DELTA(outX[2], 30, 1e-5);
TS_ASSERT_DELTA(outX[3], 34, 1e-5);
TS_ASSERT_DELTA(outX[4], 36, 1e-5);
TS_ASSERT_DELTA(outX[5], 37, 1e-5);
TS_ASSERT(checkBinWidthMonotonic(out, true));
AnalysisDataService::Instance().remove("test_Rebin_revLog");
}
void test_reverseLogIncompleteFirstBin() {
// Test UseReverseLogarithmic with a first bin that is incomplete, but still bigger than the next one so not merged.
Workspace2D_sptr test_1D = Create1DWorkspace(51);
test_1D->setDistribution(false);
AnalysisDataService::Instance().add("test_Rebin_revLog", test_1D);
Rebin rebin;
rebin.initialize();
rebin.setPropertyValue("InputWorkspace", "test_Rebin_revLog");
rebin.setPropertyValue("OutputWorkspace", "test_Rebin_revLog");
rebin.setPropertyValue("Params", "1, -1, 60");
rebin.setProperty("UseReverseLogarithmic", true);
rebin.setProperty("FullBinsOnly", true);
TS_ASSERT_THROWS_NOTHING(rebin.execute());
MatrixWorkspace_sptr out = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("test_Rebin_revLog");
auto &outX = out->x(0);
TS_ASSERT_EQUALS(outX.size(), 7);
TS_ASSERT_DELTA(outX[0], 1, 1e-5);
TS_ASSERT_DELTA(outX[1], 29, 1e-5);
TS_ASSERT_DELTA(outX[2], 45, 1e-5);
TS_ASSERT_DELTA(outX[3], 53, 1e-5);
TS_ASSERT_DELTA(outX[4], 57, 1e-5);
TS_ASSERT_DELTA(outX[5], 59, 1e-5);
TS_ASSERT_DELTA(outX[6], 60, 1e-5);
TS_ASSERT(checkBinWidthMonotonic(out, true));
AnalysisDataService::Instance().remove("test_Rebin_revLog");
}
void test_inversePowerSquareRoot() {
// Test InversePower in a simple case of square root sum
Workspace2D_sptr test_1D = Create1DWorkspace(51);
test_1D->setDistribution(false);
AnalysisDataService::Instance().add("test_Rebin_revLog", test_1D);
Rebin rebin;
rebin.initialize();
rebin.setPropertyValue("InputWorkspace", "test_Rebin_revLog");
rebin.setPropertyValue("OutputWorkspace", "test_Rebin_revLog");
rebin.setPropertyValue("Params", "1, 1, 10");
rebin.setPropertyValue("Power", "0.5");
TS_ASSERT_THROWS_NOTHING(rebin.execute());
MatrixWorkspace_sptr out = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("test_Rebin_revLog");
auto &outX = out->x(0);
TS_ASSERT_EQUALS(outX.size(), 28);
TS_ASSERT_DELTA(outX[0], 1, 1e-5);
TS_ASSERT_DELTA(outX[1], 2, 1e-5);
TS_ASSERT_DELTA(outX[2], 2.707106781, 1e-5);
TS_ASSERT_DELTA(outX[3], 3.28445705, 1e-5);
TS_ASSERT_DELTA(outX[27], 10, 1e-5);
TS_ASSERT(checkBinWidthMonotonic(out, true));
AnalysisDataService::Instance().remove("test_Rebin_revLog");
}
void test_inversePowerHarmonic() {
// Test InversePower in a simple case of harmonic serie
Workspace2D_sptr test_1D = Create1DWorkspace(51);
test_1D->setDistribution(false);
AnalysisDataService::Instance().add("test_Rebin_revLog", test_1D);
Rebin rebin;
rebin.initialize();
rebin.setPropertyValue("InputWorkspace", "test_Rebin_revLog");
rebin.setPropertyValue("OutputWorkspace", "test_Rebin_revLog");
rebin.setPropertyValue("Params", "1, 1, 5");
rebin.setPropertyValue("Power", "1");
TS_ASSERT_THROWS_NOTHING(rebin.execute());
MatrixWorkspace_sptr out = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("test_Rebin_revLog");
auto &outX = out->x(0);
TS_ASSERT_EQUALS(outX.size(), 31);
TS_ASSERT_DELTA(outX[0], 1, 1e-5);
TS_ASSERT_DELTA(outX[1], 2, 1e-5);
TS_ASSERT_DELTA(outX[2], 2.5, 1e-5);
TS_ASSERT_DELTA(outX[3], 2.8333333, 1e-5);
TS_ASSERT_DELTA(outX[30], 5, 1e-5);
TS_ASSERT(checkBinWidthMonotonic(out, true, true));
AnalysisDataService::Instance().remove("test_Rebin_revLog");
}
void test_inversePowerValidateHarmonic() {
// Test that the validator which forbid breating more than 10000 bins works in a harmonic series case
Workspace2D_sptr test_1D = Create1DWorkspace(51);
test_1D->setDistribution(false);
AnalysisDataService::Instance().add("test_Rebin_revLog", test_1D);
Rebin rebin;
rebin.initialize();
rebin.setPropertyValue("InputWorkspace", "test_Rebin_revLog");
rebin.setPropertyValue("OutputWorkspace", "test_Rebin_revLog");
rebin.setPropertyValue("Params", "1, 1, 100");
rebin.setPropertyValue("Power", "1");
TS_ASSERT_THROWS(rebin.execute(), const std::runtime_error &);
AnalysisDataService::Instance().remove("test_Rebin_revLog");
}
void test_inversePowerValidateInverseSquareRoot() {
// Test that the validator which forbid breating more than 10000 bins works in an inverse square root case
// We test both because they rely on different formula to compute the expected number of bins.
Workspace2D_sptr test_1D = Create1DWorkspace(51);
test_1D->setDistribution(false);
AnalysisDataService::Instance().add("test_Rebin_revLog", test_1D);
Rebin rebin;
rebin.initialize();
rebin.setPropertyValue("InputWorkspace", "test_Rebin_revLog");
rebin.setPropertyValue("OutputWorkspace", "test_Rebin_revLog");
rebin.setPropertyValue("Params", "1, 1, 1000");
rebin.setPropertyValue("Power", "0.5");
TS_ASSERT_THROWS(rebin.execute(), const std::runtime_error &);
AnalysisDataService::Instance().remove("test_Rebin_revLog");
}
void test_parallel_cloned() { ParallelTestHelpers::runParallel(run_rebin, "Parallel::StorageMode::Cloned"); }
void test_parallel_distributed() {
......@@ -507,10 +814,10 @@ public:
private:
Workspace2D_sptr Create1DWorkspace(int size) {
auto retVal = createWorkspace<Workspace2D>(1, size, size - 1);
double j = 1.0;
double j = 0.5;
for (int i = 0; i < size; i++) {
retVal->dataX(0)[i] = j * 0.5;
j += 1.5;
retVal->dataX(0)[i] = j;
j += 0.75;
}
retVal->setCounts(0, size - 1, 3.0);
retVal->setCountVariances(0, size - 1, 3.0);
......@@ -574,6 +881,24 @@ private:
auto &yValues = ws->y(0);
TS_ASSERT_DELTA(yValues.rawData(), yExpected, 0.001);
}
bool checkBinWidthMonotonic(MatrixWorkspace_sptr ws, bool reverse = false, bool ignoreLastBin = false) {
size_t binEdgesTotal = ws->blocksize();
if (ignoreLastBin)
binEdgesTotal--;
auto binEdges = ws->binEdges(0);
double lastBinSize = binEdges[1] - binEdges[0];
for (size_t i = 1; i < binEdgesTotal; ++i) {
double currentBinSize = binEdges[i + 1] - binEdges[i];
if (((lastBinSize < currentBinSize) && reverse) || ((lastBinSize > currentBinSize) && !reverse)) {
return false;
}
lastBinSize = currentBinSize;
}
return true;
}
};
class RebinTestPerformance : public CxxTest::TestSuite {
......
......@@ -27,7 +27,8 @@ namespace VectorHelper {
int MANTID_KERNEL_DLL createAxisFromRebinParams(const std::vector<double> &params, 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 double xMaxHint = std::nan(""),
const bool useReverseLogarithmic = false, const double power = -1);
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,
......
......@@ -27,11 +27,13 @@ namespace Mantid::Kernel::VectorHelper {
*step are not included. (Default=True)
* @param[in] xMinHint x_1 if params contains only delta_1.
* @param[in] xMaxHint x_2 if params contains only delta_1.
* @param[in] useReverseLogarithmic wheter or not to use reverse logarithmic for bins
* @param[in] power the power in case of inverse power sum. Must be between 0 and 1 or is ignored.
* @return The number of bin boundaries in the new axis
**/
int DLLExport createAxisFromRebinParams(const std::vector<double> &params, std::vector<double> &xnew,
const bool resize_xnew, const bool full_bins_only, const double xMinHint,
const double xMaxHint) {
const double xMaxHint, const bool useReverseLogarithmic, const double power) {
std::vector<double> tmp;
const std::vector<double> &fullParams = [&params, &tmp, xMinHint, xMaxHint]() {
if (params.size() == 1) {
......@@ -51,14 +53,12 @@ int DLLExport createAxisFromRebinParams(const std::vector<double> &params, std::
auto ibounds = static_cast<int>(fullParams.size());
int isteps = ibounds - 1; // highest index in params array containing a step
// This coefficitent represents the maximum difference between the size of the
// last bin and all
// This coefficitent represents the maximum difference between the size of the last bin and all
// the other bins.
double lastBinCoef(0.25);
if (full_bins_only) {
// For full_bin_only, we want it so that last bin couldn't be smaller then
// the pervious bin
// For full_bin_only, we want it so that last bin couldn't be smaller than the previous bin
lastBinCoef = 1.0;
}
......@@ -69,44 +69,75 @@ int DLLExport createAxisFromRebinParams(const std::vector<double> &params, std::
if (resize_xnew)
xnew.emplace_back(xcurr);
int currDiv = 1;
bool isPower = power > 0 && power <= 1;
while ((ibound <= ibounds) && (istep <= isteps)) {
// if step is negative then it is logarithmic step
if (fullParams[istep] >= 0.0)
xs = fullParams[istep];
else
xs = xcurr * fabs(fullParams[istep]);
bool isLogBin = (fullParams[istep] < 0.0);
bool isReverseLogBin = isLogBin && useReverseLogarithmic;
double alpha = std::fabs(fullParams[istep]);
if (isReverseLogBin && xcurr == fullParams[ibound - 2]) {
// we are starting a new bin, but since it is a rev log, xcurr needs to be at its end
xcurr = fullParams[ibound];
}
if (!isPower) {
if (!isLogBin)
xs = fullParams[istep];
else {
if (useReverseLogarithmic) {
// we go through a reverse log bin by starting from its end, and working our way back to the beginning
// this way we can define the bins in a reccuring way, and with a more obvious closeness with the usual log.