Mantid
Loading...
Searching...
No Matches
CreateWorkspace.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 +
8
13#include "MantidAPI/TextAxis.h"
16#include "MantidHistogramData/HistogramBuilder.h"
17#include "MantidIndexing/GlobalSpectrumIndex.h"
18#include "MantidIndexing/IndexInfo.h"
19#include "MantidIndexing/SpectrumIndexSet.h"
26
27namespace Mantid::Algorithms {
28
29using namespace Kernel;
30using namespace API;
31using namespace DataObjects;
32using namespace HistogramData;
33using namespace Indexing;
34
35DECLARE_ALGORITHM(CreateWorkspace)
36
37
38void CreateWorkspace::init() {
39
40 std::vector<std::string> unitOptions = UnitFactory::Instance().getKeys();
41 unitOptions.emplace_back("SpectraNumber");
42 unitOptions.emplace_back("Text");
43
44 declareProperty(std::make_unique<WorkspaceProperty<>>("OutputWorkspace", "", Direction::Output),
45 "Name to be given to the created workspace.");
46
47 auto required = std::make_shared<MandatoryValidator<std::vector<double>>>();
48 declareProperty(std::make_unique<ArrayProperty<double>>("DataX", required), "X-axis data values for workspace.");
49 declareProperty(std::make_unique<ArrayProperty<double>>("DataY", required),
50 "Y-axis data values for workspace (measures).");
51 declareProperty(std::make_unique<ArrayProperty<double>>("DataE"), "Error values for workspace.");
52 declareProperty(std::make_unique<PropertyWithValue<int>>("NSpec", 1), "Number of spectra to divide data into.");
53 declareProperty("UnitX", "", "The unit to assign to the XAxis");
54
55 declareProperty("VerticalAxisUnit", "SpectraNumber", std::make_shared<StringListValidator>(unitOptions),
56 "The unit to assign to the second Axis (leave blank for "
57 "default Spectra number)");
58 declareProperty(std::make_unique<ArrayProperty<std::string>>("VerticalAxisValues"), "Values for the VerticalAxis.");
59
60 declareProperty(std::make_unique<PropertyWithValue<bool>>("Distribution", false),
61 "Whether OutputWorkspace should be marked as a distribution.");
62 declareProperty("YUnitLabel", "", "Label for Y Axis");
63
64 declareProperty("WorkspaceTitle", "", "Title for Workspace");
65
66 declareProperty(
67 std::make_unique<WorkspaceProperty<>>("ParentWorkspace", "", Direction::Input, PropertyMode::Optional),
68 "Name of a parent workspace.");
69 declareProperty(std::make_unique<ArrayProperty<double>>("Dx"), "X error values for workspace (optional).");
70 declareProperty("ParallelStorageMode", "",
71 "The parallel storage mode of the output workspace for MPI builds. This paramter has been deprecated "
72 "and will be ignored because MPI support has been removed from Mantid. ");
73}
74
76std::map<std::string, std::string> CreateWorkspace::validateInputs() {
77 std::map<std::string, std::string> issues;
78
79 const std::string vUnit = getProperty("VerticalAxisUnit");
80 const std::vector<std::string> vAxis = getProperty("VerticalAxisValues");
81
82 if (vUnit == "SpectraNumber" && !vAxis.empty())
83 issues["VerticalAxisValues"] = "Axis values cannot be provided when using a spectra axis";
84
85 return issues;
86}
87
90 // Contortions to get at the vector in the property without copying it
91 const Property *const dataXprop = getProperty("DataX");
92 const Property *const dataYprop = getProperty("DataY");
93 const Property *const dataEprop = getProperty("DataE");
94 const Property *const errorDxprop = getProperty("Dx");
95
96 const auto xCheck = dynamic_cast<const ArrayProperty<double> *>(dataXprop);
97 if (!xCheck)
98 throw std::invalid_argument("DataX cannot be casted to a double vector");
99 const std::vector<double> &dataX = *xCheck;
100
101 const auto yCheck = dynamic_cast<const ArrayProperty<double> *>(dataYprop);
102 if (!yCheck)
103 throw std::invalid_argument("DataY cannot be casted to a double vector");
104 const std::vector<double> &dataY = *yCheck;
105
106 const auto eCheck = dynamic_cast<const ArrayProperty<double> *>(dataEprop);
107 if (!eCheck)
108 throw std::invalid_argument("DataE cannot be casted to a double vector");
109 const std::vector<double> &dataE = *eCheck;
110
111 const auto dxCheck = dynamic_cast<const ArrayProperty<double> *>(errorDxprop);
112 if (!dxCheck)
113 throw std::invalid_argument("Dx cannot be casted to a double vector");
114 const std::vector<double> &dX = *dxCheck;
115
116 const int nSpec = getProperty("NSpec");
117 const std::string xUnit = getProperty("UnitX");
118 const std::string vUnit = getProperty("VerticalAxisUnit");
119 const std::vector<std::string> vAxis = getProperty("VerticalAxisValues");
120
121 // Verify the size of the vertical axis.
122 const auto vAxisSize = static_cast<int>(vAxis.size());
123 if (vUnit != "SpectraNumber") {
124 // In the case of numerical axis, the vertical axis can represent either
125 // point data or bin edges.
126 if ((vUnit == "Text" && vAxisSize != nSpec) || (vAxisSize != nSpec && vAxisSize != nSpec + 1)) {
127 throw std::invalid_argument("The number of vertical axis values doesn't "
128 "match the number of histograms.");
129 }
130 }
131
132 // Verify length of vectors makes sense with NSpec
133 if ((dataY.size() % nSpec) != 0) {
134 throw std::invalid_argument("Length of DataY must be divisible by NSpec");
135 }
136 const std::size_t ySize = dataY.size() / nSpec;
137
138 // Check whether the X values provided are to be re-used for (are common to)
139 // every spectrum
140 const bool commonX(dataX.size() == ySize || dataX.size() == ySize + 1);
141
142 std::size_t xSize{dataX.size()};
143 HistogramBuilder histogramBuilder;
144 if (commonX) {
145 histogramBuilder.setX(dataX);
146 } else {
147 if (xSize % nSpec != 0) {
148 throw std::invalid_argument("Length of DataX must be divisible by NSpec");
149 }
150 xSize /= nSpec;
151 histogramBuilder.setX(xSize);
152 }
153 histogramBuilder.setY(ySize);
154
155 if (!dX.empty()) {
156 if (dX.size() != dataY.size())
157 throw std::runtime_error("Dx must have the same size as DataY");
158 histogramBuilder.setDx(ySize);
159 }
160
161 histogramBuilder.setDistribution(getProperty("Distribution"));
162 auto histogram = histogramBuilder.build();
163
164 const bool dataE_provided = !dataE.empty();
165 if (dataE_provided && dataY.size() != dataE.size()) {
166 throw std::runtime_error("DataE (if provided) must be the same size as DataY");
167 }
168
169 // Create the OutputWorkspace
170 MatrixWorkspace_const_sptr parentWS = getProperty("ParentWorkspace");
171 MatrixWorkspace_sptr outputWS;
172 if (parentWS) {
173 outputWS = create<HistoWorkspace>(*parentWS, nSpec, histogram);
174 } else {
175 g_log.warning()
176 << "MPI support has been removed from Mantid. ParallelStorageMode has been deprecated and will be ignored.";
177 IndexInfo indexInfo(nSpec);
178 outputWS = create<Workspace2D>(indexInfo, histogram);
179 }
180
181 Progress progress(this, 0.0, 1.0, nSpec);
182 const auto &indexInfo = outputWS->indexInfo();
183
185 for (int i = 0; i < nSpec; i++) {
187
188 const auto localIndices = indexInfo.makeIndexSet({static_cast<GlobalSpectrumIndex>(i)});
189 if (localIndices.empty())
190 continue;
191
192 const std::vector<double>::difference_type xStart = i * xSize;
193 const std::vector<double>::difference_type xEnd = xStart + xSize;
194 const std::vector<double>::difference_type yStart = i * ySize;
195 const std::vector<double>::difference_type yEnd = yStart + ySize;
196 auto local_i = localIndices[0];
197
198 // Just set the pointer if common X bins. Otherwise, copy in the right chunk
199 // (as we do for Y).
200 if (!commonX)
201 outputWS->mutableX(local_i).assign(dataX.begin() + xStart, dataX.begin() + xEnd);
202
203 outputWS->mutableY(local_i).assign(dataY.begin() + yStart, dataY.begin() + yEnd);
204
205 if (dataE_provided)
206 outputWS->mutableE(local_i).assign(dataE.begin() + yStart, dataE.begin() + yEnd);
207
208 if (!dX.empty())
209 outputWS->mutableDx(local_i).assign(dX.begin() + yStart, dX.begin() + yEnd);
210
211 progress.report();
213 }
215
216 // Set the Unit of the X Axis
217 try {
218 outputWS->getAxis(0)->unit() = UnitFactory::Instance().create(xUnit);
219 } catch (Exception::NotFoundError &) {
220 outputWS->getAxis(0)->unit() = UnitFactory::Instance().create("Label");
221 Unit_sptr unit = outputWS->getAxis(0)->unit();
222 std::shared_ptr<Units::Label> label = std::dynamic_pointer_cast<Units::Label>(unit);
223 label->setLabel(xUnit, xUnit);
224 }
225
226 // Populate the VerticalAxis. A spectra one is there by default with a 1->N
227 // mapping
228 if (vUnit != "SpectraNumber") {
229 if (vUnit == "Text") {
230 auto newAxis = std::make_unique<TextAxis>(vAxis.size());
231 auto newAxisRaw = newAxis.get();
232 outputWS->replaceAxis(1, std::move(newAxis));
233 for (size_t i = 0; i < vAxis.size(); i++) {
234 newAxisRaw->setLabel(i, vAxis[i]);
235 }
236 } else {
237 std::unique_ptr<NumericAxis> newAxis(nullptr);
238 if (vAxisSize == nSpec)
239 newAxis = std::make_unique<NumericAxis>(vAxisSize); // treat as points
240 else if (vAxisSize == nSpec + 1)
241 newAxis = std::make_unique<BinEdgeAxis>(vAxisSize); // treat as bin edges
242 else
243 throw std::range_error("Invalid vertical axis length. It must be the "
244 "same length as NSpec or 1 longer.");
245 auto newAxisRaw = newAxis.get();
246 newAxis->unit() = UnitFactory::Instance().create(vUnit);
247 outputWS->replaceAxis(1, std::move(newAxis));
248 for (size_t i = 0; i < vAxis.size(); i++) {
249 try {
250 newAxisRaw->setValue(i, boost::lexical_cast<double, std::string>(vAxis[i]));
251 } catch (boost::bad_lexical_cast &) {
252 throw std::invalid_argument("CreateWorkspace - YAxisValues property "
253 "could not be converted to a double.");
254 }
255 }
256 }
257 }
258
259 // Set Y Unit label
260 if (!parentWS || !getPropertyValue("YUnitLabel").empty()) {
261 outputWS->setYUnitLabel(getProperty("YUnitLabel"));
262 }
263
264 // Set Workspace Title
265 if (!parentWS || !getPropertyValue("WorkspaceTitle").empty()) {
266 outputWS->setTitle(getProperty("WorkspaceTitle"));
267 }
268
269 // Set OutputWorkspace property
270 setProperty("OutputWorkspace", outputWS);
271}
272} // 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.
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Kernel::Logger & g_log
Definition Algorithm.h:422
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
Helper class for reporting progress from algorithms.
Definition Progress.h:25
A property class for workspaces.
CreateWorkspace Algorithm.
std::map< std::string, std::string > validateInputs() override
Input validation.
void exec() override
Execute the Algorithm.
Support for a property that holds an array of values.
Exception for when an item is not found in a collection.
Definition Exception.h:145
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
The concrete, templated class for properties.
Base class for properties.
Definition Property.h:94
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::shared_ptr< Unit > Unit_sptr
Shared pointer to the Unit base class.
Definition Unit.h:194
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.
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54