Mantid
Loading...
Searching...
No Matches
RebinRagged2.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2023 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
7
9
15#include "MantidHistogramData/HistogramBuilder.h"
16#include "MantidHistogramData/Rebin.h"
19
20#include <utility>
21
22namespace Mantid::Algorithms {
23
24// Register the algorithm into the AlgorithmFactory
25DECLARE_ALGORITHM(RebinRagged)
26
27using namespace API;
28using namespace Kernel;
29using DataObjects::EventList;
30using DataObjects::EventWorkspace;
32using HistogramData::HistogramBuilder;
33
34//----------------------------------------------------------------------------------------------
35
37const std::string RebinRagged::name() const { return "RebinRagged"; }
38
40int RebinRagged::version() const { return 2; }
41
43const std::string RebinRagged::category() const { return "Transforms\\Splitting"; }
44
46const std::string RebinRagged::summary() const {
47 return "Rebin each spectrum of a workspace independently. There is only one delta allowed per spectrum";
48}
49
50//----------------------------------------------------------------------------------------------
54 declareProperty(std::make_unique<WorkspaceProperty<>>("InputWorkspace", "", Direction::Input), "input workspace");
55 declareProperty(std::make_unique<WorkspaceProperty<>>("OutputWorkspace", "", Direction::Output), "output workspace");
56
57 declareProperty(std::make_unique<ArrayProperty<double>>("XMin"), "minimum x values with NaN meaning no minimum");
58 declareProperty(std::make_unique<ArrayProperty<double>>("XMax"), "maximum x values with NaN meaning no maximum");
59 declareProperty(std::make_unique<ArrayProperty<double>>("Delta"), "step parameter for rebin");
60 declareProperty("PreserveEvents", true, "False converts event workspaces to histograms");
61 declareProperty("FullBinsOnly", false, "Omit the final bin if it's width is smaller than the step size");
62}
63
64std::map<std::string, std::string> RebinRagged::validateInputs() {
65 std::map<std::string, std::string> errors;
66
67 const std::vector<double> xmins = getProperty("XMin");
68 const std::vector<double> xmaxs = getProperty("XMax");
69 const std::vector<double> deltas = getProperty("Delta");
70
71 const auto numMin = xmins.size();
72 const auto numMax = xmaxs.size();
73 const auto numDelta = deltas.size();
74
75 if (std::any_of(deltas.cbegin(), deltas.cend(), [](double d) { return !std::isfinite(d); }))
76 errors["Delta"] = "All must be finite";
77 else if (std::any_of(deltas.cbegin(), deltas.cend(), [](double d) { return d == 0; }))
78 errors["Delta"] = "All must be nonzero";
79
80 MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace");
81
82 if (inputWS) {
83 const auto histnumber = inputWS->getNumberHistograms();
84
85 if (numDelta == 0)
86 errors["Delta"] = "Must specify binning";
87 else if (!(numDelta == 1 || numDelta == histnumber))
88 errors["Delta"] =
89 "Must specify for each spetra (" + std::to_string(numDelta) + "!=" + std::to_string(histnumber) + ")";
90
91 if (numMin > 1 && numMin != histnumber)
92 errors["XMin"] =
93 "Must specify min for each spectra (" + std::to_string(numMin) + "!=" + std::to_string(histnumber) + ")";
94
95 if (numMax > 1 && numMax != histnumber)
96 errors["XMax"] =
97 "Must specify max for each spectra (" + std::to_string(numMax) + "!=" + std::to_string(histnumber) + ")";
98 } else
99 errors["InputWorkspace"] = "InputWorkspace is not a MatrixWorkspace";
100
101 return errors;
102}
103
104//----------------------------------------------------------------------------------------------
108 MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace");
109 MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace");
110
111 bool preserveEvents = getProperty("PreserveEvents");
112 bool fullBinsOnly = getProperty("FullBinsOnly");
113
114 // Rebinning in-place
115 bool inPlace = (inputWS == outputWS);
116
117 // workspace independent determination of length
118 const auto histnumber = static_cast<int>(inputWS->getNumberHistograms());
119
120 std::vector<double> xmins = getProperty("XMin");
121 std::vector<double> xmaxs = getProperty("XMax");
122 std::vector<double> deltas = getProperty("Delta");
123
124 if (use_simple_rebin(xmins, xmaxs, deltas)) {
125 g_log.information("Using Rebin instead");
126 auto rebin = createChildAlgorithm("Rebin", 0.0, 1.0);
127 rebin->setProperty("InputWorkspace", inputWS);
128 rebin->setProperty("PreserveEvents", preserveEvents);
129 rebin->setProperty("FullBinsOnly", fullBinsOnly);
130 const std::vector<double> params = {xmins[0], deltas[0], xmaxs[0]};
131 rebin->setProperty("Params", params);
132 rebin->execute();
133
134 MatrixWorkspace_sptr output = rebin->getProperty("OutputWorkspace");
135 setProperty("OutputWorkspace", output);
136 return;
137 }
138
139 extend_value(histnumber, xmins);
140 extend_value(histnumber, xmaxs);
141 extend_value(histnumber, deltas);
142
143 // replace NaN and infinity with X min/max
144 for (int hist = 0; hist < histnumber; hist++) {
145 const auto inX = inputWS->x(hist);
146 if (!std::isfinite(xmins[hist]))
147 xmins[hist] = inX.front();
148 if (!std::isfinite(xmaxs[hist]))
149 xmaxs[hist] = inX.back();
150 }
151
152 const bool dist = inputWS->isDistribution();
153
154 // Now, determine if the input workspace is an EventWorkspace
155 EventWorkspace_const_sptr eventInputWS = std::dynamic_pointer_cast<const EventWorkspace>(inputWS);
156
157 if (eventInputWS) {
158 //------- EventWorkspace as input -------------------------------------
159 if (preserveEvents) {
160 if (!inPlace) {
161 outputWS = inputWS->clone();
162 }
163 auto eventOutputWS = std::dynamic_pointer_cast<EventWorkspace>(outputWS);
164
165 for (int hist = 0; hist < histnumber; hist++) {
166 auto xmin = xmins[hist];
167 auto xmax = xmaxs[hist];
168 const auto delta = deltas[hist];
169
170 std::vector<double> xAxisTmp;
171 VectorHelper::createAxisFromRebinParams({xmin, delta, xmax}, xAxisTmp, true, fullBinsOnly);
172 HistogramData::BinEdges XValues_new(std::move(xAxisTmp));
173 EventList &el = eventOutputWS->getSpectrum(hist);
174 el.setHistogram(XValues_new);
175 }
176 } else {
177 //--------- not preserving Events
178 g_log.information() << "Creating a Workspace2D from the EventWorkspace " << eventInputWS->getName() << ".\n";
179
180 outputWS = DataObjects::create<DataObjects::Workspace2D>(*inputWS);
181
182 Progress prog(this, 0.0, 1.0, histnumber);
183
184 // Go through all the histograms and set the data
185 PARALLEL_FOR_IF(Kernel::threadSafe(*inputWS, *outputWS))
186 for (int hist = 0; hist < histnumber; ++hist) {
188 auto xmin = xmins[hist];
189 auto xmax = xmaxs[hist];
190 const auto delta = deltas[hist];
191
192 // Get a const event list reference. eventInputWS->dataY() doesn't work.
193 const EventList &el = eventInputWS->getSpectrum(hist);
194
195 std::vector<double> xAxisTmp;
196 VectorHelper::createAxisFromRebinParams({xmin, delta, xmax}, xAxisTmp, true, fullBinsOnly);
197 HistogramData::BinEdges XValues_new(std::move(xAxisTmp));
198
199 MantidVec y_data, e_data;
200 // The EventList takes care of histogramming.
201 el.generateHistogram(delta, std::as_const(XValues_new), y_data, e_data);
202
203 // Create and set the output histogram
204 HistogramBuilder builder;
205 builder.setX(XValues_new.rawData());
206 builder.setY(y_data);
207 builder.setE(e_data);
208 builder.setDistribution(dist);
209 outputWS->setHistogram(hist, builder.build());
210
211 prog.report();
213 }
215 }
216 } // END ---- EventWorkspace
217
218 else
219
220 { //------- Workspace2D or other MatrixWorkspace ---------------------------
221 const bool isHist = inputWS->isHistogramData();
222
223 if (!isHist) {
224 // convert input to histogram
225 inputWS = inputWS->clone();
226 for (int hist = 0; hist < histnumber; ++hist) {
227 HistogramBuilder builder;
228 builder.setX(inputWS->histogram(hist).binEdges().rawData());
229 builder.setY(inputWS->y(hist));
230 builder.setE(inputWS->e(hist));
231 if (inputWS->hasDx(dist))
232 builder.setDx(inputWS->dx(hist));
233 builder.setDistribution(dist);
234 inputWS->setHistogram(hist, builder.build());
235 }
236 }
237
238 // make output Workspace the same type as the input
239 outputWS = DataObjects::create<API::HistoWorkspace>(*inputWS);
240
241 Progress prog(this, 0.0, 1.0, histnumber);
242
243 PARALLEL_FOR_IF(Kernel::threadSafe(*inputWS, *outputWS))
244 for (int hist = 0; hist < histnumber; ++hist) {
246 auto xmin = xmins[hist];
247 auto xmax = xmaxs[hist];
248 const auto delta = deltas[hist];
249
250 std::vector<double> xAxisTmp;
251 VectorHelper::createAxisFromRebinParams({xmin, delta, xmax}, xAxisTmp, true, fullBinsOnly);
252 HistogramData::BinEdges XValues_new(std::move(xAxisTmp));
253
254 outputWS->setHistogram(hist, HistogramData::rebin(inputWS->histogram(hist), XValues_new));
255 prog.report();
257 }
259 outputWS->setDistribution(dist);
260
261 // Now propagate any masking correctly to the output workspace
262 // More efficient to have this in a separate loop because
263 // MatrixWorkspace::maskBins blocks multi-threading
264 for (int hist = 0; hist < histnumber; ++hist) {
265 if (inputWS->hasMaskedBins(hist)) // Does the current spectrum have any masked bins?
266 {
267 outputWS->setUnmaskedBins(hist);
268 this->propagateMasks(inputWS, outputWS, hist);
269 }
270 }
271
272 if (!isHist) {
273 // convert output to point data
274 for (int hist = 0; hist < histnumber; ++hist) {
275 HistogramBuilder builder;
276 builder.setX(outputWS->histogram(hist).points().rawData());
277 builder.setY(outputWS->y(hist));
278 builder.setE(outputWS->e(hist));
279 if (outputWS->hasDx(hist))
280 builder.setDx(outputWS->dx(hist));
281 builder.setDistribution(dist);
282 outputWS->setHistogram(hist, builder.build());
283 }
284 }
285 } // END ---- Workspace2D
286
287 setProperty("OutputWorkspace", outputWS);
288}
289
290bool RebinRagged::use_simple_rebin(std::vector<double> xmins, std::vector<double> xmaxs, std::vector<double> deltas) {
291 if (xmins.size() == 1 && xmaxs.size() == 1 && deltas.size() == 1)
292 return true;
293
294 if (xmins.size() == 0 || xmaxs.size() == 0 || deltas.size() == 0)
295 return false;
296
297 // is there (effectively) only one xmin?
298 if (!std::equal(xmins.cbegin() + 1, xmins.cend(), xmins.cbegin()))
299 return false;
300
301 // is there (effectively) only one xmax?
302 if (!std::equal(xmaxs.cbegin() + 1, xmaxs.cend(), xmaxs.cbegin()))
303 return false;
304
305 // is there (effectively) only one delta?
306 if (!std::equal(deltas.cbegin() + 1, deltas.cend(), deltas.cbegin()))
307 return false;
308
309 // all of these point to 'just do rebin'
310 return true;
311}
312
313void RebinRagged::extend_value(int histnumber, std::vector<double> &array) {
314 if (array.size() == 0) {
315 array.resize(histnumber, std::numeric_limits<double>::quiet_NaN());
316 } else if (array.size() == 1) {
317 array.resize(histnumber, array[0]);
318 }
319}
320} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:542
#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 setHistogram(T &&...data)
Sets the Histogram associated with this spectrum.
Definition ISpectrum.h:110
Helper class for reporting progress from algorithms.
Definition Progress.h:25
A property class for workspaces.
std::map< std::string, std::string > validateInputs() override
Validate that the input properties are sane.
static void extend_value(int numSpec, std::vector< double > &array)
static bool use_simple_rebin(std::vector< double > xmins, std::vector< double > xmaxs, std::vector< double > deltas)
void exec() override
Execute the algorithm.
const std::string name() const override
Algorithms name for identification.
const std::string category() const override
Algorithm's category for identification.
const std::string summary() const override
Algorithm's summary for use in the GUI and help.
void init() override
Initialize the algorithm's properties.
int version() const override
Algorithm's version for identification.
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...
Definition Rebin.cpp:438
A class for holding :
Definition EventList.h:58
void generateHistogram(std::span< double const > X, MantidVec &Y, MantidVec &E, bool skipError=false) const override
Generates both the Y and E (error) histograms w.r.t TOF for an EventList with or without WeightedEven...
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 information(const std::string &msg)
Logs at information level.
Definition Logger.cpp:136
void report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
Kernel::Logger g_log("DetermineSpinStateOrder")
std::shared_ptr< const EventWorkspace > EventWorkspace_const_sptr
shared pointer to a const Workspace2D
void MANTID_KERNEL_DLL rebin(std::span< double const > xold, std::span< double const > yold, std::span< double const > eold, std::span< double const > xnew, std::span< double > ynew, std::span< double > enew, bool distribution, bool addition=false)
The input and output ranges are taken as spans so that the size-checked histogram data types,...
std::size_t 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 bool useReverseLogarithmic=false, const double power=-1)
Creates a new output X array given a 'standard' set of rebinning parameters.
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.
std::vector< double > MantidVec
typedef for the data storage used in Mantid matrix workspaces
Definition cow_ptr.h:172
std::string to_string(const wide_integer< Bits, Signed > &n)
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54