Mantid
Loading...
Searching...
No Matches
ImportMDHistoWorkspaceBase.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
19#include <algorithm>
20#include <boost/algorithm/string.hpp>
21#include <boost/regex.hpp>
22
23using namespace Mantid::API;
24using namespace Mantid::DataObjects;
25using namespace Mantid::Geometry;
26using namespace Mantid::Kernel;
27using boost::regex;
28
29namespace Mantid::MDAlgorithms {
30
34struct Product {
35 Product() : result(1) {}
36 size_t result;
37 void operator()(size_t x) { result *= x; }
38};
39
40//----------------------------------------------------------------------------------------------
44 auto validator = std::make_shared<CompositeValidator>();
45 validator->add(std::make_shared<BoundedValidator<int>>(1, 9));
46 validator->add(std::make_shared<MandatoryValidator<int>>());
47
48 declareProperty(std::make_unique<PropertyWithValue<int>>("Dimensionality", -1, validator, Direction::Input),
49 "Dimensionality of the data in the file.");
50
51 declareProperty(std::make_unique<ArrayProperty<double>>("Extents"),
52 "A comma separated list of min, max for each dimension,\n"
53 "specifying the extents of each dimension.");
54
55 declareProperty(std::make_unique<ArrayProperty<int>>("NumberOfBins"), "Number of bin in each dimension.");
56
57 declareProperty(std::make_unique<ArrayProperty<std::string>>("Names"),
58 "A comma separated list of the name of each dimension. "
59 "e.g. ('[H,0,0]','[0,K,0]','[0,0,L]') ");
60
61 declareProperty(std::make_unique<ArrayProperty<std::string>>("Units"),
62 "A comma separated list of the units of each dimension.");
63
64 declareProperty(std::make_unique<WorkspaceProperty<IMDHistoWorkspace>>("OutputWorkspace", "", Direction::Output),
65 "MDHistoWorkspace reflecting the input text file.");
66 declareProperty(std::make_unique<ArrayProperty<std::string>>("Frames"),
67 " A comma separated list of the frames of each dimension. "
68 " The frames can be"
69 " **General Frame**: Any frame which is not a Q-based frame."
70 " **QLab**: Wave-vector converted into the lab frame."
71 " **QSample**: Wave-vector converted into the frame of the sample."
72 " **HKL**: Wave-vector converted into the crystal's HKL indices."
73 " Note if nothing is specified then the **General Frame** is being "
74 "selected. Also note that if you select a frame then this might override "
75 "your unit selection if it is not compatible with the frame.");
76}
77
78//----------------------------------------------------------------------------------------------
84 // Fetch input properties
85 size_t ndims;
86 {
87 int ndims_int = getProperty("Dimensionality");
88 ndims = ndims_int;
89 }
90 std::vector<double> extents = getProperty("Extents");
91 std::vector<int> nbins = getProperty("NumberOfBins");
92 std::string dimensions_string = getPropertyValue("Names");
93 std::vector<std::string> names = parseNames(dimensions_string);
94 std::vector<std::string> units = getProperty("Units");
95 std::vector<std::string> frames = getProperty("Frames");
96
97 // Perform all validation on inputs
98 if (extents.size() != ndims * 2)
99 throw std::invalid_argument("You must specify twice as many extents "
100 "(min,max) as there are dimensions.");
101 if (nbins.size() != ndims)
102 throw std::invalid_argument("You must specify as number of bins as there are dimensions.");
103 if (names.size() != ndims)
104 throw std::invalid_argument("You must specify as many names as there are dimensions.");
105 if (units.size() != ndims)
106 throw std::invalid_argument("You must specify as many units as there are dimensions.");
107
108 // If no frames are specified we want to default to the General Frame,
109 // to ensure backward compatibility. But if they are only partly specified,
110 // then we want to throw an error. It should be either used correctly or not
111 // at all
112 if (!frames.empty() && frames.size() != ndims) {
113 throw std::invalid_argument("You must specify as many frames as there are dimensions.");
114 }
115
116 if (frames.empty()) {
117 frames.resize(ndims);
118 std::fill(frames.begin(), frames.end(), GeneralFrame::GeneralFrameName);
119 }
120
121 // Fabricate new dimensions from inputs
122 std::vector<MDHistoDimension_sptr> dimensions;
123 for (size_t k = 0; k < ndims; ++k) {
124 auto frame = createMDFrame(frames[k], units[k]);
125 dimensions.emplace_back(
126 MDHistoDimension_sptr(new MDHistoDimension(names[k], names[k], *frame, static_cast<coord_t>(extents[k * 2]),
127 static_cast<coord_t>(extents[(k * 2) + 1]), nbins[k])));
128 }
129
130 // Calculate the total number of bins by multiplying across each dimension.
131 Product answer = std::for_each(nbins.begin(), nbins.end(), Product());
132 m_bin_product = answer.result;
133
134 MDHistoWorkspace_sptr ws(new MDHistoWorkspace(dimensions));
135 return ws;
136}
137
144MDFrame_uptr ImportMDHistoWorkspaceBase::createMDFrame(const std::string &frame, const std::string &unit) {
145 auto frameFactory = makeMDFrameFactoryChain();
146 MDFrameArgument frameArg(frame, unit);
147 return frameFactory->create(frameArg);
148}
149
150std::map<std::string, std::string> ImportMDHistoWorkspaceBase::validateInputs() {
151 // Check Frame names
152 std::map<std::string, std::string> errors;
153 std::string framePropertyName = "Frames";
154 std::vector<std::string> frames = getProperty(framePropertyName);
155 int ndims_prop = getProperty("Dimensionality");
156 auto ndims = static_cast<size_t>(ndims_prop);
157
158 std::vector<std::string> targetFrames;
159 targetFrames.emplace_back(Mantid::Geometry::GeneralFrame::GeneralFrameName);
160 targetFrames.emplace_back(Mantid::Geometry::HKL::HKLName);
161 targetFrames.emplace_back(Mantid::Geometry::QLab::QLabName);
162 targetFrames.emplace_back(Mantid::Geometry::QSample::QSampleName);
163
164 auto isValidFrame = true;
165 for (auto &frame : frames) {
166 auto result = checkIfFrameValid(frame, targetFrames);
167 if (!result) {
168 isValidFrame = result;
169 }
170 }
171
172 if (!frames.empty() && frames.size() != ndims) {
173 isValidFrame = false;
174 }
175
176 if (!isValidFrame) {
177 std::string message = "The selected frames can be 'HKL', 'QSample', 'QLab' "
178 "or 'General Frame'. You must specify as many frames "
179 "as there are dimensions.";
180 errors.emplace(framePropertyName, message);
181 }
182 return errors;
183}
184
192 const std::vector<std::string> &targetFrames) {
193 return std::any_of(targetFrames.cbegin(), targetFrames.cend(),
194 [&frame](const auto &targetFrame) { return targetFrame == frame; });
195}
196
197/*
198 * The list of dimension names often looks like "[H,0,0],[0,K,0]" with "[H,0,0]"
199 * being the first dimension but getProperty returns a vector of
200 * the string split on every comma
201 * This function parses the string, and does not split on commas within brackets
202 */
203std::vector<std::string> ImportMDHistoWorkspaceBase::parseNames(const std::string &names_string) {
204
205 // This regex has two parts which are separated by the "|" (or)
206 // The first part matches anything which is bounded by square brackets
207 // unless they contain square brackets (so that it only matches inner pairs)
208 // The second part matches anything that doesn't contain a comma
209 // NB, the order of the two parts matters
210
211 regex expression(R"(\[([^\[]*)\]|[^,]+)");
212
213 boost::sregex_token_iterator iter(names_string.begin(), names_string.end(), expression, 0);
214 boost::sregex_token_iterator end;
215
216 std::vector<std::string> names_result(iter, end);
217
218 return names_result;
219}
220
221} // namespace Mantid::MDAlgorithms
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
Definition: Algorithm.cpp:1913
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
Definition: Algorithm.cpp:2026
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Definition: Algorithm.cpp:2076
A property class for workspaces.
static const std::string GeneralFrameName
Definition: GeneralFrame.h:25
static const std::string HKLName
Definition: HKL.h:27
Input argument type for MDFrameFactory chainable factory.
static const std::string QLabName
Definition: QLab.h:35
static const std::string QSampleName
Definition: QSample.h:23
Support for a property that holds an array of values.
Definition: ArrayProperty.h:28
BoundedValidator is a validator that requires the values to be between upper or lower bounds,...
Validator to check that a property is not left empty.
The concrete, templated class for properties.
std::vector< int > nbins
Vector containing the number of bins in each dimension.
void initGenericImportProps()
Initialise the properties associated with the generic import (those to do with dimensionality).
std::map< std::string, std::string > validateInputs() override
Perform validation of ALL the input properties of the algorithm.
Mantid::Geometry::MDFrame_uptr createMDFrame(const std::string &frame, const std::string &unit)
Create an MDFrame.
std::vector< std::string > parseNames(const std::string &names_string)
bool checkIfFrameValid(const std::string &frame, const std::vector< std::string > &targetFrames)
Check if the specified frame matches a target frame.
DataObjects::MDHistoWorkspace_sptr createEmptyOutputWorkspace()
Creates an empty md histo workspace (with dimensions)
std::shared_ptr< MDHistoWorkspace > MDHistoWorkspace_sptr
A shared pointer to a MDHistoWorkspace.
std::unique_ptr< MDFrame > MDFrame_uptr
Definition: MDFrame.h:36
MDFrameFactory_uptr MANTID_GEOMETRY_DLL makeMDFrameFactoryChain()
Make a complete factory chain.
std::shared_ptr< MDHistoDimension > MDHistoDimension_sptr
Shared pointer to a MDHistoDimension.
float coord_t
Typedef for the data type to use for coordinate axes in MD objects such as MDBox, MDEventWorkspace,...
Definition: MDTypes.h:27
@ Input
An input workspace.
Definition: Property.h:53
@ Output
An output workspace.
Definition: Property.h:54
Functor to compute the product of the set.