Mantid
Loading...
Searching...
No Matches
MaskMD.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 +
12#include <algorithm>
13#include <boost/algorithm/string.hpp>
14#include <boost/regex.hpp>
15
16using namespace Mantid::Kernel;
17using namespace Mantid::API;
18using namespace Mantid::Geometry;
19using boost::regex;
20
21namespace Mantid::MDAlgorithms {
22
23/*
24 * The list of dimension names often looks like "[H,0,0],[0,K,0]" with "[H,0,0]"
25 * being the first dimension but getProperty returns a vector of
26 * the string split on every comma
27 * This function parses the string, and does not split on commas within brackets
28 */
29std::vector<std::string> parseDimensionNames(const std::string &names_string) {
30
31 // This regex has two parts which are separated by the "|" (or)
32 // The first part matches anything which is bounded by square brackets
33 // unless they contain square brackets (so that it only matches inner pairs)
34 // The second part matches anything that doesn't contain a comma
35 // NB, the order of the two parts matters
36 regex expression(R"(\[([^\[]*)\]|[^,]+)");
37
38 boost::sregex_token_iterator iter(names_string.begin(), names_string.end(), expression, 0);
39 boost::sregex_token_iterator end;
40
41 std::vector<std::string> names_result(iter, end);
42
43 return names_result;
44}
45
46// Register the algorithm into the AlgorithmFactory
48
49
51 double min, max;
52 size_t index;
53};
54
57 bool operator()(const InputArgument &a, const InputArgument &b) const { return a.index < b.index; }
58};
59
60//----------------------------------------------------------------------------------------------
62const std::string MaskMD::name() const { return "MaskMD"; }
63
65int MaskMD::version() const { return 1; }
66
68const std::string MaskMD::category() const { return "MDAlgorithms\\Transforms"; }
69
70//----------------------------------------------------------------------------------------------
71
72//----------------------------------------------------------------------------------------------
76 declareProperty(std::make_unique<PropertyWithValue<bool>>("ClearExistingMasks", true, Direction::Input),
77 "Clears any existing masks before applying the provided masking.");
78 declareProperty(std::make_unique<WorkspaceProperty<IMDWorkspace>>("Workspace", "", Direction::InOut),
79 "An input/output workspace.");
81 "Dimensions", std::make_shared<MandatoryValidator<std::vector<std::string>>>(), Direction::Input),
82 "Dimension ids/names all comma separated.\n"
83 "According to the dimensionality of the workspace, these names will be "
84 "grouped,\n"
85 "so the number of entries must be n*(number of dimensions in the "
86 "workspace).");
87
88 declareProperty(std::make_unique<ArrayProperty<double>>(
89 "Extents", std::make_shared<MandatoryValidator<std::vector<double>>>(), Direction::Input),
90 "Extents {min, max} corresponding to each of the dimensions specified, "
91 "according to the order those identifies have been specified.");
92}
93
104size_t tryFetchDimensionIndex(const Mantid::API::IMDWorkspace_sptr &ws, const std::string &candidateNameOrId) {
105 size_t dimWorkspaceIndex;
106 try {
107 dimWorkspaceIndex = ws->getDimensionIndexById(candidateNameOrId);
108 } catch (const std::runtime_error &) {
109 // this will throw if the name is unknown.
110 dimWorkspaceIndex = ws->getDimensionIndexByName(candidateNameOrId);
111 }
112 return dimWorkspaceIndex;
113}
114
115//----------------------------------------------------------------------------------------------
119 IMDWorkspace_sptr ws = getProperty("Workspace");
120 std::string dimensions_string = getPropertyValue("Dimensions");
121 std::vector<double> extents = getProperty("Extents");
122
123 // Dimension names may contain brackets with commas (i.e. [H,0,0])
124 // so getProperty would return an incorrect vector of names;
125 // instead get the string and parse it here
126 std::vector<std::string> dimensions = parseDimensionNames(dimensions_string);
127 // Report what dimension names were found
128 g_log.debug() << "Dimension names parsed as: \n";
129 for (const auto &name : dimensions) {
130 g_log.debug() << name << '\n';
131 }
132
133 size_t nDims = ws->getNumDims();
134 size_t nDimensionIds = dimensions.size();
135
136 size_t nGroups = nDimensionIds / nDims;
137
138 bool bClearExistingMasks = getProperty("ClearExistingMasks");
139 if (bClearExistingMasks) {
140 ws->clearMDMasking();
141 }
142 this->interruption_point();
143 this->progress(0.0);
144
145 // Explicitly cast nGroups and group to double to avoid compiler warnings
146 // loss of precision does not matter as we are only using the result
147 // for reporting algorithm progress
148 const auto nGroups_double = static_cast<double>(nGroups);
149 // Loop over all groups
150 for (size_t group = 0; group < nGroups; ++group) {
151 std::vector<InputArgument> arguments(nDims);
152
153 // Loop over all arguments within the group. and construct InputArguments
154 // for sorting.
155 for (size_t i = 0; i < nDims; ++i) {
156 size_t index = i + (group * nDims);
157 InputArgument &arg = arguments[i];
158
159 // Try to get the index of the dimension in the workspace.
160 arg.index = tryFetchDimensionIndex(ws, dimensions[index]);
161
162 arg.min = extents[index * 2];
163 arg.max = extents[(index * 2) + 1];
164 }
165
166 // Sort all the inputs by the dimension index. Without this it will not be
167 // possible to construct the MDImplicit function property.
168 LessThanIndex comparator;
169 std::sort(arguments.begin(), arguments.end(), comparator);
170
171 // Create inputs for a box implicit function
172 VMD mins(nDims);
173 VMD maxs(nDims);
174 for (size_t i = 0; i < nDims; ++i) {
175 mins[i] = float(arguments[i].min);
176 maxs[i] = float(arguments[i].max);
177 }
178
179 // Add new masking.
180 ws->setMDMasking(std::make_unique<MDBoxImplicitFunction>(mins, maxs));
181 this->interruption_point();
182 auto group_double = static_cast<double>(group);
183 this->progress(group_double / nGroups_double);
184 }
185 this->progress(1.0); // Ensure algorithm progress is reported as complete
186}
187
188std::map<std::string, std::string> MaskMD::validateInputs() {
189 // Create the map
190 std::map<std::string, std::string> validation_output;
191
192 // Get properties to validate
193 IMDWorkspace_sptr ws = getProperty("Workspace");
194 std::string dimensions_string = getPropertyValue("Dimensions");
195 std::vector<double> extents = getProperty("Extents");
196
197 std::vector<std::string> dimensions = parseDimensionNames(dimensions_string);
198
199 std::stringstream messageStream;
200
201 // Check named dimensions can be found in workspace
202 for (const auto &dimension_name : dimensions) {
203 try {
204 tryFetchDimensionIndex(ws, dimension_name);
205 } catch (const std::runtime_error &) {
206 messageStream << "Dimension '" << dimension_name << "' not found. ";
207 }
208 }
209 if (messageStream.rdbuf()->in_avail() != 0) {
210 validation_output["Dimensions"] = messageStream.str();
211 messageStream.str(std::string());
212 }
213
214 size_t nDims = ws->getNumDims();
215 size_t nDimensionIds = dimensions.size();
216
217 // Check cardinality on names/ids
218 if (nDimensionIds % nDims != 0) {
219 messageStream << "Number of dimension ids/names must be n * " << nDims << ". The following names were given: ";
220 for (const auto &name : dimensions) {
221 messageStream << name << ", ";
222 }
223
224 validation_output["Dimensions"] = messageStream.str();
225 messageStream.str(std::string());
226 }
227
228 // Check cardinality on extents
229 if (extents.size() != (2 * dimensions.size())) {
230 messageStream << "Number of extents must be " << 2 * dimensions.size() << ". ";
231 validation_output["Extents"] = messageStream.str();
232 }
233 // Check extent value provided.
234 for (size_t i = 0; (i < nDimensionIds) && ((i * 2 + 1) < extents.size()); ++i) {
235 double min = extents[i * 2];
236 double max = extents[(i * 2) + 1];
237 if (min > max) {
238 messageStream << "Cannot have minimum extents " << min << " larger than maximum extents " << max << ". ";
239 validation_output["Extents"] = messageStream.str();
240 }
241 }
242
243 return validation_output;
244}
245
246} // namespace Mantid::MDAlgorithms
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
std::map< DeltaEMode::Type, std::string > index
Definition: DeltaEMode.cpp:19
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
Kernel::Logger & g_log
Definition: Algorithm.h:451
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
Definition: Algorithm.cpp:231
void interruption_point()
This is called during long-running operations, and check if the algorithm has requested that it be ca...
Definition: Algorithm.cpp:1687
A property class for workspaces.
Support for a property that holds an array of values.
Definition: ArrayProperty.h:28
void debug(const std::string &msg)
Logs at debug level.
Definition: Logger.cpp:114
Validator to check that a property is not left empty.
The concrete, templated class for properties.
const std::string name() const override
Algorithm's name for identification.
Definition: MaskMD.cpp:62
std::map< std::string, std::string > validateInputs() override
Perform validation of ALL the input properties of the algorithm.
Definition: MaskMD.cpp:188
const std::string category() const override
Algorithm's category for identification.
Definition: MaskMD.cpp:68
void exec() override
Execute the algorithm.
Definition: MaskMD.cpp:118
int version() const override
Algorithm's version for identification.
Definition: MaskMD.cpp:65
void init() override
Initialize the algorithm's properties.
Definition: MaskMD.cpp:75
std::shared_ptr< IMDWorkspace > IMDWorkspace_sptr
Shared pointer to the IMDWorkspace base class.
Definition: IMDWorkspace.h:146
std::vector< std::string > MANTID_MDALGORITHMS_DLL parseDimensionNames(const std::string &names_string)
Definition: MaskMD.cpp:29
size_t tryFetchDimensionIndex(const Mantid::API::IMDWorkspace_sptr &ws, const std::string &candidateNameOrId)
Free helper function.
Definition: MaskMD.cpp:104
@ InOut
Both an input & output workspace.
Definition: Property.h:55
@ Input
An input workspace.
Definition: Property.h:53
Local type to group min, max extents with a dimension index.
Definition: MaskMD.cpp:50
Comparator to allow sorting by dimension index.
Definition: MaskMD.cpp:56
bool operator()(const InputArgument &a, const InputArgument &b) const
Definition: MaskMD.cpp:57