Mantid
Loading...
Searching...
No Matches
ExtractMaskToTable.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 +
14
15namespace Mantid::Algorithms {
16
17using namespace Mantid::API;
18using namespace Mantid::DataObjects;
19using namespace Mantid::Geometry;
20using namespace Mantid::Kernel;
21
22DECLARE_ALGORITHM(ExtractMaskToTable)
23
24//----------------------------------------------------------------------------------------------
27void ExtractMaskToTable::init() {
28 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>("InputWorkspace", "", Direction::Input),
29 "A workspace whose masking is to be extracted or a MaskWorkspace. ");
30
31 declareProperty(std::make_unique<WorkspaceProperty<TableWorkspace>>("MaskTableWorkspace", "", Direction::Input,
33 "A mask table workspace containing 3 columns: "
34 "XMin, XMax and DetectorIDsList. ");
35
36 declareProperty(std::make_unique<WorkspaceProperty<TableWorkspace>>("OutputWorkspace", "", Direction::Output),
37 "A comma separated list or array containing a "
38 "list of masked detector ID's ");
39
40 declareProperty("Xmin", EMPTY_DBL(), "Minimum of X-value.");
41
42 declareProperty("Xmax", EMPTY_DBL(), "Maximum of X-value.");
43}
44
45//----------------------------------------------------------------------------------------------
49 // Get input properties
50 m_dataWS = getProperty("InputWorkspace");
51 if (!m_dataWS)
52 throw std::runtime_error("InputWorkspace cannot be cast to a MatrixWorkspace.");
53 MaskWorkspace_const_sptr maskws = std::dynamic_pointer_cast<const MaskWorkspace>(m_dataWS);
54
55 bool m_inputIsMask = false;
56 if (maskws) {
57 g_log.notice() << "InputWorkspace " << m_dataWS->getName() << " is a MaskWorkspace.\n";
58 m_inputIsMask = true;
59 } else {
60 m_inputIsMask = false;
61 }
62
63 m_inputTableWS = getProperty("MaskTableWorkspace");
64
65 double xmin = getProperty("XMin");
66 double xmax = getProperty("XMax");
67 if (xmin == EMPTY_DBL() || xmax == EMPTY_DBL() || xmin >= xmax)
68 throw std::runtime_error("XMin or XMax cannot be empty. XMin must be less than XMax.");
69
70 // Create and set up output workspace
71 auto outws = std::make_shared<TableWorkspace>();
72 outws->addColumn("double", "XMin");
73 outws->addColumn("double", "XMax");
74 outws->addColumn("str", "DetectorIDsList");
75 setProperty("OutputWorkspace", outws);
76
77 // Optionally import the input table workspace
78 std::vector<detid_t> prevmaskeddetids;
79 if (m_inputTableWS) {
80 g_log.notice("Parse input masking table workspace.");
81 prevmaskeddetids = parseMaskTable(m_inputTableWS);
82 } else {
83 g_log.notice("No input workspace to parse.");
84 }
85
86 // Extract mask
87 std::vector<detid_t> maskeddetids;
88 if (m_inputIsMask)
89 maskeddetids = extractMaskFromMaskWorkspace();
90 else
91 maskeddetids = extractMaskFromMatrixWorkspace();
92 g_log.debug() << "[DB] Number of masked detectors = " << maskeddetids.size() << ".\n";
93
94 // Write out
95 if (m_inputTableWS) {
96 g_log.notice() << "About to copying input table workspace content to output workspace."
97 << ".\n";
99 } else {
100 g_log.notice() << "There is no input workspace information to copy to "
101 "output workspace."
102 << ".\n";
103 }
104
105 addToTableWorkspace(outws, maskeddetids, xmin, xmax, prevmaskeddetids);
106}
107
108//----------------------------------------------------------------------------------------------
115 // Output vector
116 std::vector<detid_t> maskeddetectorids;
117
118 // Check format of mask table workspace
119 if (masktablews->columnCount() != 3) {
120 g_log.error("Mask table workspace must have more than 3 columns. First 3 "
121 "must be Xmin, Xmax and Spectrum List.");
122 return maskeddetectorids;
123 } else {
124 std::vector<std::string> colnames = masktablews->getColumnNames();
125 std::vector<std::string> chkcolumans(3);
126 chkcolumans[0] = "XMin";
127 chkcolumans[1] = "XMax";
128 chkcolumans[2] = "DetectorIDsList";
129 for (int i = 0; i < 3; ++i) {
130 if (colnames[i] != chkcolumans[i]) {
131 g_log.error() << "Mask table workspace " << masktablews->getName() << "'s " << i << "-th column name is "
132 << colnames[i] << ", while it should be " << chkcolumans[i] << ". MaskWorkspace is invalid"
133 << " and thus not used.\n";
134 return maskeddetectorids;
135 }
136 }
137 }
138
139 // Parse each row
140 size_t numrows = masktablews->rowCount();
141 double xmin, xmax;
142 std::string specliststr;
143 for (size_t i = 0; i < numrows; ++i) {
144 TableRow tmprow = masktablews->getRow(i);
145 tmprow >> xmin >> xmax >> specliststr;
146
147 std::vector<detid_t> tmpdetidvec = parseStringToVector(specliststr);
148 maskeddetectorids.insert(maskeddetectorids.end(), tmpdetidvec.begin(), tmpdetidvec.end());
149 }
150
151 return maskeddetectorids;
152}
153
154//----------------------------------------------------------------------------------------------
160std::vector<detid_t> ExtractMaskToTable::parseStringToVector(const std::string &liststr) {
161 std::vector<detid_t> detidvec;
162
163 // Use ArrayProperty to parse the list
164 ArrayProperty<int> detlist("i", liststr);
165 if (!detlist.isValid().empty()) {
166 std::stringstream errss;
167 errss << "String '" << liststr << "' is unable to be converted to a list of detectors IDs. "
168 << "Validation mesage: " << detlist.isValid();
169 g_log.error(errss.str());
170 throw std::runtime_error(errss.str());
171 }
172
173 // Convert from ArrayProperty to detectors list
174 size_t numdetids = detlist.size();
175 detidvec.reserve(numdetids);
176 for (size_t i = 0; i < numdetids; ++i) {
177 int tmpid = detlist.operator()()[i];
178 detidvec.emplace_back(tmpid);
179 g_log.debug() << "[DB] Add detector ID: " << tmpid << ".\n";
180 }
181
182 return detidvec;
183}
184
185//----------------------------------------------------------------------------------------------
190 // Clear input
191 std::vector<detid_t> maskeddetids;
192
193 // Get on hold of instrument
194 const auto &detectorInfo = m_dataWS->detectorInfo();
195 if (detectorInfo.size() == 0)
196 throw std::runtime_error("There is no instrument in input workspace.");
197
198 // Extract
199 const std::vector<detid_t> &detids = detectorInfo.detectorIDs();
200
201 for (size_t i = 0; i < detectorInfo.size(); ++i) {
202 bool masked = detectorInfo.isMasked(i);
203 if (masked) {
204 maskeddetids.emplace_back(detids[i]);
205 }
206 g_log.debug() << "[DB] Detector No. " << i << ": ID = " << detids[i] << ", Masked = " << masked << ".\n";
207 }
208
209 g_log.notice() << "Extract mask: There are " << maskeddetids.size()
210 << " detectors that"
211 " are masked."
212 << ".\n";
213
214 return maskeddetids;
215}
216
217//----------------------------------------------------------------------------------------------
223 // output vector
224 std::vector<detid_t> maskeddetids;
225
226 // Go through all spectra to find masked workspace
227 MaskWorkspace_const_sptr maskws = std::dynamic_pointer_cast<const MaskWorkspace>(m_dataWS);
228 size_t numhist = maskws->getNumberHistograms();
229 for (size_t i = 0; i < numhist; ++i) {
230 // Rule out the spectrum without mask
231 if (maskws->readY(i)[0] < 1.0E-9)
232 continue;
233
234 const auto &detidset = maskws->getSpectrum(i).getDetectorIDs();
235 std::copy(detidset.cbegin(), detidset.cend(), std::inserter(maskeddetids, maskeddetids.end()));
236 }
237 return maskeddetids;
238}
239
240//----------------------------------------------------------------------------------------------
246 const TableWorkspace_sptr &targetWS) {
247 // Compare the column names. They must be exactly the same
248 std::vector<std::string> sourcecolnames = sourceWS->getColumnNames();
249 std::vector<std::string> targetcolnames = targetWS->getColumnNames();
250 if (sourcecolnames.size() != targetcolnames.size()) {
251 std::stringstream errmsg;
252 errmsg << "Soruce table workspace " << sourceWS->getName() << " has different number of columns ("
253 << sourcecolnames.size() << ") than target table workspace's (" << targetcolnames.size() << ")";
254 throw std::runtime_error(errmsg.str());
255 }
256 for (size_t i = 0; i < sourcecolnames.size(); ++i) {
257 if (sourcecolnames[i] != targetcolnames[i]) {
258 std::stringstream errss;
259 errss << "Source and target have incompatible column name at column " << i << ". "
260 << "Column name of source is " << sourcecolnames[i] << "; "
261 << "Column name of target is " << targetcolnames[i];
262 throw std::runtime_error(errss.str());
263 }
264 }
265
266 // Copy over the content
267 size_t numrows = sourceWS->rowCount();
268 for (size_t i = 0; i < numrows; ++i) {
269 double xmin, xmax;
270 std::string speclist;
271 TableRow tmprow = sourceWS->getRow(i);
272 tmprow >> xmin >> xmax >> speclist;
273
274 TableRow newrow = targetWS->appendRow();
275 newrow << xmin << xmax << speclist;
276 }
277}
278
279//----------------------------------------------------------------------------------------------
289void ExtractMaskToTable::addToTableWorkspace(const TableWorkspace_sptr &outws, std::vector<detid_t> maskeddetids,
290 double xmin, double xmax, std::vector<detid_t> prevmaskedids) {
291 // Sort vector of detectors ID
292 size_t numdetids = maskeddetids.size();
293 if (numdetids == 0) {
294 std::stringstream warnss;
295 warnss << "Attempting to add an empty vector of masked detectors IDs to "
296 "output workspace. Operation failed.";
297 g_log.warning(warnss.str());
298 return;
299 } else {
300 sort(maskeddetids.begin(), maskeddetids.end());
301 }
302
303 // Exclude previously masked detectors IDs from masked detectors IDs
304 if (!prevmaskedids.empty()) {
305 sort(prevmaskedids.begin(), prevmaskedids.end());
306 maskeddetids = subtractVector(maskeddetids, prevmaskedids);
307 numdetids = maskeddetids.size();
308 } else {
309 g_log.debug() << "[DB] There is no previously masked detectors."
310 << ".\n";
311 }
312
313 if (numdetids == 0) {
314 // I don't know what should be done here
315 throw std::runtime_error("Empty detector ID list");
316 }
317
318 // Convert vector to string
319 std::stringstream spectralist;
320 detid_t previd = maskeddetids[0];
321 detid_t headid = maskeddetids[0];
322 for (size_t i = 1; i < numdetids; ++i) {
323 detid_t tmpid = maskeddetids[i];
324 if (tmpid == previd + 1) {
325 // Continuous ID
326 previd = tmpid;
327 } else if (tmpid > previd + 1) {
328 // Skipped ID: make a pair
329 if (previd == headid) {
330 // Single item
331 spectralist << " " << headid << ", ";
332 } else {
333 // Multiple items
334 spectralist << " " << headid << "-" << previd << ", ";
335 }
336
337 // New head
338 headid = tmpid;
339 previd = tmpid;
340 } else {
341 g_log.error() << "Current ID = " << tmpid << ", Previous ID = " << previd << ", Head ID = " << headid << ".\n";
342 throw std::runtime_error("Impossible! Programming logic error!");
343 }
344 } // ENDFOR (i)
345
346 // Last one
347 if (previd == headid)
348 spectralist << " " << headid;
349 else
350 spectralist << " " << headid << "-" << previd;
351
352 // Add to table workspace
353 std::string specliststr = spectralist.str();
354 TableRow newrow = outws->appendRow();
355 newrow << xmin << xmax << specliststr;
356}
357
358//----------------------------------------------------------------------------------------------
363std::vector<detid_t> ExtractMaskToTable::subtractVector(std::vector<detid_t> minuend, std::vector<detid_t> subtrahend) {
364 // Define some variables
365 std::vector<detid_t>::iterator firstsubiter, fiter;
366 firstsubiter = subtrahend.begin();
367
368 // Returned
369 std::vector<detid_t> diff;
370 size_t numminend = minuend.size();
371
372 for (size_t i = 0; i < numminend; ++i) {
373 detid_t tmpid = minuend[i];
374 fiter = lower_bound(firstsubiter, subtrahend.end(), tmpid);
375 bool exist(false);
376 if (fiter != subtrahend.end())
377 exist = *fiter == tmpid;
378 if (!exist) {
379 diff.emplace_back(tmpid);
380 }
381 firstsubiter = fiter;
382 }
383
384 return diff;
385}
386
387} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
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
TableRow represents a row in a TableWorkspace.
Definition: TableRow.h:39
A property class for workspaces.
ExtractMaskToTable : Extract the mask in a workspace to a table workspace.
std::vector< detid_t > extractMaskFromMatrixWorkspace()
Extract mask from a workspace to a list of detectors.
std::vector< detid_t > parseMaskTable(const DataObjects::TableWorkspace_sptr &masktablews)
Parse input TableWorkspace to get a list of detectors IDs of which detector are already masked.
void copyTableWorkspaceContent(const DataObjects::TableWorkspace_sptr &sourceWS, const DataObjects::TableWorkspace_sptr &targetWS)
Copy table workspace content from one workspace to another.
std::vector< detid_t > subtractVector(std::vector< detid_t > minuend, std::vector< detid_t > subtrahend)
Remove the items appeared in a vector from another.
std::vector< detid_t > parseStringToVector(const std::string &liststr)
Parse a string containing list in format (x, xx-yy, x, x, ...) to a vector of detid_t.
void addToTableWorkspace(const DataObjects::TableWorkspace_sptr &outws, std::vector< detid_t > maskeddetids, double xmin, double xmax, std::vector< detid_t > prevmaskedids)
Add a list of spectra (detector IDs) to the output table workspace.
DataObjects::TableWorkspace_sptr m_inputTableWS
Input table workspace.
API::MatrixWorkspace_const_sptr m_dataWS
Input matrix workspace.
void exec() override
Execution code.
std::vector< detid_t > extractMaskFromMaskWorkspace()
Extract masked detectors from a MaskWorkspace.
Support for a property that holds an array of values.
Definition: ArrayProperty.h:28
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void debug(const std::string &msg)
Logs at debug level.
Definition: Logger.cpp:114
void notice(const std::string &msg)
Logs at notice level.
Definition: Logger.cpp:95
void error(const std::string &msg)
Logs at error level.
Definition: Logger.cpp:77
void warning(const std::string &msg)
Logs at warning level.
Definition: Logger.cpp:86
int size() const override
Return the size of this property.
std::string isValid() const override
Overridden function that checks whether the property, if not overriden returns "".
std::shared_ptr< TableWorkspace > TableWorkspace_sptr
shared pointer to Mantid::DataObjects::TableWorkspace
std::shared_ptr< const MaskWorkspace > MaskWorkspace_const_sptr
shared pointer to a const MaskWorkspace
Definition: MaskWorkspace.h:67
int32_t detid_t
Typedef for a detector ID.
Definition: SpectrumInfo.h:21
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition: EmptyValues.h:43
@ Input
An input workspace.
Definition: Property.h:53
@ Output
An output workspace.
Definition: Property.h:54