Mantid
Loading...
Searching...
No Matches
UnwrapMonitorsInTOF.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 +
13#include "MantidHistogramData/Counts.h"
14#include "MantidHistogramData/Histogram.h"
15#include "MantidHistogramData/Points.h"
17#include <numeric>
18
19namespace {
20const double specialWavelengthCutoff = -1.0;
21const double specialTimeOfFlightCutoff = -1.0;
22const int specialIndex = -1;
23
24struct MinAndMaxTof {
25 MinAndMaxTof(double minTof, double maxTof) : minTof(minTof), maxTof(maxTof) {}
26 double minTof;
27 double maxTof;
28};
29
30struct MinAndMaxIndex {
31 MinAndMaxIndex(int minIndex, int maxIndex) : minIndex(minIndex), maxIndex(maxIndex) {}
32 int minIndex;
33 int maxIndex;
34};
35
50MinAndMaxTof getMinAndMaxTofForDistanceFromSoure(double distanceFromSource, double lowerWavelengthLimit,
51 double upperWavelengthLimit) {
52 // Calculate and set the constant factor for the conversion to wavelength
53 const double angstromConversion = 1e10;
54 const double microsecondConversion = 1e6;
55 const double conversionConstant =
56 (distanceFromSource * Mantid::PhysicalConstants::NeutronMass * microsecondConversion) /
57 (Mantid::PhysicalConstants::h * angstromConversion);
58 const double minTof = lowerWavelengthLimit == specialWavelengthCutoff ? specialTimeOfFlightCutoff
59 : conversionConstant * lowerWavelengthLimit;
60 const double maxTof = upperWavelengthLimit == specialWavelengthCutoff ? specialTimeOfFlightCutoff
61 : conversionConstant * upperWavelengthLimit;
62 return MinAndMaxTof(minTof, maxTof);
63}
64
65double getDistanceFromSourceForWorkspaceIndex(Mantid::API::MatrixWorkspace const *workspace,
66 const Mantid::API::SpectrumInfo &spectrumInfo, size_t workspaceIndex) {
67 const auto &detector = spectrumInfo.detector(workspaceIndex);
68 return detector.getDistance(*(workspace->getInstrument()->getSource()));
69}
70
71MinAndMaxTof getMinAndMaxTof(Mantid::API::MatrixWorkspace const *workspace,
72 const Mantid::API::SpectrumInfo &spectrumInfo, size_t workspaceIndex,
73 double lowerWavelengthLimit, double upperWavelengthLimit) {
74 const auto distanceFromSource = getDistanceFromSourceForWorkspaceIndex(workspace, spectrumInfo, workspaceIndex);
75 return getMinAndMaxTofForDistanceFromSoure(distanceFromSource, lowerWavelengthLimit, upperWavelengthLimit);
76}
77
86Mantid::HistogramData::Points getPoints(Mantid::API::MatrixWorkspace const *workspace, size_t workspaceIndex) {
87 auto points = workspace->points(workspaceIndex);
88 std::vector<double> doubledData(2 * points.size(), 0);
89 std::copy(std::begin(points), std::end(points), std::begin(doubledData));
90
91 // Calculate the doubled up bit. To do this we need to:
92 // 1. Get the last element of the original BinEdges
93 // 2. For each entry in the BinEdges calcualte the increment and add it to the
94 // last element. In addition
95 // we have to make sure that there is a spacing between the last element
96 // and the newly append last+1 element
97 // This spacing is taken to be the difference between the first and the
98 // second element
99 auto firstTof = points.front();
100 auto lastTof = points.back();
101 auto doubledDataIterator = doubledData.begin();
102 std::advance(doubledDataIterator, points.size());
103
104 double lastElementToNewElementSpacing = 0.0;
105 if (doubledData.size() > 1) {
106 lastElementToNewElementSpacing = doubledData[1] - doubledData[0];
107 }
108
109 for (auto pointsIterator = points.begin(); doubledDataIterator != doubledData.end();
110 ++doubledDataIterator, ++pointsIterator) {
111 auto newValue = lastTof + lastElementToNewElementSpacing + (*pointsIterator - firstTof);
112 *doubledDataIterator = newValue;
113 }
114
115 return Mantid::HistogramData::Points{doubledData};
116}
117
118MinAndMaxIndex getMinAndMaxIndex(const MinAndMaxTof &minMaxTof, const Mantid::HistogramData::Points &points) {
119 int minIndex = specialIndex;
120 int maxIndex = specialIndex;
121 const auto minCutOff = minMaxTof.minTof;
122 const auto maxCutOff = minMaxTof.maxTof;
123 int index = 0;
124 for (const auto &element : points) {
125 if (element < minCutOff) {
126 minIndex = index;
127 }
128
129 if (element > maxCutOff) {
130 maxIndex = index;
131 // We can break here since the min would have been set before the max
132 break;
133 }
134 ++index;
135 }
136
137 // We have to take care since the maxIndex can be a special index for two
138 // reasons
139 // 1. The maxCutOff is smaller than the smallest time of flight value of the
140 // workspace, then the special index index is correct
141 // 2. The maxCutOff is larger then the largest time of flight value of the
142 // workspace, then the last index is correct
143 if (maxIndex == specialIndex) {
144 if (points[points.size() - 1] < maxCutOff) {
145 maxIndex = static_cast<int>(points.size()) - 1;
146 }
147 }
148
149 // The min index is the index which is the largest lower bound index which is
150 // not in the TOF region, hence we need index + 1 as the
151 // lower bound index
152 minIndex += 1;
153
154 return MinAndMaxIndex(minIndex, maxIndex);
155}
156
157void setTofBelowLowerBoundToZero(std::vector<double> &doubledData, int minIndex) {
158 if (minIndex == specialIndex) {
159 return;
160 }
161 auto begin = doubledData.begin();
162 auto end = begin;
163 std::advance(end, minIndex);
164 std::fill(begin, end, 0.0);
165}
166
167void setTofAboveUpperBoundToZero(std::vector<double> &doubledData, int maxIndex) {
168 if (maxIndex >= static_cast<int>(doubledData.size()) - 1) {
169 return;
170 }
171 auto begin = doubledData.begin();
172 std::advance(begin, maxIndex);
173 auto end = doubledData.end();
174 std::fill(begin, end, 0.0);
175}
176
187Mantid::HistogramData::Counts getCounts(Mantid::API::MatrixWorkspace const *workspace, size_t workspaceIndex,
188 const MinAndMaxTof &minMaxTof, const Mantid::HistogramData::Points &points) {
189 // Create the data twice
190 auto counts = workspace->counts(workspaceIndex);
191 std::vector<double> doubledData(2 * counts.size(), 0);
192 auto doubledDataIterator = doubledData.begin();
193 std::copy(std::begin(counts), std::end(counts), doubledDataIterator);
194 std::advance(doubledDataIterator, counts.size());
195 std::copy(std::begin(counts), std::end(counts), doubledDataIterator);
196
197 // Now set everything to zero entires which correspond to TOF which is less
198 // than minTof and more than maxTof
199 auto minAndMaxIndex = getMinAndMaxIndex(minMaxTof, points);
200 if (minMaxTof.minTof != specialTimeOfFlightCutoff) {
201 setTofBelowLowerBoundToZero(doubledData, minAndMaxIndex.minIndex);
202 }
203
204 if (minMaxTof.maxTof != specialTimeOfFlightCutoff) {
205 setTofAboveUpperBoundToZero(doubledData, minAndMaxIndex.maxIndex);
206 }
207 return Mantid::HistogramData::Counts(doubledData);
208}
209
219std::vector<size_t> getWorkspaceIndicesForMonitors(Mantid::API::MatrixWorkspace *workspace) {
220 std::vector<size_t> workspaceIndices;
221 auto monitorWorkspace = workspace->monitorWorkspace();
222 if (monitorWorkspace) {
223 auto numberOfHistograms = monitorWorkspace->getNumberHistograms();
224 for (size_t index = 0; index < numberOfHistograms; ++index) {
225 const auto &spectrum = workspace->getSpectrum(index);
226 auto spectrumNumber = spectrum.getSpectrumNo();
227 auto workspaceIndex = workspace->getIndexFromSpectrumNumber(spectrumNumber);
228 workspaceIndices.emplace_back(workspaceIndex);
229 }
230 } else {
231 auto numberOfHistograms = workspace->getNumberHistograms();
232 const auto &spectrumInfo = workspace->spectrumInfo();
233 for (size_t workspaceIndex = 0; workspaceIndex < numberOfHistograms; ++workspaceIndex) {
234 if (spectrumInfo.isMonitor(workspaceIndex)) {
235 workspaceIndices.emplace_back(workspaceIndex);
236 }
237 }
238 }
239 return workspaceIndices;
240}
241} // namespace
242
243namespace Mantid::Algorithms {
244
247
248// Register the algorithm into the AlgorithmFactory
249DECLARE_ALGORITHM(UnwrapMonitorsInTOF)
250
251//----------------------------------------------------------------------------------------------
252
253
254UnwrapMonitorsInTOF::UnwrapMonitorsInTOF() { deprecatedDate("2025-04-01"); }
255
257const std::string UnwrapMonitorsInTOF::name() const { return "UnwrapMonitorsInTOF"; }
258
260int UnwrapMonitorsInTOF::version() const { return 1; }
261
263const std::string UnwrapMonitorsInTOF::category() const { return "CorrectionFunctions\\InstrumentCorrections"; }
264
266const std::string UnwrapMonitorsInTOF::summary() const {
267 return "Takes a TOF input workspace that contains 'raw' data and unwraps "
268 "monitor data "
269 "according to a specified wavelength range. The monitor spectra are "
270 "essentially "
271 "doubled and then trimmed to the specified wavelength range. If no "
272 "wavelength "
273 "range is specified (-1), then the doubled data is not trimmed. The "
274 "units of the output "
275 "workspace is in TOF. Note that currently only workspaces with "
276 "linearly binned monitor data "
277 "can be handled correctly.";
278}
279
280//----------------------------------------------------------------------------------------------
285 std::make_unique<WorkspaceProperty<Mantid::API::MatrixWorkspace>>("InputWorkspace", "", Direction::Input),
286 "An input workspace.");
288 std::make_unique<WorkspaceProperty<Mantid::API::MatrixWorkspace>>("OutputWorkspace", "", Direction::Output),
289 "An output workspace.");
290 declareProperty<double>("WavelengthMin", specialWavelengthCutoff, "A lower bound of the wavelength range.");
291 declareProperty<double>("WavelengthMax", specialWavelengthCutoff, "An upper bound of the wavelength range.");
292}
293
294//----------------------------------------------------------------------------------------------
298 // The unwrapping happens in three parts
299 // 1. We duplicate the monitor data, by appending the data to itself again.
300 // This means
301 // that at there is an interval in which the data is correct
302 // 2. Data which is outside of a certain equivalent wavelength range will be
303 // set to 0
304 Mantid::API::MatrixWorkspace_sptr inputWorkspace = getProperty("InputWorkspace");
305 const double lowerWavelengthLimit = getProperty("WavelengthMin");
306 const double upperWavelengthLimit = getProperty("WavelengthMax");
307
308 auto outputWorkspace = Mantid::API::MatrixWorkspace_sptr(inputWorkspace->clone());
309 const auto workspaceIndices = getWorkspaceIndicesForMonitors(outputWorkspace.get());
310
311 const auto &spectrumInfo = outputWorkspace->spectrumInfo();
312
313 for (const auto &workspaceIndex : workspaceIndices) {
314 const auto minMaxTof = getMinAndMaxTof(outputWorkspace.get(), spectrumInfo, workspaceIndex, lowerWavelengthLimit,
315 upperWavelengthLimit);
316 auto points = getPoints(outputWorkspace.get(), workspaceIndex);
317 auto counts = getCounts(outputWorkspace.get(), workspaceIndex, minMaxTof, points);
318 // Get the input histogram
319 auto inputHistogram = inputWorkspace->histogram(workspaceIndex);
320 auto spectrumIsHistogramData = inputHistogram.xMode() == Mantid::HistogramData::Histogram::XMode::BinEdges;
321 if (spectrumIsHistogramData) {
322 Mantid::HistogramData::BinEdges binEdges(points);
323 Mantid::HistogramData::Histogram histogram(binEdges, counts);
324 outputWorkspace->setHistogram(workspaceIndex, histogram);
325 } else {
326 Mantid::HistogramData::Histogram histogram(points, counts);
327 outputWorkspace->setHistogram(workspaceIndex, histogram);
328 }
329 }
330 setProperty("OutputWorkspace", outputWorkspace);
331}
332
337std::map<std::string, std::string> UnwrapMonitorsInTOF::validateInputs() {
338 std::map<std::string, std::string> invalidProperties;
339 // The lower wavelength boundary needs to be smaller than the upper wavelength
340 // boundary
341 const double lowerWavelengthLimit = getProperty("WavelengthMin");
342 const double upperWavelengthLimit = getProperty("WavelengthMax");
343 if (lowerWavelengthLimit != specialWavelengthCutoff && lowerWavelengthLimit < 0.0) {
344 invalidProperties["WavelengthMin"] = "The lower wavelength limit must be set to a positive value.";
345 }
346
347 if (upperWavelengthLimit != specialWavelengthCutoff && upperWavelengthLimit < 0.0) {
348 invalidProperties["WavelengthMax"] = "The upper wavelength limit must be set to a positive value.";
349 }
350
351 if (lowerWavelengthLimit != specialWavelengthCutoff && upperWavelengthLimit != specialWavelengthCutoff &&
352 lowerWavelengthLimit >= upperWavelengthLimit) {
353 invalidProperties["WavelengthMin"] = "The lower wavelength limit must be "
354 "smaller than the upper wavelnegth "
355 "limit.";
356 invalidProperties["WavelengthMax"] = "The lower wavelength limit must be "
357 "smaller than the upper wavelnegth "
358 "limit.";
359 }
360
361 return invalidProperties;
362}
363
364} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
IPeaksWorkspace_sptr workspace
std::map< DeltaEMode::Type, std::string > index
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.
Base MatrixWorkspace Abstract Class.
API::SpectrumInfo is an intermediate step towards a SpectrumInfo that is part of Instrument-2....
bool isMonitor(const size_t index) const
Returns true if the detector(s) associated with the spectrum are monitors.
const Geometry::IDetector & detector(const size_t index) const
Return a const reference to the detector or detector group of the spectrum with given index.
A property class for workspaces.
UnwrapMonitorsInTOF : Handles workspaces which contain monitors that recorded data which spills over ...
const std::string category() const override
Algorithm's category for identification.
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.
void exec() override
Execute the algorithm.
void init() override
Initialize the algorithm's properties.
const std::string name() const override
Algorithms name for identification.
std::map< std::string, std::string > validateInputs() override
Check the inputs for invalid values.
double getDistance(const IComponent &comp) const override=0
Get the distance of this detector object from another Component.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
static constexpr double NeutronMass
Mass of the neutron in kg.
static constexpr double h
Planck constant in J*s.
Describes the direction (within an algorithm) of a Property.
Definition Property.h:50
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54