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