Mantid
Loading...
Searching...
No Matches
Workspace2D.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 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 +
9#include "MantidAPI/RefAxis.h"
10#include "MantidAPI/Run.h"
13#include "MantidDataObjects/DllConfig.h"
14#include "MantidHistogramData/LinearGenerator.h"
18
19#include <algorithm>
20#include <sstream>
21
23
24namespace Mantid::DataObjects {
25using std::size_t;
26
27DECLARE_WORKSPACE(Workspace2D)
28
29
31
32Workspace2D::Workspace2D(const Workspace2D &other) : HistoWorkspace(other), m_monitorList(other.m_monitorList) {
33 data.resize(other.data.size());
34 for (size_t i = 0; i < data.size(); ++i) {
35 data[i] = std::make_unique<Histogram1D>(*(other.data[i]));
36 }
37}
38
41
54void Workspace2D::init(const std::size_t &NVectors, const std::size_t &XLength, const std::size_t &YLength) {
55 data.resize(NVectors);
56
57 auto x = Kernel::make_cow<HistogramData::HistogramX>(XLength, HistogramData::LinearGenerator(1.0, 1.0));
58 HistogramData::Counts y(YLength);
59 HistogramData::CountStandardDeviations e(YLength);
60 Histogram1D spec(HistogramData::getHistogramXMode(XLength, YLength), HistogramData::Histogram::YMode::Counts);
61 spec.setSharedX(x);
62 spec.setCounts(y);
64 for (size_t i = 0; i < data.size(); i++) {
65 data[i] = std::make_unique<Histogram1D>(spec);
66 // Default spectrum number = starts at 1, for workspace index 0.
67 data[i]->setSpectrumNo(specnum_t(i + 1));
68 }
69
70 // Add axes that reference the data
71 m_axes.resize(2);
72 m_axes[0] = std::make_unique<API::RefAxis>(this);
73 m_axes[1] = std::make_unique<API::SpectraAxis>(this);
74}
75
76void Workspace2D::init(const HistogramData::Histogram &histogram) {
78
79 HistogramData::Histogram initializedHistogram(histogram);
80 if (!histogram.sharedY()) {
81 if (histogram.yMode() == HistogramData::Histogram::YMode::Frequencies) {
82 initializedHistogram.setFrequencies(histogram.size(), 0.0);
83 initializedHistogram.setFrequencyStandardDeviations(histogram.size(), 0.0);
84 } else { // YMode::Counts or YMode::Uninitialized -> default to Counts
85 initializedHistogram.setCounts(histogram.size(), 0.0);
86 initializedHistogram.setCountStandardDeviations(histogram.size(), 0.0);
87 }
88 }
89
90 Histogram1D spec(initializedHistogram.xMode(), initializedHistogram.yMode());
91 spec.setHistogram(initializedHistogram);
92 std::transform(data.begin(), data.end(), data.begin(),
93 [&spec](const auto &) { return std::make_unique<Histogram1D>(spec); });
94
95 // Add axes that reference the data
96 m_axes.resize(2);
97 m_axes[0] = std::make_unique<API::RefAxis>(this);
98 m_axes[1] = std::make_unique<API::SpectraAxis>(this);
99}
100
104 if (data.empty()) {
105 throw std::runtime_error("There is no data in the Workspace2D, "
106 "therefore cannot determine if it is ragged.");
107 } else {
108 const auto numberOfBins = data[0]->size();
109 return std::any_of(data.cbegin(), data.cend(),
110 [&numberOfBins](const auto &histogram) { return numberOfBins != histogram->size(); });
111 }
112}
113
118
120size_t Workspace2D::size() const {
121 return std::accumulate(
122 data.begin(), data.end(), static_cast<size_t>(0),
123 [](const size_t value, const std::unique_ptr<Histogram1D> &histo) { return value + histo->size(); });
124}
125
128 if (data.empty()) {
129 return 0;
130 } else {
131 size_t numBins = data[0]->size();
132 const auto it =
133 std::find_if_not(data.cbegin(), data.cend(), [numBins](const auto &iter) { return numBins == iter->size(); });
134 if (it != data.cend())
135 throw std::length_error("blocksize undefined because size of histograms is not equal");
136 return numBins;
137 }
138}
139
144std::size_t Workspace2D::getNumberBins(const std::size_t &index) const {
145 if (index < data.size())
146 return data[index]->size();
147
148 throw std::invalid_argument("Could not find number of bins in a histogram at index " + std::to_string(index) +
149 ": index is too large.");
150}
151
155std::size_t Workspace2D::getMaxNumberBins() const {
156 if (data.empty()) {
157 return 0;
158 } else {
159 auto maxNumberOfBins = data[0]->size();
160 for (const auto &iter : data) {
161 const auto numberOfBins = iter->size();
162 if (numberOfBins > maxNumberOfBins)
163 maxNumberOfBins = numberOfBins;
164 }
165 return maxNumberOfBins;
166 }
167}
168
175void Workspace2D::setImageY(const MantidImage &image, size_t start, bool parallelExecution) {
177 setImageYAndE(image, m, start, parallelExecution);
178}
179
186void Workspace2D::setImageE(const MantidImage &image, size_t start, bool parallelExecution) {
188 setImageYAndE(m, image, start, parallelExecution);
189}
190
207void Workspace2D::setImageYAndE(const API::MantidImage &imageY, const API::MantidImage &imageE, size_t start,
208 bool loadAsRectImg, double scale_1, [[maybe_unused]] bool parallelExecution) {
209 if (imageY.empty() && imageE.empty())
210 return;
211 if (imageY.empty() && imageE[0].empty())
212 return;
213 if (imageE.empty() && imageY[0].empty())
214 return;
215
216 const size_t numBins = blocksize();
217 if (!loadAsRectImg && numBins != 1) {
218 throw std::runtime_error("Cannot set image in workspace: a single bin workspace is "
219 "required when initializing a workspace from an "
220 "image using a histogram per pixel.");
221 }
222
223 size_t height;
224 size_t width;
225 if (!imageY.empty()) {
226 height = imageY.size();
227 width = imageY.front().size();
228 } else {
229 height = imageE.size();
230 width = imageE.front().size();
231 }
232 size_t dataSize = width * height;
233
234 if (start + dataSize > getNumberHistograms() * numBins) {
235 throw std::runtime_error("Cannot set image: image is bigger than workspace.");
236 }
237
238 if (!loadAsRectImg) {
239 // 1 pixel - one spectrum
240 PARALLEL_FOR_IF(parallelExecution)
241 for (int i = 0; i < static_cast<int>(height); ++i) {
242
243 const auto &rowY = imageY[i];
244 const auto &rowE = imageE[i];
245 size_t spec = start + static_cast<size_t>(i) * width;
246 auto pE = rowE.begin();
247 for (auto pY = rowY.begin(); pY != rowY.end() && pE != rowE.end(); ++pY, ++pE, ++spec) {
248 data[spec]->mutableY()[0] = *pY;
249 data[spec]->mutableE()[0] = *pE;
250 }
251 }
252 } else {
253
254 if (height != (getNumberHistograms()))
255 throw std::runtime_error(std::string("To load an image into a workspace with one spectrum per "
256 "row, then number of spectra (") +
258 ") needs to be equal to the height (rows) of the image (" + std::to_string(height) +
259 ")");
260
261 if (width != numBins)
262 throw std::runtime_error(std::string("To load an image into a workspace with one spectrum per "
263 "row, then number of bins (") +
264 std::to_string(numBins) + ") needs to be equal to the width (columns) of the image (" +
265 std::to_string(width) + ")");
266
267 // one spectrum - one row
268 PARALLEL_FOR_IF(parallelExecution)
269 for (int i = 0; i < static_cast<int>(height); ++i) {
270
271 const auto &rowY = imageY[i];
272 const auto &rowE = imageE[i];
273 data[i]->mutableY() = rowY;
274 data[i]->mutableE() = rowE;
275 }
276 // X values. Set first spectrum and copy/propagate that one to all the other
277 // spectra
278 PARALLEL_FOR_IF(parallelExecution)
279 for (int i = 0; i < static_cast<int>(width) + 1; ++i) {
280 data[0]->mutableX()[i] = i * scale_1;
281 }
282 PARALLEL_FOR_IF(parallelExecution)
283 for (int i = 1; i < static_cast<int>(height); ++i) {
284 data[i]->setSharedX(data[0]->sharedX());
285 }
286 }
287}
288
291 auto &spec = const_cast<Histogram1D &>(static_cast<const Workspace2D &>(*this).getSpectrum(index));
292 spec.setMatrixWorkspace(this, index);
293 return spec;
294}
295
297const Histogram1D &Workspace2D::getSpectrum(const size_t index) const {
298 if (index >= data.size()) {
299 std::ostringstream ss;
300 ss << "Workspace2D::getSpectrum, histogram number " << index << " out of range " << data.size();
301 throw std::range_error(ss.str());
302 }
303 return *data[index];
304}
305
306//--------------------------------------------------------------------------------------------
314size_t Workspace2D::getHistogramNumberHelper() const { return data.size(); }
315
316//---------------------------------------------------------------------------
326void Workspace2D::generateHistogram(const std::size_t index, std::span<double const> X, MantidVec &Y, MantidVec &E,
327 bool skipError) const {
328 UNUSED_ARG(skipError);
329 if (index >= data.size())
330 throw std::range_error("Workspace2D::generateHistogram, histogram number out of range");
331 // output data arrays are implicitly filled by function
332 const auto &spec = this->getSpectrum(index);
333 Mantid::HistogramData::HistogramX const &currentX = spec.x();
334 Mantid::HistogramData::HistogramY const &currentY = spec.y();
335 Mantid::HistogramData::HistogramE const &currentE = spec.e();
336 if (X.size() <= 1)
337 throw std::runtime_error("Workspace2D::generateHistogram(): X vector must be at least length 2");
338 Y.resize(X.size() - 1, 0);
339 E.resize(X.size() - 1, 0);
340
341 // Perform the rebin from the current bins to the new ones
342 if (currentX.size() == currentY.size()) // First, convert to bin boundaries if needed. The
343 { // VectorHelper::rebin, assumes bin boundaries, even if
344 std::vector<double> histX; // it is a distribution!
345 histX.resize(currentX.size() + 1);
347 Mantid::Kernel::VectorHelper::rebin(histX, currentY, currentE, X, Y, E, true);
348 } else // assume x_size = y_size + 1
349 {
350 Mantid::Kernel::VectorHelper::rebin(currentX, currentY, currentE, X, Y, E, this->isDistribution());
351 }
352}
353
354Workspace2D *Workspace2D::doClone() const { return new Workspace2D(*this); }
356} // namespace Mantid::DataObjects
357
358namespace Mantid::Kernel {
359template <>
361IPropertyManager::getValue<Mantid::DataObjects::Workspace2D_sptr>(const std::string &name) const {
362 auto *prop = dynamic_cast<PropertyWithValue<Mantid::DataObjects::Workspace2D_sptr> *>(getPointerToProperty(name));
363 if (prop) {
364 return *prop;
365 } else {
366 std::string message =
367 "Attempt to assign property " + name + " to incorrect type. Expected shared_ptr<Workspace2D>.";
368 throw std::runtime_error(message);
369 }
370}
371
372template <>
374IPropertyManager::getValue<Mantid::DataObjects::Workspace2D_const_sptr>(const std::string &name) const {
375 const auto *prop =
376 dynamic_cast<PropertyWithValue<Mantid::DataObjects::Workspace2D_sptr> *>(getPointerToProperty(name));
377 if (prop) {
378 return prop->operator()();
379 } else {
380 std::string message =
381 "Attempt to assign property " + name + " to incorrect type. Expected const shared_ptr<Workspace2D>.";
382 throw std::runtime_error(message);
383 }
384}
385} // namespace Mantid::Kernel
std::string name
Definition Run.cpp:60
double value
The value of the point.
Definition FitMW.cpp:51
double height
Definition GetAllEi.cpp:155
std::map< DeltaEMode::Type, std::string > index
#define PARALLEL_FOR_IF(condition)
Empty definitions - to enable set your complier to enable openMP.
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
Definition System.h:44
#define DECLARE_WORKSPACE(classname)
size_t numberOfDetectorGroups() const
Returns the number of detector groups.
HistoWorkspace is an abstract base class for MatrixWorkspace types that are NOT event workspaces.
void setHistogram(T &&...data)
Sets the Histogram associated with this spectrum.
Definition ISpectrum.h:110
void setMatrixWorkspace(MatrixWorkspace *matrixWorkspace, const size_t index)
Sets the MatrixWorkspace pointer (pointer to the owning workspace).
void setCountStandardDeviations(T &&...data) &
Definition ISpectrum.h:169
void setCounts(T &&...data) &
Definition ISpectrum.h:160
void setSharedX(const Kernel::cow_ptr< HistogramData::HistogramX > &x) &
Definition ISpectrum.h:203
std::vector< std::unique_ptr< Axis > > m_axes
A vector of pointers to the axes for this workspace.
const HistogramData::HistogramE & e(const size_t index) const
bool isDistribution() const
Are the Y-values dimensioned?
Kernel::cow_ptr< HistogramData::HistogramX > sharedX(const size_t index) const
HistogramData::Histogram histogram(const size_t index) const
Returns the Histogram at the given workspace index.
1D histogram implementation.
Definition Histogram1D.h:19
virtual std::size_t size() const
get pseudo size
Definition Histogram1D.h:87
Concrete workspace implementation.
Definition Workspace2D.h:30
std::size_t getNumberHistograms() const override
Returns the histogram number.
std::size_t size() const override
get pseudo size
bool isRaggedWorkspace() const override
Returns true if the workspace is ragged (has differently sized spectra).
std::vector< std::unique_ptr< Histogram1D > > data
A vector that holds the 1D histograms.
Definition Workspace2D.h:99
std::size_t getMaxNumberBins() const override
Returns the maximum number of bins in a workspace (works on ragged data).
void setImageYAndE(const API::MantidImage &imageY, const API::MantidImage &imageE, size_t start=0, bool loadAsRectImg=false, double scale_1=1.0, bool parallelExecution=true)
Copy the data from an image to this workspace's (Y's) and errors.
void init(const std::size_t &NVectors, const std::size_t &XLength, const std::size_t &YLength) override
Called by initialize()
Workspace2D * doClone() const override
Virtual clone method. Not implemented to force implementation in children.
~Workspace2D() override
Destructor.
virtual std::size_t getHistogramNumberHelper() const
Returns the number of histograms.
void generateHistogram(const std::size_t index, std::span< double const > X, MantidVec &Y, MantidVec &E, bool skipError=false) const override
Generate a new histogram by rebinning the existing histogram.
Histogram1D & getSpectrumWithoutInvalidation(const size_t index) override
Return reference to Histogram1D at the given workspace index.
std::size_t getNumberBins(const std::size_t &index) const override
Returns the number of bins for a given histogram index.
void setImageY(const API::MantidImage &image, size_t start=0, bool parallelExecution=true) override
Copy the data (Y's) from an image to this workspace.
void setImageE(const API::MantidImage &image, size_t start=0, bool parallelExecution=true) override
Copy the data from an image to this workspace's errors.
Histogram1D & getSpectrum(const size_t index) override
Return the underlying ISpectrum ptr at the given workspace index.
Definition Workspace2D.h:64
std::size_t blocksize() const override
get the size of each vector
Workspace2D * doCloneEmpty() const override
Virtual cloneEmpty method.
The concrete, templated class for properties.
std::vector< std::vector< double > > MantidImage
typedef for the image type
std::shared_ptr< Workspace2D > Workspace2D_sptr
shared pointer to Mantid::DataObjects::Workspace2D
std::shared_ptr< const Workspace2D > Workspace2D_const_sptr
shared pointer to Mantid::DataObjects::Workspace2D (const version)
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,...
void MANTID_KERNEL_DLL convertToBinBoundary(std::span< double const > bin_centers, std::vector< double > &bin_edges)
Convert an array of bin centers to bin boundary values.
std::vector< double > MantidVec
typedef for the data storage used in Mantid matrix workspaces
Definition cow_ptr.h:172
int32_t specnum_t
Typedef for a spectrum Number.
Definition IDTypes.h:14
std::string to_string(const wide_integer< Bits, Signed > &n)