Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
mantidproject
mantid
Commits
71901b4e
Commit
71901b4e
authored
Aug 09, 2021
by
Mathieu Tillet
Browse files
Add an inverse power rebinning method
Allow the user to rebin with bins that becomes increasingly smaller.
parent
d12a0b4f
Changes
7
Show whitespace changes
Inline
Side-by-side
Framework/Algorithms/inc/MantidAlgorithms/Rebin.h
View file @
71901b4e
...
...
@@ -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
);
...
...
Framework/Algorithms/src/Rebin.cpp
View file @
71901b4e
...
...
@@ -78,6 +78,56 @@ 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"
);
if
(
power
<
0
)
{
helpMessages
[
"Power"
]
=
"Power cannot be negative"
;
return
helpMessages
;
}
if
(
power
>
1
)
{
helpMessages
[
"Power"
]
=
"Power cannot be more than one."
;
return
helpMessages
;
}
// 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 1000 bins."
;
}
}
return
helpMessages
;
}
/** Initialisation method. Declares properties to be used in algorithm.
*
*/
...
...
@@ -110,6 +160,9 @@ void Rebin::init() {
"For logarithmic intervals, the splitting starts from the end and go back to the start, ie the bins "
"are bigger at the start and exponentially reduces until they reach the end. For these bins, the "
"FullBinsOnly flag is ignored."
);
declareProperty
(
"Power"
,
EMPTY_DBL
(),
"Splits the interval in bins whose width is width / (i ^ power). Power must be between 0 and 1."
);
}
/** Executes the rebin algorithm
...
...
@@ -138,6 +191,7 @@ void Rebin::exec() {
bool
fullBinsOnly
=
getProperty
(
"FullBinsOnly"
);
bool
useReverseLog
=
getProperty
(
"UseReverseLogarithmic"
);
double
power
=
getProperty
(
"Power"
);
double
xmin
=
0.
;
double
xmax
=
0.
;
...
...
@@ -146,7 +200,7 @@ void Rebin::exec() {
HistogramData
::
BinEdges
XValues_new
(
0
);
// create new output X axis
static_cast
<
void
>
(
VectorHelper
::
createAxisFromRebinParams
(
rbParams
,
XValues_new
.
mutableRawData
(),
true
,
fullBinsOnly
,
xmin
,
xmax
,
useReverseLog
));
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
);
...
...
Framework/Algorithms/test/RebinTest.h
View file @
71901b4e
...
...
@@ -689,6 +689,93 @@ public:
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
);
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
);
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
()
{
...
...
Framework/Kernel/inc/MantidKernel/VectorHelper.h
View file @
71901b4e
...
...
@@ -28,7 +28,7 @@ int MANTID_KERNEL_DLL createAxisFromRebinParams(const std::vector<double> ¶m
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
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
,
...
...
Framework/Kernel/src/VectorHelper.cpp
View file @
71901b4e
...
...
@@ -10,6 +10,7 @@
#include
"MantidKernel/VectorHelper.h"
#include
<algorithm>
#include
<boost/algorithm/string.hpp>
#include
<iostream>
#include
<numeric>
#include
<sstream>
...
...
@@ -34,7 +35,7 @@ namespace VectorHelper {
**/
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
bool
useReverseLogarithmic
)
{
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
)
{
...
...
@@ -70,6 +71,10 @@ int DLLExport createAxisFromRebinParams(const std::vector<double> ¶ms, 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
bool
isLogBin
=
(
fullParams
[
istep
]
<
0.0
);
...
...
@@ -80,7 +85,7 @@ int DLLExport createAxisFromRebinParams(const std::vector<double> ¶ms, std::
// 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
{
...
...
@@ -95,6 +100,10 @@ int DLLExport createAxisFromRebinParams(const std::vector<double> ¶ms, std::
}
else
xs
=
xcurr
*
fabs
(
fullParams
[
istep
]);
}
}
else
{
xs
=
fullParams
[
istep
]
*
std
::
pow
(
currDiv
,
-
power
);
++
currDiv
;
}
if
(
fabs
(
xs
)
==
0.0
)
{
// Someone gave a 0-sized step! What a dope.
...
...
docs/source/algorithms/Rebin-v1.rst
View file @
71901b4e
...
...
@@ -94,6 +94,19 @@ Hence the actual *Param* string used is "0, 2, 4, 3, 10".
This flag is ignored if UseReverseLogarithm is checked.
Power option
############
If a value between 0 (excluded) and 1 (included) is provided in the Power field, the binning will follow an inverse power
pattern, each bin having a width of
.. math:: w_i = \frac{F}{i^{\mathrm{power}}
where F is the factor provided between the boundaries.
Since, even though these series diverge and will reach whatever bounds are given, they might take an exponentially slow time
to reach them, and thus an exponential number of bins, a check ensure that the total number of bins is not greater
than 10000.
.. _rebin-usage:
Usage
...
...
@@ -161,6 +174,26 @@ Output:
The rebinned X values are: [ 1. 6. 8. 9.]
**Example - Inverse power rebinning:**
.. testcode:: ExInversePower
# create histogram workspace
dataX = [1,2,3,4,5,6,7,8,9,10] # or use dataX=range(1,11)
dataY = [1,2,3,4,5,6,7,8,9] # or use dataY=range(1,10)
ws = CreateWorkspace(dataX, dataY)
# rebin from min to max - 1 with square root
ws = Rebin(ws, "1, 3, 10", Power=0.5)
print("The rebinned X values are: {}".format(ws.readX(0)))
Output:
.. testoutput:: ExHistRevLog
The rebinned X values are: [ 1. 4. 6.121320344 7.853371151 9.353371151 10.]
**Example - custom two regions rebinning:**
.. testcode:: ExHistCustom
...
...
docs/source/release/v6.2.0/framework.rst
View file @
71901b4e
...
...
@@ -21,7 +21,7 @@ Improvements
- :ref:`CreateSampleWorkspace <algm-CreateSampleWorkspace>` has new property InstrumentName.
- Event nexuses produced at ILL can now be loaded using :ref:`LoadEventNexus <algm-LoadEventNexus>`.
- :ref:`Rebin <algm-Rebin>` now support reverse logarithmic binning.
- :ref:`Rebin <algm-Rebin>` now support reverse logarithmic
and inverse power
binning.
Bugfixes
########
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment