Mantid
Loading...
Searching...
No Matches
ExtractSpectra.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
12#include "MantidAPI/TextAxis.h"
14#include "MantidIndexing/Extract.h"
15#include "MantidIndexing/IndexInfo.h"
18
19#include <algorithm>
20#include <set>
21#include <vector>
22
23namespace {
25const double xBoundaryTolerance = 1.0e-15;
26} // namespace
27
28namespace Mantid::Algorithms {
29
30using namespace Kernel;
31using namespace API;
32using namespace DataObjects;
33using namespace HistogramData;
34using Types::Event::TofEvent;
35
36// Register the algorithm into the AlgorithmFactory
37DECLARE_ALGORITHM(ExtractSpectra)
38
39
40const std::string ExtractSpectra::name() const { return "ExtractSpectra"; }
41
43int ExtractSpectra::version() const { return 1; }
44
46const std::string ExtractSpectra::category() const { return "Transforms\\Splitting"; }
47
49const std::string ExtractSpectra::summary() const {
50 return "Extracts a list of spectra from a workspace and places them in a new "
51 "workspace.";
52}
53
55std::map<std::string, std::string> ExtractSpectra::validateInputs() {
56 std::map<std::string, std::string> helpMessages;
57 if (!isDefault("XMin") && !isDefault("XMax")) {
58 const double xmin = getProperty("XMin");
59 const double xmax = getProperty("XMax");
60 if (xmin > xmax) {
61 helpMessages["XMin"] = "XMin must be less than XMax";
62 helpMessages["XMax"] = "XMax must be greater than XMin";
63 }
64 }
65
66 if (!isDefault("StartWorkspaceIndex")) {
67 const int minSpec_i = getProperty("StartWorkspaceIndex");
68 auto minSpec = static_cast<size_t>(minSpec_i);
69 API::MatrixWorkspace_sptr ws = getProperty("InputWorkspace");
70 const size_t numberOfSpectra = ws->indexInfo().globalSize();
71 int maxSpec_i = getProperty("EndWorkspaceIndex");
72 auto maxSpec = static_cast<size_t>(maxSpec_i);
73 if (isEmpty(maxSpec_i))
74 maxSpec = numberOfSpectra - 1;
75 if (maxSpec < minSpec) {
76 helpMessages["StartWorkspaceIndex"] = "StartWorkspaceIndex must be less than or equal to EndWorkspaceIndex";
77 helpMessages["EndWorkspaceIndex"] = "EndWorkspaceIndex must be greater than or equal to StartWorkspaceIndex";
78 }
79 }
80
81 return helpMessages;
82}
83
87 declareProperty(std::make_unique<WorkspaceProperty<>>("InputWorkspace", "", Direction::Input), "The input workspace");
88 declareProperty(std::make_unique<WorkspaceProperty<>>("OutputWorkspace", "", Direction::Output),
89 "Name of the output workspace");
90
91 declareProperty("XMin", EMPTY_DBL(),
92 "An X value that is within the first "
93 "(lowest X value) bin that will be "
94 "retained\n"
95 "(default: workspace min)");
96 declareProperty("XMax", EMPTY_DBL(),
97 "An X value that is in the highest X "
98 "value bin to be retained (default: max "
99 "X)");
100 auto mustBePositive = std::make_shared<BoundedValidator<int>>();
101 mustBePositive->setLower(0);
102 declareProperty("StartWorkspaceIndex", 0, mustBePositive,
103 "The index number of the first entry in the Workspace that "
104 "will be loaded\n"
105 "(default: first entry in the Workspace)");
106 // As the property takes ownership of the validator pointer, have to take care
107 // to pass in a unique pointer to each property.
108 declareProperty("EndWorkspaceIndex", EMPTY_INT(), mustBePositive,
109 "The index number of the last entry in the Workspace to be loaded\n"
110 "(default: last entry in the Workspace)");
111 declareProperty(std::make_unique<ArrayProperty<size_t>>("WorkspaceIndexList"),
112 "A comma-separated list of individual workspace indices to "
113 "read. Only used if\n"
114 "explicitly set. The WorkspaceIndexList is only used if the "
115 "DetectorList is empty.");
116
117 declareProperty(std::make_unique<ArrayProperty<detid_t>>("DetectorList"),
118 "A comma-separated list of individual detector IDs to read. "
119 "Only used if\n"
120 "explicitly set. When specifying the WorkspaceIndexList and "
121 "DetectorList property,\n"
122 "the latter is being selected.");
123}
124
130 m_inputWorkspace = getProperty("InputWorkspace");
131 m_isHistogramData = m_inputWorkspace->isHistogramData();
132 m_commonBoundaries = m_inputWorkspace->isCommonBins();
133 this->checkProperties();
134
135 if (m_workspaceIndexList.empty()) {
136 MatrixWorkspace_sptr out = getProperty("OutputWorkspace");
137 // No spectra extracted, but not in-place, clone input before cropping.
138 if (out != m_inputWorkspace)
140 } else {
141 auto extract = std::make_shared<ExtractSpectra2>();
142 setupAsChildAlgorithm(extract);
143 extract->setWorkspaceInputProperties(
144 "InputWorkspace", m_inputWorkspace, IndexType::WorkspaceIndex,
145 std::vector<int64_t>(m_workspaceIndexList.begin(), m_workspaceIndexList.end()));
146 extract->execute();
147 m_inputWorkspace = extract->getProperty("OutputWorkspace");
148 }
149 setProperty("OutputWorkspace", m_inputWorkspace);
150
151 // don't trim x-range if those values are not specified
152 if (isDefault("XMin") && isDefault("XMax"))
153 return;
154
155 eventW = std::dynamic_pointer_cast<EventWorkspace>(m_inputWorkspace);
156 if (eventW)
157 this->execEvent();
158 else
159 this->execHistogram();
160}
161
164 auto size = static_cast<int>(m_inputWorkspace->getNumberHistograms());
165 auto croppedCommonXHistogram = getCroppedXHistogram(*m_inputWorkspace);
166 Progress prog(this, 0.0, 1.0, size);
167 for (int i = 0; i < size; ++i) {
168 if (m_commonBoundaries) {
169 this->cropCommon(*m_inputWorkspace, croppedCommonXHistogram, i);
170 } else {
171 this->cropRagged(*m_inputWorkspace, i);
172 }
174 prog.report();
175 }
176}
177
185 const auto hist = workspace.histogram(0);
186 auto begin = m_minXIndex;
187 auto end = histXMaxIndex();
188
189 auto cropped(hist);
190 cropped.resize(end - begin);
191
192 auto xEnd = hist.xMode() == Histogram::XMode::Points ? end : end + 1;
193 cropped.mutableX().assign(hist.x().begin() + begin, hist.x().begin() + xEnd);
194 return cropped.sharedX();
195}
196
204 const auto hist = workspace.histogram(index);
205 auto begin = m_minXIndex;
206 auto end = histXMaxIndex();
207
208 auto cropped(hist);
209 cropped.resize(end - begin);
210
211 cropped.setX(XHistogram);
212
213 if (cropped.sharedY())
214 cropped.mutableY().assign(hist.y().begin() + begin, hist.y().begin() + end);
215 if (cropped.sharedE())
216 cropped.mutableE().assign(hist.e().begin() + begin, hist.e().begin() + end);
217 if (cropped.sharedDx())
218 cropped.mutableDx().assign(hist.dx().begin() + begin, hist.dx().begin() + end);
219
220 workspace.setHistogram(index, cropped);
221}
222
228 auto &Y = workspace.mutableY(index);
229 auto &E = workspace.mutableE(index);
230 const size_t size = Y.size();
231 size_t startX = this->getXMinIndex(index);
232 if (startX > size)
233 startX = size;
234 for (size_t i = 0; i < startX; ++i) {
235 Y[i] = 0.0;
236 E[i] = 0.0;
237 }
238 size_t endX = this->getXMaxIndex(index);
239 if (endX > 0 && m_isHistogramData)
240 endX -= 1;
241 for (size_t i = endX; i < size; ++i) {
242 Y[i] = 0.0;
243 E[i] = 0.0;
244 }
245}
246
247namespace { // anonymous namespace
248template <class T> void filterEventsHelper(std::vector<T> &events, const double xmin, const double xmax) {
249 events.erase(std::remove_if(events.begin(), events.end(),
250 [xmin, xmax](const T &event) {
251 const double tof = event.tof();
252 return bool(tof < xmin || tof > xmax);
253 }),
254 events.end());
255}
256} // namespace
257
266 // use min/max from workspace if the values aren't supplied by the user
267 const double minX_val = isDefault("XMin") ? eventW->getTofMin() : getProperty("XMin");
268 const double maxX_val = isDefault("XMax") ? eventW->getTofMax() : getProperty("XMax");
269
270 BinEdges binEdges(2);
271 if (m_commonBoundaries) {
272 auto &oldX = m_inputWorkspace->x(0);
273 binEdges = BinEdges(oldX.begin() + m_minXIndex, oldX.begin() + m_maxXIndex);
274 }
275 if (m_maxXIndex - m_minXIndex < 2) {
276 // create new output X axis
277 binEdges = {minX_val, maxX_val};
278 }
279
280 Progress prog(this, 0.0, 1.0, eventW->getNumberHistograms());
282 for (int i = 0; i < static_cast<int>(eventW->getNumberHistograms()); ++i) {
284 EventList &el = eventW->getSpectrum(i);
285
286 if (!el.empty()) {
287 switch (el.getEventType()) {
288 case TOF: {
289 filterEventsHelper(el.getEvents(), minX_val, maxX_val);
290 break;
291 }
292 case WEIGHTED: {
293 filterEventsHelper(el.getWeightedEvents(), minX_val, maxX_val);
294 break;
295 }
296 case WEIGHTED_NOTIME: {
297 filterEventsHelper(el.getWeightedEventsNoTime(), minX_val, maxX_val);
298 break;
299 }
300 }
301 }
302
303 // If the X axis is NOT common, then keep the initial X axis, just clear the
304 // events, otherwise:
305 if (m_commonBoundaries) {
306 const auto oldDx = el.pointStandardDeviations();
307 el.setHistogram(binEdges);
308 if (oldDx) {
309 auto end = histXMaxIndex();
310 el.setPointStandardDeviations(oldDx.begin() + m_minXIndex, oldDx.begin() + end);
311 }
312 }
314 prog.report();
316 }
318}
319
322 auto end = histXMaxIndex();
323 if (workspace.hasMaskedBins(i)) {
324 MatrixWorkspace::MaskList filteredMask;
325 for (const auto &mask : workspace.maskedBins(i)) {
326 const size_t maskIndex = mask.first;
327 if (maskIndex >= m_minXIndex && maskIndex < end)
328 filteredMask[maskIndex - m_minXIndex] = mask.second;
329 }
330 if (filteredMask.size() > 0)
331 workspace.setMaskedBins(i, filteredMask);
332 else
333 workspace.setUnmaskedBins(i);
334 }
335}
336
346 m_minXIndex = this->getXMinIndex();
347 m_maxXIndex = this->getXMaxIndex();
348 const size_t xSize = m_inputWorkspace->x(0).size();
349 if (m_minXIndex > 0 || m_maxXIndex < xSize) {
350 if (m_minXIndex > m_maxXIndex) {
351 throw std::out_of_range("XMin must be less than XMax");
352 }
353 m_croppingInX = true;
354 if (m_commonBoundaries && !std::dynamic_pointer_cast<EventWorkspace>(m_inputWorkspace) &&
356 m_minXIndex--;
358 if (m_isHistogramData) {
359 m_maxXIndex += 1;
360 }
361 }
362 }
363 if (!m_commonBoundaries) {
364 m_minXIndex = 0;
365 m_maxXIndex = static_cast<int>(m_inputWorkspace->x(0).size());
366 }
367
368 // The hierarchy of inputs is (one is being selected):
369 // 1. DetectorList
370 // 2. WorkspaceIndexList
371 // 3. Start and stop index
372 std::vector<detid_t> detectorList = getProperty("DetectorList");
373 if (!detectorList.empty()) {
374 std::vector<size_t> indicesVector = m_inputWorkspace->getIndicesFromDetectorIDs(detectorList);
375 m_workspaceIndexList = std::set<size_t>(indicesVector.begin(), indicesVector.end());
376 } else {
377 std::vector<size_t> indicesVector = getProperty("WorkspaceIndexList");
378 m_workspaceIndexList = std::set<size_t>(indicesVector.begin(), indicesVector.end());
379
380 if (m_workspaceIndexList.empty()) {
381 int minSpec_i = getProperty("StartWorkspaceIndex");
382 auto minSpec = static_cast<size_t>(minSpec_i);
383 const size_t numberOfSpectra = m_inputWorkspace->indexInfo().globalSize();
384 int maxSpec_i = getProperty("EndWorkspaceIndex");
385 auto maxSpec = static_cast<size_t>(maxSpec_i);
386 if (isEmpty(maxSpec_i))
387 maxSpec = numberOfSpectra - 1;
388 if (maxSpec - minSpec + 1 != numberOfSpectra) {
389 for (size_t i = minSpec; i <= maxSpec; ++i)
390 m_workspaceIndexList.insert(i);
391 }
392 }
393 }
394} // namespace Algorithms
395
402size_t ExtractSpectra::getXMinIndex(const size_t wsIndex) {
403 double minX_val = getProperty("XMin");
404 size_t xIndex = 0;
405 if (!isEmpty(minX_val)) { // A value has been passed to the algorithm, check
406 // it and maybe store it
407 const auto &X = m_inputWorkspace->x(wsIndex);
408 if (m_commonBoundaries && minX_val > X.back()) {
409 std::stringstream msg;
410 msg << "XMin is greater than the largest X value (" << minX_val << " > " << X.back() << ")";
411 throw std::out_of_range(msg.str());
412 }
413 // Reduce cut-off value slightly to allow for rounding errors
414 // when trying to exactly hit a bin boundary.
415 minX_val -= std::abs(minX_val * xBoundaryTolerance);
416 xIndex = std::lower_bound(X.begin(), X.end(), minX_val) - X.begin();
417 }
418 return xIndex;
419}
420
427size_t ExtractSpectra::getXMaxIndex(const size_t wsIndex) {
428 const auto &X = m_inputWorkspace->x(wsIndex);
429 size_t xIndex = X.size();
430 // get the value that the user entered if they entered one at all
431 double maxX_val = getProperty("XMax");
432 if (!isEmpty(maxX_val)) { // we have a user value, check it and maybe store it
433 if (m_commonBoundaries && maxX_val < X.front()) {
434 std::stringstream msg;
435 msg << "XMax is less than the smallest X value (" << maxX_val << " < " << X.front() << ")";
436 throw std::out_of_range(msg.str());
437 }
438 // Increase cut-off value slightly to allow for rounding errors
439 // when trying to exactly hit a bin boundary.
440 maxX_val += std::abs(maxX_val * xBoundaryTolerance);
441 xIndex = std::upper_bound(X.begin(), X.end(), maxX_val) - X.begin();
442 }
443 return xIndex;
444}
445
447 if (m_isHistogramData) {
448 return m_maxXIndex - 1;
449 }
450 return m_maxXIndex;
451}
452
453} // namespace Mantid::Algorithms
std::string name
Definition Run.cpp:60
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:542
IPeaksWorkspace_sptr workspace
std::map< DeltaEMode::Type, std::string > index
IntArray detectorList
#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.
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
bool isDefault(const std::string &name) const
static bool isEmpty(const NumT toCheck)
checks that the value was not set by users, uses the value in empty double/int.
void setupAsChildAlgorithm(const Algorithm_sptr &algorithm, const double startProgress=-1., const double endProgress=-1., const bool enableLogging=true)
Setup algorithm as child algorithm.
Base MatrixWorkspace Abstract Class.
std::map< size_t, double > MaskList
Masked bins for each spectrum are stored as a set of pairs containing <bin index, weight>
Helper class for reporting progress from algorithms.
Definition Progress.h:25
A property class for workspaces.
Extracts specified spectra from a workspace and places them in a new workspace.
void checkProperties()
Retrieves the optional input properties and checks that they have valid values.
void cropCommon(API::MatrixWorkspace &workspace, Kernel::cow_ptr< Mantid::HistogramData::HistogramX > XHistogram, int index)
Crops the given workspace in accordance with m_minX and m_maxX.
bool m_isHistogramData
Flag indicating whether we're dealing with histogram data.
std::size_t m_minXIndex
The bin index to start the cropped workspace from.
void execHistogram()
Execute the algorithm in case of a histogrammed data.
std::size_t m_maxXIndex
The bin index to end the cropped workspace at.
const Kernel::cow_ptr< Mantid::HistogramData::HistogramX > getCroppedXHistogram(const API::MatrixWorkspace &workspace)
Returns a pointer to a cropped X Histogram to be used as the X Histogram for each of the spectra in t...
std::size_t getXMaxIndex(const size_t wsIndex=0)
Find the X index corresponding to (or just within) the value given in the XMax property.
std::map< std::string, std::string > validateInputs() override
Validate the input properties are sane.
void init() override
Initialize the algorithm's properties.
void execEvent()
Executes the algorithm.
void cropRagged(API::MatrixWorkspace &workspace, int index)
Zeroes all data points outside the X values given.
int version() const override
Algorithm's version for identification.
const std::string summary() const override
Algorithm's summary for use in the GUI and help.
bool m_croppingInX
Flag indicating whether XMin and/or XMax has been set.
API::MatrixWorkspace_sptr m_inputWorkspace
The input workspace.
DataObjects::EventWorkspace_sptr eventW
void exec() override
Executes the algorithm.
std::set< size_t > m_workspaceIndexList
The list of workspaces to extract.
bool m_commonBoundaries
Flag indicating whether the input workspace has common boundaries.
const std::string category() const override
Algorithm's category for identification.
void propagateBinMasking(API::MatrixWorkspace &workspace, const int i) const
Propagate bin masking if there is any.
std::size_t getXMinIndex(const size_t wsIndex=0)
Find the X index corresponding to (or just within) the value given in the XMin property.
A class for holding :
Definition EventList.h:57
Support for a property that holds an array of values.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
Implements a copy on write data template.
Definition cow_ptr.h:41
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
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.
constexpr int EMPTY_INT() noexcept
Returns what we consider an "empty" integer within a property.
Definition EmptyValues.h:24
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition EmptyValues.h:42
STL namespace.
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54