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
10#include "MantidAPI/Algorithm.tcc"
12#include "MantidAPI/TextAxis.h"
14#include "MantidHistogramData/Slice.h"
15#include "MantidIndexing/Extract.h"
16#include "MantidIndexing/IndexInfo.h"
19
20#include <algorithm>
21
22namespace {
24const double xBoundaryTolerance = 1.0e-15;
25} // namespace
26
27namespace Mantid::Algorithms {
28
29using namespace Kernel;
30using namespace API;
31using namespace DataObjects;
32using namespace HistogramData;
33using Types::Event::TofEvent;
34
35// Register the algorithm into the AlgorithmFactory
36DECLARE_ALGORITHM(ExtractSpectra)
37
38
39const std::string ExtractSpectra::name() const { return "ExtractSpectra"; }
40
42int ExtractSpectra::version() const { return 1; }
43
45const std::string ExtractSpectra::category() const { return "Transforms\\Splitting"; }
46
48const std::string ExtractSpectra::summary() const {
49 return "Extracts a list of spectra from a workspace and places them in a new "
50 "workspace.";
51}
52
54std::map<std::string, std::string> ExtractSpectra::validateInputs() {
55 std::map<std::string, std::string> helpMessages;
56 if (!isDefault("XMin") && !isDefault("XMax")) {
57 const double xmin = getProperty("XMin");
58 const double xmax = getProperty("XMax");
59 if (xmin > xmax) {
60 helpMessages["XMin"] = "XMin must be less than XMax";
61 helpMessages["XMax"] = "XMax must be greater than XMin";
62 }
63 }
64 return helpMessages;
65}
66
70 declareProperty(std::make_unique<WorkspaceProperty<>>("InputWorkspace", "", Direction::Input), "The input workspace");
71 declareProperty(std::make_unique<WorkspaceProperty<>>("OutputWorkspace", "", Direction::Output),
72 "Name of the output workspace");
73
74 declareProperty("XMin", EMPTY_DBL(),
75 "An X value that is within the first "
76 "(lowest X value) bin that will be "
77 "retained\n"
78 "(default: workspace min)");
79 declareProperty("XMax", EMPTY_DBL(),
80 "An X value that is in the highest X "
81 "value bin to be retained (default: max "
82 "X)");
83 auto mustBePositive = std::make_shared<BoundedValidator<int>>();
84 mustBePositive->setLower(0);
85 declareProperty("StartWorkspaceIndex", 0, mustBePositive,
86 "The index number of the first entry in the Workspace that "
87 "will be loaded\n"
88 "(default: first entry in the Workspace)");
89 // As the property takes ownership of the validator pointer, have to take care
90 // to pass in a unique pointer to each property.
91 declareProperty("EndWorkspaceIndex", EMPTY_INT(), mustBePositive,
92 "The index number of the last entry in the Workspace to be loaded\n"
93 "(default: last entry in the Workspace)");
94 declareProperty(std::make_unique<ArrayProperty<size_t>>("WorkspaceIndexList"),
95 "A comma-separated list of individual workspace indices to "
96 "read. Only used if\n"
97 "explicitly set. The WorkspaceIndexList is only used if the "
98 "DetectorList is empty.");
99
100 declareProperty(std::make_unique<ArrayProperty<detid_t>>("DetectorList"),
101 "A comma-separated list of individual detector IDs to read. "
102 "Only used if\n"
103 "explicitly set. When specifying the WorkspaceIndexList and "
104 "DetectorList property,\n"
105 "the latter is being selected.");
106}
107
113 m_inputWorkspace = getProperty("InputWorkspace");
114 m_histogram = m_inputWorkspace->isHistogramData();
115 m_commonBoundaries = m_inputWorkspace->isCommonBins();
116 this->checkProperties();
117
118 if (m_workspaceIndexList.empty()) {
119 MatrixWorkspace_sptr out = getProperty("OutputWorkspace");
120 // No spectra extracted, but not in-place, clone input before cropping.
121 if (out != m_inputWorkspace)
123 } else {
124 auto extract = std::make_shared<ExtractSpectra2>();
125 setupAsChildAlgorithm(extract);
126 extract->setWorkspaceInputProperties(
127 "InputWorkspace", m_inputWorkspace, IndexType::WorkspaceIndex,
128 std::vector<int64_t>(m_workspaceIndexList.begin(), m_workspaceIndexList.end()));
129 extract->execute();
130 m_inputWorkspace = extract->getProperty("OutputWorkspace");
131 }
132 setProperty("OutputWorkspace", m_inputWorkspace);
133
134 if (isDefault("XMin") && isDefault("XMax"))
135 return;
136
137 eventW = std::dynamic_pointer_cast<EventWorkspace>(m_inputWorkspace);
138 if (eventW)
139 this->execEvent();
140 else
141 this->execHistogram();
142}
143
146 auto size = static_cast<int>(m_inputWorkspace->getNumberHistograms());
147 Progress prog(this, 0.0, 1.0, size);
148 for (int i = 0; i < size; ++i) {
149 if (m_commonBoundaries) {
150 m_inputWorkspace->setHistogram(i, slice(m_inputWorkspace->histogram(i), m_minX, m_maxX - m_histogram));
151 } else {
152 this->cropRagged(*m_inputWorkspace, i);
153 }
155 prog.report();
156 }
157}
158
159namespace { // anonymous namespace
160
161template <class T> struct eventFilter {
162 eventFilter(const double minValue, const double maxValue) : minValue(minValue), maxValue(maxValue) {}
163
164 bool operator()(const T &value) {
165 const double tof = value.tof();
166 return !(tof <= maxValue && tof >= minValue);
167 }
168
169 double minValue;
170 double maxValue;
171};
172
173template <class T> void filterEventsHelper(std::vector<T> &events, const double xmin, const double xmax) {
174 events.erase(std::remove_if(events.begin(), events.end(), eventFilter<T>(xmin, xmax)), events.end());
175}
176} // namespace
177
183 double minX_val = getProperty("XMin");
184 double maxX_val = getProperty("XMax");
185 if (isEmpty(minX_val))
186 minX_val = eventW->getTofMin();
187 if (isEmpty(maxX_val))
188 maxX_val = eventW->getTofMax();
189
190 BinEdges binEdges(2);
191 if (m_commonBoundaries) {
192 auto &oldX = m_inputWorkspace->x(0);
193 binEdges = BinEdges(oldX.begin() + m_minX, oldX.begin() + m_maxX);
194 }
195 if (m_maxX - m_minX < 2) {
196 // create new output X axis
197 binEdges = {minX_val, maxX_val};
198 }
199
200 eventW->sortAll(TOF_SORT, nullptr);
201
202 Progress prog(this, 0.0, 1.0, eventW->getNumberHistograms());
204 for (int i = 0; i < static_cast<int>(eventW->getNumberHistograms()); ++i) {
206 EventList &el = eventW->getSpectrum(i);
207
208 switch (el.getEventType()) {
209 case TOF: {
210 filterEventsHelper(el.getEvents(), minX_val, maxX_val);
211 break;
212 }
213 case WEIGHTED: {
214 filterEventsHelper(el.getWeightedEvents(), minX_val, maxX_val);
215 break;
216 }
217 case WEIGHTED_NOTIME: {
218 filterEventsHelper(el.getWeightedEventsNoTime(), minX_val, maxX_val);
219 break;
220 }
221 }
222
223 // If the X axis is NOT common, then keep the initial X axis, just clear the
224 // events, otherwise:
225 if (m_commonBoundaries) {
226 const auto oldDx = el.pointStandardDeviations();
227 el.setHistogram(binEdges);
228 if (oldDx) {
229 el.setPointStandardDeviations(oldDx.begin() + m_minX, oldDx.begin() + (m_maxX - m_histogram));
230 }
231 }
233 prog.report();
235 }
237}
238
241 if (workspace.hasMaskedBins(i)) {
242 MatrixWorkspace::MaskList filteredMask;
243 for (const auto &mask : workspace.maskedBins(i)) {
244 const size_t maskIndex = mask.first;
245 if (maskIndex >= m_minX && maskIndex < m_maxX - m_histogram)
246 filteredMask[maskIndex - m_minX] = mask.second;
247 }
248 if (filteredMask.size() > 0)
249 workspace.setMaskedBins(i, filteredMask);
250 else
251 workspace.setUnmaskedBins(i);
252 }
253}
254
264 m_minX = this->getXMinIndex();
265 m_maxX = this->getXMaxIndex();
266 const size_t xSize = m_inputWorkspace->x(0).size();
267 if (m_minX > 0 || m_maxX < xSize) {
268 if (m_minX > m_maxX) {
269 throw std::out_of_range("XMin must be less than XMax");
270 }
271 m_croppingInX = true;
272 if (m_commonBoundaries && !std::dynamic_pointer_cast<EventWorkspace>(m_inputWorkspace) &&
273 (m_minX == m_maxX || (m_histogram && m_maxX == m_minX + 1))) {
274 m_minX--;
275 m_maxX = m_minX + 1 + m_histogram;
276 }
277 }
278 if (!m_commonBoundaries) {
279 m_minX = 0;
280 m_maxX = static_cast<int>(m_inputWorkspace->x(0).size());
281 }
282
283 // The hierarchy of inputs is (one is being selected):
284 // 1. DetectorList
285 // 2. WorkspaceIndexList
286 // 3. Start and stop index
287 std::vector<detid_t> detectorList = getProperty("DetectorList");
288 if (!detectorList.empty()) {
289 m_workspaceIndexList = m_inputWorkspace->getIndicesFromDetectorIDs(detectorList);
290 } else {
291 m_workspaceIndexList = getProperty("WorkspaceIndexList");
292
293 if (m_workspaceIndexList.empty()) {
294 int minSpec_i = getProperty("StartWorkspaceIndex");
295 auto minSpec = static_cast<size_t>(minSpec_i);
296 const size_t numberOfSpectra = m_inputWorkspace->indexInfo().globalSize();
297 int maxSpec_i = getProperty("EndWorkspaceIndex");
298 auto maxSpec = static_cast<size_t>(maxSpec_i);
299 if (isEmpty(maxSpec_i))
300 maxSpec = numberOfSpectra - 1;
301 if (maxSpec < minSpec) {
302 g_log.error("StartWorkspaceIndex must be less than or equal to "
303 "EndWorkspaceIndex");
304 throw std::out_of_range("StartWorkspaceIndex must be less than or equal "
305 "to EndWorkspaceIndex");
306 }
307 if (maxSpec - minSpec + 1 != numberOfSpectra) {
308 m_workspaceIndexList.reserve(maxSpec - minSpec + 1);
309 for (size_t i = minSpec; i <= maxSpec; ++i)
310 m_workspaceIndexList.emplace_back(i);
311 }
312 }
313 }
314} // namespace Algorithms
315
322size_t ExtractSpectra::getXMinIndex(const size_t wsIndex) {
323 double minX_val = getProperty("XMin");
324 size_t xIndex = 0;
325 if (!isEmpty(minX_val)) { // A value has been passed to the algorithm, check
326 // it and maybe store it
327 const auto &X = m_inputWorkspace->x(wsIndex);
328 if (m_commonBoundaries && minX_val > X.back()) {
329 std::stringstream msg;
330 msg << "XMin is greater than the largest X value (" << minX_val << " > " << X.back() << ")";
331 throw std::out_of_range(msg.str());
332 }
333 // Reduce cut-off value slightly to allow for rounding errors
334 // when trying to exactly hit a bin boundary.
335 minX_val -= std::abs(minX_val * xBoundaryTolerance);
336 xIndex = std::lower_bound(X.begin(), X.end(), minX_val) - X.begin();
337 }
338 return xIndex;
339}
340
347size_t ExtractSpectra::getXMaxIndex(const size_t wsIndex) {
348 const auto &X = m_inputWorkspace->x(wsIndex);
349 size_t xIndex = X.size();
350 // get the value that the user entered if they entered one at all
351 double maxX_val = getProperty("XMax");
352 if (!isEmpty(maxX_val)) { // we have a user value, check it and maybe store it
353 if (m_commonBoundaries && maxX_val < X.front()) {
354 std::stringstream msg;
355 msg << "XMax is less than the smallest X value (" << maxX_val << " < " << X.front() << ")";
356 throw std::out_of_range(msg.str());
357 }
358 // Increase cut-off value slightly to allow for rounding errors
359 // when trying to exactly hit a bin boundary.
360 maxX_val += std::abs(maxX_val * xBoundaryTolerance);
361 xIndex = std::upper_bound(X.begin(), X.end(), maxX_val) - X.begin();
362 }
363 return xIndex;
364}
365
371 auto &Y = workspace.mutableY(index);
372 auto &E = workspace.mutableE(index);
373 const size_t size = Y.size();
374 size_t startX = this->getXMinIndex(index);
375 if (startX > size)
376 startX = size;
377 for (size_t i = 0; i < startX; ++i) {
378 Y[i] = 0.0;
379 E[i] = 0.0;
380 }
381 size_t endX = this->getXMaxIndex(index);
382 if (endX > 0)
383 endX -= m_histogram;
384 for (size_t i = endX; i < size; ++i) {
385 Y[i] = 0.0;
386 E[i] = 0.0;
387 }
388}
389
390} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
double maxValue
double minValue
double value
The value of the point.
Definition: FitMW.cpp:51
IPeaksWorkspace_sptr workspace
Definition: IndexPeaks.cpp:114
std::map< DeltaEMode::Type, std::string > index
Definition: DeltaEMode.cpp:19
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...
Definition: MultiThreaded.h:94
#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.
Definition: Algorithm.cpp:1913
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
bool isDefault(const std::string &name) const
Definition: Algorithm.cpp:2084
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.
Definition: Algorithm.cpp:855
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.
std::size_t m_maxX
The bin index to end the cropped workspace at.
std::vector< size_t > m_workspaceIndexList
The list of workspaces to extract.
void execHistogram()
Execute the algorithm in case of a histogrammed data.
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.
bool m_histogram
Flag indicating whether we're dealing with histogram data.
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.
std::size_t m_minX
The bin index to start the cropped workspace from.
API::MatrixWorkspace_sptr m_inputWorkspace
The input workspace.
DataObjects::EventWorkspace_sptr eventW
void exec() override
Executes the algorithm.
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:56
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 error(const std::string &msg)
Logs at error level.
Definition: Logger.cpp:77
void report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
Definition: ProgressBase.h:51
@ WEIGHTED_NOTIME
Definition: IEventList.h:18
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.
Definition: MultiThreaded.h:22
constexpr int EMPTY_INT() noexcept
Returns what we consider an "empty" integer within a property.
Definition: EmptyValues.h:25
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition: EmptyValues.h:43
STL namespace.
@ Input
An input workspace.
Definition: Property.h:53
@ Output
An output workspace.
Definition: Property.h:54