Mantid
Loading...
Searching...
No Matches
UnwrapSNS.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 +
20
21#include <limits>
22
23namespace Mantid::Algorithms {
24
25DECLARE_ALGORITHM(UnwrapSNS)
26
27using namespace Kernel;
28using namespace API;
29using DataObjects::EventWorkspace;
30using std::size_t;
31
34 : m_conversionConstant(0.), m_inputWS(), m_inputEvWS(), m_LRef(0.), m_Tmin(0.), m_Tmax(0.), m_frameWidth(0.),
35 m_numberOfSpectra(0), m_XSize(0) {
36 deprecatedDate("2025-03-24");
37}
38
41 auto wsValidator = std::make_shared<CompositeValidator>();
42 wsValidator->add<WorkspaceUnitValidator>("TOF");
43 wsValidator->add<HistogramValidator>();
44 wsValidator->add<RawCountValidator>();
45 wsValidator->add<InstrumentValidator>();
47 std::make_unique<WorkspaceProperty<MatrixWorkspace>>("InputWorkspace", "", Direction::Input, wsValidator),
48 "Contains numbers counts against time of flight (TOF).");
49 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>("OutputWorkspace", "", Direction::Output),
50 "This workspace will be in the units of time of flight. (See "
51 "http://docs.mantidproject.org/concepts/UnitFactory)");
52
53 auto validator = std::make_shared<BoundedValidator<double>>();
54 validator->setLower(0.01);
55 declareProperty("LRef", 0.0, validator,
56 "A distance at which it is possible to deduce if a particle "
57 "is from the current or a past frame based on its arrival "
58 "time. This time criterion can be set with the property "
59 "below e.g. correct when arrival time < Tmin.");
60 validator->setLower(0.01);
61 declareProperty("Tmin", Mantid::EMPTY_DBL(), validator,
62 "With LRef this defines the maximum speed expected for "
63 "particles. For each count or time bin the mean particle "
64 "speed is calculated and if this is greater than LRef/Tmin "
65 "its TOF is corrected.");
66 validator->setLower(0.01);
67 declareProperty("Tmax", Mantid::EMPTY_DBL(), validator,
68 "The maximum time of flight of the data used for the width "
69 "of the frame. If not set the maximum time of flight of the "
70 "data is used.");
71
72 // Calculate and set the constant factor for the conversion to wavelength
73 const double TOFisinMicroseconds = 1e6;
74 const double toAngstroms = 1e10;
75 m_conversionConstant = (PhysicalConstants::h * toAngstroms) / (PhysicalConstants::NeutronMass * TOFisinMicroseconds);
76}
77
86 // Get the input workspace
87 m_inputWS = getProperty("InputWorkspace");
88
89 // Get the "reference" flightpath (currently passed in as a property)
90 m_LRef = getProperty("LRef");
91
92 m_XSize = static_cast<int>(m_inputWS->x(0).size());
93 m_numberOfSpectra = static_cast<int>(m_inputWS->getNumberHistograms());
94 g_log.debug() << "Number of spectra in input workspace: " << m_numberOfSpectra << "\n";
95
96 // go off and do the event version if appropriate
97 m_inputEvWS = std::dynamic_pointer_cast<const EventWorkspace>(m_inputWS);
98 if ((m_inputEvWS != nullptr)) // && ! this->getProperty("ForceHist")) // TODO
99 // remove ForceHist option
100 {
101 this->execEvent();
102 return;
103 }
104
105 this->getTofRangeData(false);
106
107 // set up the progress bar
108 m_progress = std::make_unique<Progress>(this, 0.0, 1.0, m_numberOfSpectra);
109
110 MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace");
111 if (outputWS != m_inputWS) {
113 setProperty("OutputWorkspace", outputWS);
114 }
115
116 // without the primary flight path the algorithm cannot work
117 const auto &spectrumInfo = m_inputWS->spectrumInfo();
118 const double L1 = spectrumInfo.l1();
119
121 for (int workspaceIndex = 0; workspaceIndex < m_numberOfSpectra; workspaceIndex++) {
123 if (!spectrumInfo.hasDetectors(workspaceIndex)) {
124 // If the detector flightpath is missing, zero the data
125 g_log.debug() << "Detector information for workspace index " << workspaceIndex << " is not available.\n";
126 outputWS->setSharedX(workspaceIndex, m_inputWS->sharedX(workspaceIndex));
127 outputWS->mutableY(workspaceIndex) = 0.0;
128 outputWS->mutableE(workspaceIndex) = 0.0;
129 } else {
130 const double Ld = L1 + spectrumInfo.l2(workspaceIndex);
131 // fix the x-axis
132 std::vector<double> timeBins;
133 size_t pivot = this->unwrapX(m_inputWS->x(workspaceIndex), timeBins, Ld);
134 outputWS->setBinEdges(workspaceIndex, std::move(timeBins));
135
136 pivot++; // one-off difference between x and y
137
138 // fix the counts using the pivot point
139 auto &yIn = m_inputWS->y(workspaceIndex);
140 auto &yOut = outputWS->mutableY(workspaceIndex);
141
142 auto lengthFirstPartY = std::distance(yIn.begin() + pivot, yIn.end());
143 std::copy(yIn.begin() + pivot, yIn.end(), yOut.begin());
144 std::copy(yIn.begin(), yIn.begin() + pivot, yOut.begin() + lengthFirstPartY);
145
146 // fix the uncertainties using the pivot point
147 auto &eIn = m_inputWS->e(workspaceIndex);
148 auto &eOut = outputWS->mutableE(workspaceIndex);
149
150 auto lengthFirstPartE = std::distance(eIn.begin() + pivot, eIn.end());
151 std::copy(eIn.begin() + pivot, eIn.end(), eOut.begin());
152 std::copy(eIn.begin(), eIn.begin() + pivot, eOut.begin() + lengthFirstPartE);
153 }
154 m_progress->report();
156 }
158
159 m_inputWS.reset();
160 this->runMaskDetectors();
161}
162
164 // set up the output workspace
165 MatrixWorkspace_sptr matrixOutW = this->getProperty("OutputWorkspace");
166 if (matrixOutW != m_inputWS) {
167 matrixOutW = m_inputWS->clone();
168 setProperty("OutputWorkspace", matrixOutW);
169 }
170 auto outW = std::dynamic_pointer_cast<EventWorkspace>(matrixOutW);
171
172 // set up the progress bar
173 m_progress = std::make_unique<Progress>(this, 0.0, 1.0, m_numberOfSpectra * 2);
174
175 // algorithm assumes the data is sorted so it can jump out early
176 outW->sortAll(Mantid::DataObjects::TOF_SORT, m_progress.get());
177
178 this->getTofRangeData(true);
179
180 // without the primary flight path the algorithm cannot work
181 const auto &spectrumInfo = m_inputWS->spectrumInfo();
182 const double L1 = spectrumInfo.l1();
183
184 // do the actual work
185 for (int workspaceIndex = 0; workspaceIndex < m_numberOfSpectra; workspaceIndex++) {
186 std::size_t numEvents = outW->getSpectrum(workspaceIndex).getNumberEvents();
187 double Ld = -1.0;
188 if (spectrumInfo.hasDetectors(workspaceIndex))
189 Ld = L1 + spectrumInfo.l2(workspaceIndex);
190
191 if (outW->x(0).size() > 2) {
192 std::vector<double> time_bins;
193 this->unwrapX(m_inputWS->x(workspaceIndex), time_bins, Ld);
194 outW->setBinEdges(workspaceIndex, std::move(time_bins));
195 } else {
196 outW->setSharedX(workspaceIndex, m_inputWS->sharedX(workspaceIndex));
197 }
198 if (numEvents > 0) {
199 std::vector<double> times(numEvents);
200 outW->getSpectrum(workspaceIndex).getTofs(times);
201 double filterVal = m_Tmin * Ld / m_LRef;
202 for (size_t j = 0; j < numEvents; j++) {
203 if (times[j] < filterVal)
204 times[j] += m_frameWidth;
205 else
206 break; // stop filtering
207 }
208 outW->getSpectrum(workspaceIndex).setTofs(times);
209 }
210 m_progress->report();
211 }
212
213 outW->clearMRU();
214 this->runMaskDetectors();
215}
216
217int UnwrapSNS::unwrapX(const Mantid::HistogramData::HistogramX &datain, std::vector<double> &dataout,
218 const double &Ld) {
219 std::vector<double> tempX_L; // lower half - to be frame wrapped
220 tempX_L.reserve(m_XSize);
221 tempX_L.clear();
222 std::vector<double> tempX_U; // upper half - to not be frame wrapped
223 tempX_U.reserve(m_XSize);
224 tempX_U.clear();
225
226 double filterVal = m_Tmin * Ld / m_LRef;
227 dataout.clear();
228 int specialBin = 0;
229 for (int bin = 0; bin < m_XSize; ++bin) {
230 // This is the time-of-flight value under consideration in the current
231 // iteration of the loop
232 const double tof = datain[bin];
233 if (tof < filterVal) {
234 tempX_L.emplace_back(tof + m_frameWidth);
235 // Record the bins that fall in this range for copying over the data &
236 // errors
237 if (specialBin < bin)
238 specialBin = bin;
239 } else {
240 tempX_U.emplace_back(tof);
241 }
242 } // loop over X values
243
244 // now put it back into the vector supplied
245 dataout.clear();
246 dataout.insert(dataout.begin(), tempX_U.begin(), tempX_U.end());
247 dataout.insert(dataout.end(), tempX_L.begin(), tempX_L.end());
248 assert(datain.size() == dataout.size());
249
250 return specialBin;
251}
252
253void UnwrapSNS::getTofRangeData(const bool isEvent) {
254 // get the Tmin/Tmax properties
255 m_Tmin = this->getProperty("Tmin");
256 m_Tmax = this->getProperty("Tmax");
257
258 // if either the values are not specified by properties, find them from the
259 // data
260 double empty = Mantid::EMPTY_DBL();
261 if ((m_Tmin == empty) || (m_Tmax == empty)) {
262 // get data min/max values
263 double dataTmin;
264 double dataTmax;
265 if (isEvent) {
266 m_inputEvWS->sortAll(DataObjects::TOF_SORT, nullptr);
267 m_inputEvWS->getEventXMinMax(dataTmin, dataTmax);
268 } else {
269 m_inputWS->getXMinMax(dataTmin, dataTmax);
270 }
271
272 // fix the unspecified values
273 if (m_Tmin == empty) {
274 m_Tmin = dataTmin;
275 }
276 if (m_Tmax == empty) {
277 m_Tmax = dataTmax;
278 }
279 }
280
281 // check the frame width
283
284 g_log.information() << "Frame range in microseconds is: " << m_Tmin << " - " << m_Tmax << "\n";
285 if (m_Tmin < 0.)
286 throw std::runtime_error("Cannot have Tmin less than zero");
287 if (m_Tmin > m_Tmax)
288 throw std::runtime_error("Have case of Tmin > Tmax");
289
290 g_log.information() << "Wavelength cuttoff is : " << (m_conversionConstant * m_Tmin / m_LRef)
291 << "Angstrom, Frame width is: " << m_frameWidth << "microseconds\n";
292}
293
295 auto alg = createChildAlgorithm("MaskDetectors");
296 alg->setProperty<MatrixWorkspace_sptr>("Workspace", this->getProperty("OutputWorkspace"));
297 alg->setProperty<MatrixWorkspace_sptr>("MaskedWorkspace", this->getProperty("InputWorkspace"));
298 if (!alg->execute())
299 throw std::runtime_error("MaskDetectors Child Algorithm has not executed successfully");
300}
301
302} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
#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.
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.
Kernel::Logger & g_log
Definition Algorithm.h:422
void deprecatedDate(const std::string &)
The date the algorithm was deprecated on.
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.
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...
double m_conversionConstant
The constant used in the conversion from TOF.
Definition UnwrapSNS.h:60
double m_Tmin
The start of the time-of-flight frame.
Definition UnwrapSNS.h:65
double m_Tmax
The end of the time-of-flight frame.
Definition UnwrapSNS.h:66
double m_frameWidth
The width of the frame cached to speed up things.
Definition UnwrapSNS.h:67
void init() override
Initialisation method.
Definition UnwrapSNS.cpp:40
UnwrapSNS()
Default constructor.
Definition UnwrapSNS.cpp:33
double m_LRef
The 'reference' flightpath.
Definition UnwrapSNS.h:64
DataObjects::EventWorkspace_const_sptr m_inputEvWS
Pointer to the input event workspace.
Definition UnwrapSNS.h:63
int unwrapX(const Mantid::HistogramData::HistogramX &, std::vector< double > &dataout, const double &Ld)
API::MatrixWorkspace_const_sptr m_inputWS
to wavelength
Definition UnwrapSNS.h:62
int m_XSize
The size of the X vectors in the input workspace.
Definition UnwrapSNS.h:69
std::unique_ptr< API::Progress > m_progress
Progress reporting.
Definition UnwrapSNS.h:71
void exec() override
Executes the algorithm.
Definition UnwrapSNS.cpp:85
int m_numberOfSpectra
The number of spectra in the workspace.
Definition UnwrapSNS.h:68
void getTofRangeData(const bool)
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:145
void information(const std::string &msg)
Logs at information level.
Definition Logger.cpp:136
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
std::size_t numEvents(Nexus::File &file, bool &hasTotalCounts, bool &oldNeXusFileNames, const std::string &prefix, const Nexus::NexusDescriptor &descriptor)
Get the number of events in the currently opened group.
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.
static constexpr double NeutronMass
Mass of the neutron in kg.
static constexpr double h
Planck constant in J*s.
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition EmptyValues.h:42
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54