Mantid
Loading...
Searching...
No Matches
UnwrapMonitor.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 +
8#include "MantidAPI/Axis.h"
21
22namespace Mantid::Algorithms {
23
24DECLARE_ALGORITHM(UnwrapMonitor)
25
26using namespace Kernel;
27using namespace API;
28
31 : m_conversionConstant(0.), m_inputWS(), m_LRef(0.), m_Tmin(0.), m_Tmax(0.), m_XSize(0) {}
32
35 auto wsValidator = std::make_shared<CompositeValidator>();
36 wsValidator->add<WorkspaceUnitValidator>("TOF");
37 wsValidator->add<HistogramValidator>();
38 wsValidator->add<RawCountValidator>();
39 wsValidator->add<InstrumentValidator>();
41 std::make_unique<WorkspaceProperty<MatrixWorkspace>>("InputWorkspace", "", Direction::Input, wsValidator),
42 "A workspace with x values in units of TOF and y values in counts");
43 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>("OutputWorkspace", "", Direction::Output),
44 "The name of the workspace to be created as the output of the algorithm");
45
46 auto validator = std::make_shared<BoundedValidator<double>>();
47 validator->setLower(0.01);
48 declareProperty("LRef", 0.0, validator, "The length of the reference flight path (in metres)");
49
50 declareProperty("JoinWavelength", 0.0, Direction::Output);
51
52 // Calculate and set the constant factor for the conversion to wavelength
53 const double TOFisinMicroseconds = 1e6;
54 const double toAngstroms = 1e10;
55 m_conversionConstant = (PhysicalConstants::h * toAngstroms) / (PhysicalConstants::NeutronMass * TOFisinMicroseconds);
56}
57
66 // Get the input workspace
67 m_inputWS = getProperty("InputWorkspace");
68 // Get the number of spectra in this workspace
69 const auto numberOfSpectra = static_cast<int>(m_inputWS->getNumberHistograms());
70 g_log.debug() << "Number of spectra in input workspace: " << numberOfSpectra << '\n';
71
72 // Get the "reference" flightpath (currently passed in as a property)
73 m_LRef = getProperty("LRef");
74 // Get the min & max frame values
75 m_Tmin = m_inputWS->x(0).front();
76 m_Tmax = m_inputWS->x(0).back();
77 g_log.debug() << "Frame range in microseconds is: " << m_Tmin << " - " << m_Tmax << '\n';
78 m_XSize = m_inputWS->x(0).size();
79
80 // Need a new workspace. Will just be used temporarily until the data is
81 // rebinned.
82 MatrixWorkspace_sptr tempWS = WorkspaceFactory::Instance().create(m_inputWS, numberOfSpectra, m_XSize, m_XSize - 1);
83 // Set the correct X unit on the output workspace
84 tempWS->getAxis(0)->unit() = UnitFactory::Instance().create("Wavelength");
85
86 // This will be used later to store the maximum number of bin BOUNDARIES for
87 // the rebinning
88 size_t max_bins = 0;
89
90 const auto &spectrumInfo = m_inputWS->spectrumInfo();
91 const double L1 = spectrumInfo.l1();
92
93 m_progress = std::make_unique<Progress>(this, 0.0, 1.0, numberOfSpectra);
94 // Loop over the histograms (detector spectra)
95 for (int i = 0; i < numberOfSpectra; ++i) {
96 if (!spectrumInfo.hasDetectors(i)) {
97 // If the detector flightpath is missing, zero the data
98 g_log.debug() << "Detector information for workspace index " << i << " is not available.\n";
99 tempWS->mutableX(i) = 0.0;
100 tempWS->mutableY(i) = 0.0;
101 tempWS->mutableE(i) = 0.0;
102 continue;
103 }
104
105 // Getting the unwrapped data is a three step process.
106 // 1. We ge the unwrapped version of the x data.
107 // 2. Then we get the unwrapped version of the y and e data for
108 // which we require the x data from the previous step
109 // 3. Finally we need to set the newly unwrapped data on the
110 // histogram
111
112 // Unwrap the x data. Returns the bin ranges that end up being used
113 const double Ld = L1 + spectrumInfo.l2(i);
114 std::vector<double> newX;
115 const std::vector<int> rangeBounds = this->unwrapX(newX, i, Ld);
116
117 // Unwrap the y & e data according to the ranges found above
118 std::vector<double> newY;
119 std::vector<double> newE;
120 this->unwrapYandE(tempWS, i, rangeBounds, newY, newE);
121
122 // Now set the new X, Y and E values on the Histogram
123 auto histogram = tempWS->histogram(i);
124 tempWS->setHistogram(i, Mantid::HistogramData::BinEdges(std::move(newX)),
125 Mantid::HistogramData::Counts(std::move(newY)),
126 Mantid::HistogramData::CountStandardDeviations(std::move(newE)));
127
128 // Get the maximum number of bins (excluding monitors) for the rebinning
129 // below
130 if (!spectrumInfo.isMonitor(i)) {
131 const size_t XLen = tempWS->x(i).size();
132 if (XLen > max_bins)
133 max_bins = XLen;
134 }
135 m_progress->report();
136 } // loop over spectra
137
138 // Only rebin if more that just a single monitor spectrum in the input WS
139 if (numberOfSpectra > 1) {
140 // Calculate the minimum and maximum possible wavelengths for the rebinning
141 const double minLambda = (m_conversionConstant * m_Tmin) / m_LRef;
142 const double maxLambda = (m_conversionConstant * m_Tmax) / m_LRef;
143 // Rebin the data into common wavelength bins
144 MatrixWorkspace_sptr outputWS = this->rebin(tempWS, minLambda, maxLambda, max_bins - 1);
145
146 g_log.debug() << "Rebinned workspace has " << outputWS->getNumberHistograms() << " histograms of "
147 << outputWS->blocksize() << " bins each\n";
148 setProperty("OutputWorkspace", outputWS);
149 } else
150 setProperty("OutputWorkspace", tempWS);
151
152 m_inputWS.reset();
153}
154
163const std::vector<int> UnwrapMonitor::unwrapX(std::vector<double> &newX, const int &spectrum, const double &Ld) {
164 // Create and initalise the vector that will store the bin ranges, and will be
165 // returned
166 // Elements are: 0 - Lower range start, 1 - Lower range end, 2 - Upper range
167 // start
168 std::vector<int> binRange(3, -1);
169
170 // Calculate cut-off times
171 const double T1 = m_Tmax - (m_Tmin * (1 - (Ld / m_LRef)));
172 const double T2 = m_Tmax * (Ld / m_LRef);
173
174 // Create a temporary vector to store the lower range of the unwrapped
175 // histograms
176 std::vector<double> tempX_L;
177 tempX_L.reserve(m_XSize); // Doing this possible gives a small efficiency increase
178 // Create a vector for the upper range. Make it a reference to the output
179 // histogram to save an assignment later
180 newX.clear();
181 newX.reserve(m_XSize);
182
183 // Get a reference to the input x data
184 const auto &xdata = m_inputWS->x(spectrum);
185 // Loop over histogram, selecting bins in appropriate ranges.
186 // At the moment, the data in the bin in which a cut-off sits is excluded.
187 for (unsigned int bin = 0; bin < m_XSize; ++bin) {
188 // This is the time-of-flight value under consideration in the current
189 // iteration of the loop
190 const double tof = xdata[bin];
191 // First deal with bins where m_Tmin < tof < T2
192 if (tof < T2) {
193 const double wavelength = (m_conversionConstant * tof) / Ld;
194 tempX_L.emplace_back(wavelength);
195 // Record the bins that fall in this range for copying over the data &
196 // errors
197 if (binRange[0] == -1)
198 binRange[0] = bin;
199 binRange[1] = bin;
200 }
201 // Now do the bins where T1 < tof < m_Tmax
202 else if (tof > T1) {
203 const double velocity = Ld / (tof - m_Tmax + m_Tmin);
204 const double wavelength = m_conversionConstant / velocity;
205 newX.emplace_back(wavelength);
206 // Remove the duplicate boundary bin
207 if (tof == m_Tmax && std::abs(wavelength - tempX_L.front()) < 1.0e-5)
208 newX.pop_back();
209 // Record the bins that fall in this range for copying over the data &
210 // errors
211 if (binRange[2] == -1)
212 binRange[2] = bin;
213 }
214 } // loop over X values
215
216 // Deal with the (rare) case that a detector (e.g. downstream monitor) is at a
217 // longer flightpath than m_LRef
218 if (Ld > m_LRef) {
219 std::pair<int, int> binLimits = this->handleFrameOverlapped(xdata, Ld, tempX_L);
220 binRange[0] = binLimits.first;
221 binRange[1] = binLimits.second;
222 }
223
224 // Record the point at which the unwrapped sections are joined, first time
225 // through only
226 Property *join = getProperty("JoinWavelength");
227 if (join->isDefault()) {
228 g_log.information() << "Joining wavelength: " << tempX_L.front() << " Angstrom\n";
229 setProperty("JoinWavelength", tempX_L.front());
230 }
231
232 // Append first vector to back of second
233 newX.insert(newX.end(), tempX_L.begin(), tempX_L.end());
234
235 return binRange;
236}
237
241std::pair<int, int> UnwrapMonitor::handleFrameOverlapped(const Mantid::HistogramData::HistogramX &xdata,
242 const double &Ld, std::vector<double> &tempX) {
243 // Calculate the interval to exclude
244 const double Dt = (m_Tmax - m_Tmin) * (1 - (m_LRef / Ld));
245 // This gives us new minimum & maximum tof values
246 const double minT = m_Tmin + Dt;
247 const double maxT = m_Tmax - Dt;
248 // Can have situation where Ld is so much larger than Lref that everything
249 // would be excluded.
250 // This is an invalid input - warn and leave spectrum unwrapped
251 if (minT > maxT) {
252 g_log.warning() << "Invalid input, Ld (" << Ld << ") >> Lref (" << m_LRef
253 << "). Current spectrum will not be unwrapped.\n";
254 return std::make_pair(0, static_cast<int>(xdata.size() - 1));
255 }
256
257 int min = 0, max = static_cast<int>(xdata.size());
258 for (unsigned int j = 0; j < m_XSize; ++j) {
259 const double T = xdata[j];
260 if (T < minT) {
261 min = j + 1;
262 tempX.erase(tempX.begin());
263 } else if (T > maxT) {
264 tempX.erase(tempX.end() - (max - j), tempX.end());
265 max = j - 1;
266 break;
267 }
268 }
269 return std::make_pair(min, max);
270}
271
281void UnwrapMonitor::unwrapYandE(const API::MatrixWorkspace_sptr &tempWS, const int &spectrum,
282 const std::vector<int> &rangeBounds, std::vector<double> &newY,
283 std::vector<double> &newE) {
284 // Copy over the relevant ranges of Y & E data
285 std::vector<double> &Y = newY;
286 std::vector<double> &E = newE;
287 // Get references to the input data
288 const auto &YIn = m_inputWS->y(spectrum);
289 const auto &EIn = m_inputWS->e(spectrum);
290 if (rangeBounds[2] != -1) {
291 // Copy in the upper range
292 Y.assign(YIn.begin() + rangeBounds[2], YIn.end());
293 E.assign(EIn.begin() + rangeBounds[2], EIn.end());
294 // Propagate masking, if necessary
295 if (m_inputWS->hasMaskedBins(spectrum)) {
296 const MatrixWorkspace::MaskList &inputMasks = m_inputWS->maskedBins(spectrum);
297 MatrixWorkspace::MaskList::const_iterator it;
298 for (it = inputMasks.begin(); it != inputMasks.end(); ++it) {
299 if (static_cast<int>((*it).first) >= rangeBounds[2])
300 tempWS->flagMasked(spectrum, (*it).first - rangeBounds[2], (*it).second);
301 }
302 }
303 } else {
304 // Y & E are references to existing vector. Assign above clears them, so
305 // need to explicitly here
306 Y.clear();
307 E.clear();
308 }
309 if (rangeBounds[0] != -1 && rangeBounds[1] > 0) {
310 // Now append the lower range
311 auto YStart = YIn.begin();
312 auto EStart = EIn.begin();
313 Y.insert(Y.end(), YStart + rangeBounds[0], YStart + rangeBounds[1]);
314 E.insert(E.end(), EStart + rangeBounds[0], EStart + rangeBounds[1]);
315 // Propagate masking, if necessary
316 if (m_inputWS->hasMaskedBins(spectrum)) {
317 const MatrixWorkspace::MaskList &inputMasks = m_inputWS->maskedBins(spectrum);
318 for (const auto &inputMask : inputMasks) {
319 const auto maskIndex = static_cast<int>(inputMask.first);
320 if (maskIndex >= rangeBounds[0] && maskIndex < rangeBounds[1])
321 tempWS->flagMasked(spectrum, maskIndex - rangeBounds[0], inputMask.second);
322 }
323 }
324 }
325}
326
336 const double &max, const size_t &numBins) {
337 // Calculate the width of a bin
338 const double step = (max - min) / static_cast<double>(numBins);
339
340 // Create a Rebin child algorithm
341 auto childAlg = createChildAlgorithm("Rebin");
342 childAlg->setProperty<MatrixWorkspace_sptr>("InputWorkspace", workspace);
343 childAlg->setPropertyValue("OutputWorkspace", "Anonymous");
344
345 // Construct the vector that holds the rebin parameters and set the property
346 std::vector<double> paramArray = {min, step, max};
347 childAlg->setProperty<std::vector<double>>("Params", paramArray);
348 g_log.debug() << "Rebinning unwrapped data into " << numBins << " bins of width " << step
349 << " Angstroms, running from " << min << " to " << max << '\n';
350
351 childAlg->executeAsChildAlg();
352 return childAlg->getProperty("OutputWorkspace");
353}
354
355} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
IPeaksWorkspace_sptr workspace
Definition: IndexPeaks.cpp:114
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
virtual std::shared_ptr< Algorithm > createChildAlgorithm(const std::string &name, const double startProgress=-1., const double endProgress=-1., const bool enableLogging=true, const int &version=-1)
Create a Child Algorithm.
Definition: Algorithm.cpp:842
Kernel::Logger & g_log
Definition: Algorithm.h:451
A validator which checks that a workspace contains histogram data (the default) or point data as requ...
A validator which checks that a workspace has a valid instrument.
std::map< size_t, double > MaskList
Masked bins for each spectrum are stored as a set of pairs containing <bin index, weight>
A validator which checks that a workspace contains raw counts in its bins.
A property class for workspaces.
A validator which checks that the unit of the workspace referred to by a WorkspaceProperty is the exp...
UnwrapMonitor()
Default constructor.
API::MatrixWorkspace_const_sptr m_inputWS
to wavelength
Definition: UnwrapMonitor.h:67
double m_LRef
The 'reference' flightpath.
Definition: UnwrapMonitor.h:68
double m_Tmin
The start of the time-of-flight frame.
Definition: UnwrapMonitor.h:69
void init() override
Initialisation method.
size_t m_XSize
The size of the X vectors in the input workspace.
Definition: UnwrapMonitor.h:71
std::unique_ptr< API::Progress > m_progress
Progress reporting.
Definition: UnwrapMonitor.h:73
API::MatrixWorkspace_sptr rebin(const API::MatrixWorkspace_sptr &workspace, const double &min, const double &max, const size_t &numBins)
Rebins the data into common bins of wavelength.
std::pair< int, int > handleFrameOverlapped(const Mantid::HistogramData::HistogramX &xdata, const double &Ld, std::vector< double > &tempX)
Deals with the (rare) case where the flightpath is longer than the reference Note that in this case b...
double m_Tmax
The end of the time-of-flight frame.
Definition: UnwrapMonitor.h:70
const std::vector< int > unwrapX(std::vector< double > &newX, const int &spectrum, const double &Ld)
Unwraps an X array, converting the units to wavelength along the way.
double m_conversionConstant
The constant used in the conversion from TOF.
Definition: UnwrapMonitor.h:65
void unwrapYandE(const API::MatrixWorkspace_sptr &tempWS, const int &spectrum, const std::vector< int > &rangeBounds, std::vector< double > &newY, std::vector< double > &newE)
Unwraps the Y & E vectors of a spectrum according to the ranges found in unwrapX.
void exec() override
Executes the algorithm.
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 warning(const std::string &msg)
Logs at warning level.
Definition: Logger.cpp:86
void information(const std::string &msg)
Logs at information level.
Definition: Logger.cpp:105
Base class for properties.
Definition: Property.h:94
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
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.
@ Input
An input workspace.
Definition: Property.h:53
@ Output
An output workspace.
Definition: Property.h:54