Mantid
Loading...
Searching...
No Matches
ModeratorTzeroLinear.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"
9#include "MantidAPI/Run.h"
16#include "MantidHistogramData/Histogram.h"
19
20namespace Mantid::Algorithms {
21
22// Register the algorithm into the AlgorithmFactory
23DECLARE_ALGORITHM(ModeratorTzeroLinear)
24
25using namespace Mantid::Kernel;
26using namespace Mantid::API;
27using namespace Mantid::Geometry;
28using namespace Mantid::DataObjects;
29using namespace Mantid::HistogramData;
30
31// A reference to the logger is provided by the base class, it is called g_log.
32// It is used to print out information, warning and error messages
33
34ModeratorTzeroLinear::ModeratorTzeroLinear() : API::Algorithm(), m_gradient(0.), m_intercept(0.), m_instrument() {}
35
36const std::string ModeratorTzeroLinear::name() const { return "ModeratorTzeroLinear"; }
37
38const std::string ModeratorTzeroLinear::summary() const {
39 return "Corrects the time of flight of an indirect geometry instrument by a "
40 "time offset that is linearly dependent on the wavelength of the "
41 "neutron after passing through the moderator.";
42}
43
44int ModeratorTzeroLinear::version() const { return 1; }
45
46const std::string ModeratorTzeroLinear::category() const { return "CorrectionFunctions\\InstrumentCorrections"; }
47
49 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>("InputWorkspace", "", Direction::Input,
50 std::make_shared<WorkspaceUnitValidator>("TOF")),
51 "The name of the input workspace, containing events and/or "
52 "histogram data, in units of time-of-flight");
53 declareProperty("Gradient", EMPTY_DBL(),
54 "Wavelength dependent TOF shift, units in microsec/Angstrom. "
55 "Overrides the value stored in the instrument object");
56 declareProperty("Intercept", EMPTY_DBL(),
57 "TOF shift, units in microseconds. Overrides the value"
58 "stored in the instrument object");
59 // declare the output workspace
60 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>("OutputWorkspace", "", Direction::Output),
61 "The name of the output workspace");
62
63} // end of void ModeratorTzeroLinear::init()
64
66 // retrieve the input workspace.
67 const MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace");
68
69 // Get a pointer to the instrument contained in the workspace
70 m_instrument = inputWS->getInstrument();
71
72 // deltaE-mode (should be "indirect")
73 try {
74 const std::vector<std::string> Emode = m_instrument->getStringParameter("deltaE-mode");
75 if (Emode.empty())
76 throw Exception::InstrumentDefinitionError("Unable to retrieve "
77 "instrument geometry (direct "
78 "or indirect) parameter",
79 inputWS->getTitle());
80 if (Emode[0] != "indirect")
81 throw Exception::InstrumentDefinitionError("Instrument geometry must be of type indirect.");
82 } catch (Exception::NotFoundError &) {
83 g_log.error("Unable to retrieve instrument geometry (direct or indirect) "
84 "parameter");
85 throw Exception::InstrumentDefinitionError("Unable to retrieve instrument geometry (direct or indirect) parameter",
86 inputWS->getTitle());
87 }
88
89 // gradient, intercept constants
90 try {
91
92 // determine which Gradient to use
93 const std::vector<double> gradientParam = m_instrument->getNumberParameter("Moderator.TimeZero.gradient");
94 const double gradientParamManual = getProperty("Gradient");
95 if (gradientParam.empty() && gradientParamManual == EMPTY_DBL())
96 throw Exception::InstrumentDefinitionError("Unable to retrieve Moderator Time Zero parameters (gradient)",
97 inputWS->getTitle());
98 if (gradientParamManual != EMPTY_DBL()) {
99 m_gradient = gradientParamManual;
100 } else {
101 m_gradient = gradientParam[0]; //[gradient]=microsecond/Angstrom
102 }
103 // conversion factor for gradient from microsecond/Angstrom to meters
104 double convfactor = 1.0e4 * PhysicalConstants::h / PhysicalConstants::NeutronMass;
105 m_gradient *= convfactor; //[gradient] = meter
106
107 // determine which Intercept to use
108 const std::vector<double> interceptParam = m_instrument->getNumberParameter("Moderator.TimeZero.intercept");
109 const double interceptParamManual = getProperty("Intercept");
110 if (interceptParam.empty() && interceptParamManual == EMPTY_DBL())
111 throw Exception::InstrumentDefinitionError("Unable to retrieve Moderator Time Zero parameters (intercept)",
112 inputWS->getTitle());
113 if (interceptParamManual != EMPTY_DBL()) {
114 m_intercept = interceptParamManual;
115 } else {
116 m_intercept = interceptParam[0]; //[intercept]=microsecond
117 }
118
119 g_log.debug() << "Moderator Time Zero: gradient=" << m_gradient << "intercept=" << m_intercept << '\n';
120 } catch (Exception::NotFoundError &) {
121 g_log.error("Unable to retrieve Moderator Time Zero parameters (gradient "
122 "and intercept)");
123 throw Exception::InstrumentDefinitionError("Unable to retrieve Moderator "
124 "Time Zero parameters (gradient "
125 "and intercept)",
126 inputWS->getTitle());
127 }
128
129 // Run execEvent if eventWorkSpace
130 EventWorkspace_const_sptr eventWS = std::dynamic_pointer_cast<const EventWorkspace>(inputWS);
131 if (eventWS != nullptr) {
132 execEvent();
133 return;
134 }
135
136 MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace");
137 // Check whether input = output to see whether a new workspace is required.
138 if (outputWS != inputWS) {
139 // Create new workspace for output from old
140 outputWS = create<MatrixWorkspace>(*inputWS);
141 }
142
143 // do the shift in X
144 const auto &spectrumInfo = inputWS->spectrumInfo();
145 const size_t numHists = inputWS->getNumberHistograms();
146 Progress prog(this, 0.0, 1.0, numHists); // report progress of algorithm
147 PARALLEL_FOR_IF(Kernel::threadSafe(*inputWS, *outputWS))
148 for (int i = 0; i < static_cast<int>(numHists); ++i) {
150 double t_f, L_i;
151 auto wsIndex = static_cast<size_t>(i);
152 calculateTfLi(spectrumInfo, wsIndex, t_f, L_i);
153
154 outputWS->setHistogram(i, inputWS->histogram(i));
155 // shift the time of flights
156 if (t_f >= 0) // t_f < 0 when no detector info is available
157 {
158 const double scaling = L_i / (L_i + m_gradient);
159 const double offset = (1 - scaling) * t_f - scaling * m_intercept;
160 auto &outbins = outputWS->mutableX(i);
161 outbins *= scaling;
162 outbins += offset;
163 }
164 prog.report();
166 }
168
169 // Copy units
170 if (inputWS->getAxis(0)->unit()) {
171 outputWS->getAxis(0)->unit() = inputWS->getAxis(0)->unit();
172 }
173 try {
174 if (inputWS->getAxis(1)->unit()) {
175 outputWS->getAxis(1)->unit() = inputWS->getAxis(1)->unit();
176 }
177 } catch (Exception::IndexError &) {
178 // OK, so this isn't a Workspace2D
179 }
180
181 // Assign it to the output workspace property
182 setProperty("OutputWorkspace", outputWS);
183}
184
186 g_log.information("Processing event workspace");
187
188 const MatrixWorkspace_const_sptr matrixInputWS = getProperty("InputWorkspace");
189
190 // generate the output workspace pointer
191 MatrixWorkspace_sptr matrixOutputWS = getProperty("OutputWorkspace");
192 if (matrixOutputWS != matrixInputWS) {
193 matrixOutputWS = matrixInputWS->clone();
194 setProperty("OutputWorkspace", matrixOutputWS);
195 }
196 auto outputWS = std::dynamic_pointer_cast<EventWorkspace>(matrixOutputWS);
197
198 // Loop over the spectra
199 const auto &spectrumInfo = matrixOutputWS->spectrumInfo();
200 const size_t numHists = outputWS->getNumberHistograms();
201 Progress prog(this, 0.0, 1.0, numHists); // report progress of algorithm
203 for (int i = 0; i < static_cast<int>(numHists); ++i) {
204 auto wsIndex = static_cast<size_t>(i);
206 EventList &evlist = outputWS->getSpectrum(wsIndex);
207 if (evlist.getNumberEvents() > 0) // don't bother with empty lists
208 {
209 // Calculate the time from sample to detector 'i'
210 double t_f, L_i;
211 calculateTfLi(spectrumInfo, wsIndex, t_f, L_i);
212 if (t_f >= 0) {
213 const double scaling = L_i / (L_i + m_gradient);
214 // Calculate new time of flight, TOF'=scaling*(TOF-t_f-intercept)+t_f =
215 // scaling*TOF + (1-scaling)*t_f - scaling*intercept
216 evlist.convertTof(scaling, (1 - scaling) * t_f - scaling * m_intercept);
217 }
218 }
219 prog.report();
221 }
223 outputWS->clearMRU(); // Clears the Most Recent Used lists */
224} // end of void ModeratorTzeroLinear::execEvent()
225
226// calculate time from sample to detector
227void ModeratorTzeroLinear::calculateTfLi(const SpectrumInfo &spectrumInfo, size_t i, double &t_f, double &L_i) {
228 static const double convFact = 1.0e-6 * sqrt(2 * PhysicalConstants::meV / PhysicalConstants::NeutronMass);
229 static const double TfError = -1.0; // signal error when calculating final
230 // time
231
232 if (!spectrumInfo.hasDetectors(i)) {
233 t_f = TfError;
234 return;
235 }
236
237 if (spectrumInfo.isMonitor(i)) {
238 L_i = spectrumInfo.sourcePosition().distance(spectrumInfo.position(i));
239 t_f = 0.0; // t_f=0.0 since there is no sample to detector path
240 } else {
241 L_i = spectrumInfo.l1();
242 // Get final energy E_f, final velocity v_f
243 auto wsProp = spectrumInfo.detector(i).getNumberParameter("Efixed");
244 if (!wsProp.empty()) {
245 double E_f = wsProp.at(0); //[E_f]=meV
246 double v_f = convFact * sqrt(E_f); //[v_f]=meter/microsec
247 t_f = spectrumInfo.l2(i) / v_f;
248 } else {
249 g_log.debug() << "Efixed not found for detector " << i << '\n';
250 t_f = TfError;
251 }
252 }
253}
254
255} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
#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.
Base class from which all concrete algorithm classes should be derived.
Definition: Algorithm.h:85
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
Helper class for reporting progress from algorithms.
Definition: Progress.h:25
API::SpectrumInfo is an intermediate step towards a SpectrumInfo that is part of Instrument-2....
Definition: SpectrumInfo.h:53
bool isMonitor(const size_t index) const
Returns true if the detector(s) associated with the spectrum are monitors.
Kernel::V3D sourcePosition() const
Returns the source position.
bool hasDetectors(const size_t index) const
Returns true if the spectrum is associated with detectors in the instrument.
Kernel::V3D position(const size_t index) const
Returns the position of the spectrum with given index.
double l2(const size_t index) const
Returns L2 (distance from sample to spectrum).
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.
double l1() const
Returns L1 (distance from source to sample).
A property class for workspaces.
const std::string summary() const override
Summary of algorithms purpose.
void init() override
Virtual method - must be overridden by concrete algorithm.
const std::string category() const override
Algorithm's category for identification.
void exec() override
Virtual method - must be overridden by concrete algorithm.
const std::string name() const override
Algorithm's name.
void calculateTfLi(const API::SpectrumInfo &spectrumInfo, size_t i, double &t_f, double &L_i)
int version() const override
Algorithm's version.
Geometry::Instrument_const_sptr m_instrument
A class for holding :
Definition: EventList.h:56
virtual std::vector< double > getNumberParameter(const std::string &pname, bool recursive=true) const =0
Get a parameter defined as a double.
Exception for index errors.
Definition: Exception.h:284
Exception for errors associated with the instrument definition.
Definition: Exception.h:220
Exception for when an item is not found in a collection.
Definition: Exception.h:145
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 error(const std::string &msg)
Logs at error level.
Definition: Logger.cpp:77
void information(const std::string &msg)
Logs at information level.
Definition: Logger.cpp:105
void report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
Definition: ProgressBase.h:51
double distance(const V3D &v) const noexcept
Calculates the distance between two vectors.
Definition: V3D.h:287
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::shared_ptr< const EventWorkspace > EventWorkspace_const_sptr
shared pointer to a const Workspace2D
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
static constexpr double NeutronMass
Mass of the neutron in kg.
static constexpr double h
Planck constant in J*s.
static constexpr double meV
1 meV in Joules.
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition: EmptyValues.h:43
@ Input
An input workspace.
Definition: Property.h:53
@ Output
An output workspace.
Definition: Property.h:54