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
20namespace Mantid {
21namespace Algorithms {
22
23// Register the algorithm into the AlgorithmFactory
24DECLARE_ALGORITHM(RebinRagged)
25
26using namespace API;
27using namespace Kernel;
28using DataObjects::EventList;
29using DataObjects::EventWorkspace;
31using HistogramData::HistogramBuilder;
32
33//----------------------------------------------------------------------------------------------
34
36const std::string RebinRagged::name() const { return "RebinRagged"; }
37
39int RebinRagged::version() const { return 2; }
40
42const std::string RebinRagged::category() const { return "Transforms\\Splitting"; }
43
45const std::string RebinRagged::summary() const {
46 return "Rebin each spectrum of a workspace independently. There is only one delta allowed per spectrum";
47}
48
49//----------------------------------------------------------------------------------------------
53 declareProperty(std::make_unique<WorkspaceProperty<>>("InputWorkspace", "", Direction::Input), "input workspace");
54 declareProperty(std::make_unique<WorkspaceProperty<>>("OutputWorkspace", "", Direction::Output), "output workspace");
55
56 declareProperty(std::make_unique<ArrayProperty<double>>("XMin"), "minimum x values with NaN meaning no minimum");
57 declareProperty(std::make_unique<ArrayProperty<double>>("XMax"), "maximum x values with NaN meaning no maximum");
58 declareProperty(std::make_unique<ArrayProperty<double>>("Delta"), "step parameter for rebin");
59 declareProperty("PreserveEvents", true, "False converts event workspaces to histograms");
60 declareProperty("FullBinsOnly", false, "Omit the final bin if it's width is smaller than the step size");
61}
62
63std::map<std::string, std::string> RebinRagged::validateInputs() {
64 std::map<std::string, std::string> errors;
65
66 const std::vector<double> xmins = getProperty("XMin");
67 const std::vector<double> xmaxs = getProperty("XMax");
68 const std::vector<double> deltas = getProperty("Delta");
69
70 const auto numMin = xmins.size();
71 const auto numMax = xmaxs.size();
72 const auto numDelta = deltas.size();
73
74 if (std::any_of(deltas.cbegin(), deltas.cend(), [](double d) { return !std::isfinite(d); }))
75 errors["Delta"] = "All must be finite";
76 else if (std::any_of(deltas.cbegin(), deltas.cend(), [](double d) { return d == 0; }))
77 errors["Delta"] = "All must be nonzero";
78
79 MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace");
80
81 if (inputWS) {
82 const auto histnumber = inputWS->getNumberHistograms();
83
84 if (numDelta == 0)
85 errors["Delta"] = "Must specify binning";
86 else if (!(numDelta == 1 || numDelta == histnumber))
87 errors["Delta"] =
88 "Must specify for each spetra (" + std::to_string(numDelta) + "!=" + std::to_string(histnumber) + ")";
89
90 if (numMin > 1 && numMin != histnumber)
91 errors["XMin"] =
92 "Must specify min for each spectra (" + std::to_string(numMin) + "!=" + std::to_string(histnumber) + ")";
93
94 if (numMax > 1 && numMax != histnumber)
95 errors["XMax"] =
96 "Must specify max for each spectra (" + std::to_string(numMax) + "!=" + std::to_string(histnumber) + ")";
97 } else
98 errors["InputWorkspace"] = "InputWorkspace is not a MatrixWorkspace";
99
100 return errors;
101}
102
103//----------------------------------------------------------------------------------------------
107 MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace");
108 MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace");
109
110 bool preserveEvents = getProperty("PreserveEvents");
111 bool fullBinsOnly = getProperty("FullBinsOnly");
112
113 // Rebinning in-place
114 bool inPlace = (inputWS == outputWS);
115
116 // workspace independent determination of length
117 const auto histnumber = static_cast<int>(inputWS->getNumberHistograms());
118
119 std::vector<double> xmins = getProperty("XMin");
120 std::vector<double> xmaxs = getProperty("XMax");
121 std::vector<double> deltas = getProperty("Delta");
122
123 if (use_simple_rebin(xmins, xmaxs, deltas)) {
124 g_log.information("Using Rebin instead");
125 auto rebin = createChildAlgorithm("Rebin", 0.0, 1.0);
126 rebin->setProperty("InputWorkspace", inputWS);
127 rebin->setProperty("PreserveEvents", preserveEvents);
128 rebin->setProperty("FullBinsOnly", fullBinsOnly);
129 const std::vector<double> params = {xmins[0], deltas[0], xmaxs[0]};
130 rebin->setProperty("Params", params);
131 rebin->execute();
132
133 MatrixWorkspace_sptr output = rebin->getProperty("OutputWorkspace");
134 setProperty("OutputWorkspace", output);
135 return;
136 }
137
138 extend_value(histnumber, xmins);
139 extend_value(histnumber, xmaxs);
140 extend_value(histnumber, deltas);
141
142 // replace NaN and infinity with X min/max
143 for (int hist = 0; hist < histnumber; hist++) {
144 const auto inX = inputWS->x(hist);
145 if (!std::isfinite(xmins[hist]))
146 xmins[hist] = inX.front();
147 if (!std::isfinite(xmaxs[hist]))
148 xmaxs[hist] = inX.back();
149 }
150
151 const bool dist = inputWS->isDistribution();
152
153 // Now, determine if the input workspace is an EventWorkspace
154 EventWorkspace_const_sptr eventInputWS = std::dynamic_pointer_cast<const EventWorkspace>(inputWS);
155
156 if (eventInputWS) {
157 //------- EventWorkspace as input -------------------------------------
158 if (preserveEvents) {
159 if (!inPlace) {
160 outputWS = inputWS->clone();
161 }
162 auto eventOutputWS = std::dynamic_pointer_cast<EventWorkspace>(outputWS);
163
164 for (int hist = 0; hist < histnumber; hist++) {
165 auto xmin = xmins[hist];
166 auto xmax = xmaxs[hist];
167 const auto delta = deltas[hist];
168
169 HistogramData::BinEdges XValues_new(0);
170 static_cast<void>(VectorHelper::createAxisFromRebinParams({xmin, delta, xmax}, XValues_new.mutableRawData(),
171 true, fullBinsOnly));
172 EventList &el = eventOutputWS->getSpectrum(hist);
173 el.setHistogram(XValues_new);
174 }
175 } else {
176 //--------- not preserving Events
177 g_log.information() << "Creating a Workspace2D from the EventWorkspace " << eventInputWS->getName() << ".\n";
178
179 outputWS = DataObjects::create<DataObjects::Workspace2D>(*inputWS);
180
181 Progress prog(this, 0.0, 1.0, histnumber);
182
183 // Go through all the histograms and set the data
184 PARALLEL_FOR_IF(Kernel::threadSafe(*inputWS, *outputWS))
185 for (int hist = 0; hist < histnumber; ++hist) {
187 auto xmin = xmins[hist];
188 auto xmax = xmaxs[hist];
189 const auto delta = deltas[hist];
190
191 // Get a const event list reference. eventInputWS->dataY() doesn't work.
192 const EventList &el = eventInputWS->getSpectrum(hist);
193
194 HistogramData::BinEdges XValues_new(0);
195 static_cast<void>(VectorHelper::createAxisFromRebinParams({xmin, delta, xmax}, XValues_new.mutableRawData(),
196 true, fullBinsOnly));
197
198 MantidVec y_data, e_data;
199 // The EventList takes care of histogramming.
200 el.generateHistogram(delta, XValues_new.rawData(), y_data, e_data);
201
202 // Create and set the output histogram
203 HistogramBuilder builder;
204 builder.setX(XValues_new.rawData());
205 builder.setY(y_data);
206 builder.setE(e_data);
207 builder.setDistribution(dist);
208 outputWS->setHistogram(hist, builder.build());
209
210 prog.report();
212 }
214 }
215 } // END ---- EventWorkspace
216
217 else
218
219 { //------- Workspace2D or other MatrixWorkspace ---------------------------
220 const bool isHist = inputWS->isHistogramData();
221
222 if (!isHist) {
223 // convert input to histogram
224 inputWS = inputWS->clone();
225 for (int hist = 0; hist < histnumber; ++hist) {
226 HistogramBuilder builder;
227 builder.setX(inputWS->histogram(hist).binEdges().rawData());
228 builder.setY(inputWS->readY(hist));
229 builder.setE(inputWS->readE(hist));
230 if (inputWS->hasDx(dist))
231 builder.setDx(inputWS->readDx(hist));
232 builder.setDistribution(dist);
233 inputWS->setHistogram(hist, builder.build());
234 }
235 }
236
237 // make output Workspace the same type as the input
238 outputWS = DataObjects::create<API::HistoWorkspace>(*inputWS);
239
240 Progress prog(this, 0.0, 1.0, histnumber);
241
242 PARALLEL_FOR_IF(Kernel::threadSafe(*inputWS, *outputWS))
243 for (int hist = 0; hist < histnumber; ++hist) {
245 auto xmin = xmins[hist];
246 auto xmax = xmaxs[hist];
247 const auto delta = deltas[hist];
248
249 HistogramData::BinEdges XValues_new(0);
250 static_cast<void>(VectorHelper::createAxisFromRebinParams({xmin, delta, xmax}, XValues_new.mutableRawData(), true,
251 fullBinsOnly));
252
253 outputWS->setHistogram(hist, HistogramData::rebin(inputWS->histogram(hist), XValues_new));
254 prog.report();
256 }
258 outputWS->setDistribution(dist);
259
260 // Now propagate any masking correctly to the output workspace
261 // More efficient to have this in a separate loop because
262 // MatrixWorkspace::maskBins blocks multi-threading
263 for (int hist = 0; hist < histnumber; ++hist) {
264 if (inputWS->hasMaskedBins(hist)) // Does the current spectrum have any masked bins?
265 {
266 outputWS->setUnmaskedBins(hist);
267 this->propagateMasks(inputWS, outputWS, hist);
268 }
269 }
270
271 if (!isHist) {
272 // convert output to point data
273 for (int hist = 0; hist < histnumber; ++hist) {
274 HistogramBuilder builder;
275 builder.setX(outputWS->histogram(hist).points().rawData());
276 builder.setY(outputWS->readY(hist));
277 builder.setE(outputWS->readE(hist));
278 if (outputWS->hasDx(hist))
279 builder.setDx(outputWS->readDx(hist));
280 builder.setDistribution(dist);
281 outputWS->setHistogram(hist, builder.build());
282 }
283 }
284 } // END ---- Workspace2D
285
286 setProperty("OutputWorkspace", outputWS);
287}
288
289bool RebinRagged::use_simple_rebin(std::vector<double> xmins, std::vector<double> xmaxs, std::vector<double> deltas) {
290 if (xmins.size() == 1 && xmaxs.size() == 1 && deltas.size() == 1)
291 return true;
292
293 if (xmins.size() == 0 || xmaxs.size() == 0 || deltas.size() == 0)
294 return false;
295
296 // is there (effectively) only one xmin?
297 if (!std::equal(xmins.cbegin() + 1, xmins.cend(), xmins.cbegin()))
298 return false;
299
300 // is there (effectively) only one xmax?
301 if (!std::equal(xmaxs.cbegin() + 1, xmaxs.cend(), xmaxs.cbegin()))
302 return false;
303
304 // is there (effectively) only one delta?
305 if (!std::equal(deltas.cbegin() + 1, deltas.cend(), deltas.cbegin()))
306 return false;
307
308 // all of these point to 'just do rebin'
309 return true;
310}
311
312void RebinRagged::extend_value(int histnumber, std::vector<double> &array) {
313 if (array.size() == 0) {
314 array.resize(histnumber, std::numeric_limits<double>::quiet_NaN());
315 } else if (array.size() == 1) {
316 array.resize(histnumber, array[0]);
317 }
318}
319} // namespace Algorithms
320} // namespace Mantid
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
#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:96
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:437
A class for holding :
Definition EventList.h:57
void generateHistogram(const MantidVec &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
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 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.
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.
Helper class which provides the Collimation Length for SANS instruments.
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