Mantid
Loading...
Searching...
No Matches
TOFSANSResolution.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
21namespace Mantid::Algorithms {
22
23// Register the algorithm into the AlgorithmFactory
24DECLARE_ALGORITHM(TOFSANSResolution)
25
26using namespace Kernel;
27using namespace API;
28using namespace Geometry;
29using namespace DataObjects;
30
32
34 declareProperty(std::make_unique<WorkspaceProperty<>>("InputWorkspace", "", Direction::InOut,
35 std::make_shared<WorkspaceUnitValidator>("MomentumTransfer")),
36 "Name the workspace to calculate the resolution for");
37
38 auto wsValidator = std::make_shared<WorkspaceUnitValidator>("Wavelength");
39 declareProperty(std::make_unique<WorkspaceProperty<>>("ReducedWorkspace", "", Direction::Input, wsValidator),
40 "I(Q) workspace");
41 declareProperty(std::make_unique<ArrayProperty<double>>("OutputBinning", std::make_shared<RebinParamsValidator>()));
42
43 declareProperty("MinWavelength", EMPTY_DBL(), "Minimum wavelength to use.");
44 declareProperty("MaxWavelength", EMPTY_DBL(), "Maximum wavelength to use.");
45
46 auto positiveDouble = std::make_shared<BoundedValidator<double>>();
47 positiveDouble->setLower(0);
48 declareProperty("PixelSizeX", 5.15, positiveDouble, "Pixel size in the X direction (mm).");
49 declareProperty("PixelSizeY", 5.15, positiveDouble, "Pixel size in the Y direction (mm).");
50 declareProperty("SampleApertureRadius", 5.0, positiveDouble, "Sample aperture radius (mm).");
51 declareProperty("SourceApertureRadius", 10.0, positiveDouble, "Source aperture radius (mm).");
52 declareProperty("DeltaT", 250.0, positiveDouble, "TOF spread (microsec).");
53}
54
55/*
56 * Double Boltzmann fit to the TOF resolution as a function of wavelength
57 */
59 UNUSED_ARG(wl);
60 return m_wl_resolution;
61}
62
63/*
64 * Return the effective pixel size in X, in meters
65 */
67 double pixel_size_x = getProperty("PixelSizeX");
68 return pixel_size_x / 1000.0;
69}
70
71/*
72 * Return the effective pixel size in Y, in meters
73 */
75 double pixel_size_y = getProperty("PixelSizeY");
76 return pixel_size_y / 1000.0;
77}
78
80 MatrixWorkspace_sptr iqWS = getProperty("InputWorkspace");
81 MatrixWorkspace_sptr reducedWS = getProperty("ReducedWorkspace");
82 EventWorkspace_sptr reducedEventWS = std::dynamic_pointer_cast<EventWorkspace>(reducedWS);
83 const double min_wl = getProperty("MinWavelength");
84 const double max_wl = getProperty("MaxWavelength");
85 double pixel_size_x = getEffectiveXPixelSize();
86 double pixel_size_y = getEffectiveYPixelSize();
87 double R1 = getProperty("SourceApertureRadius");
88 double R2 = getProperty("SampleApertureRadius");
89 // Convert to meters
90 R1 /= 1000.0;
91 R2 /= 1000.0;
92 m_wl_resolution = getProperty("DeltaT");
93
94 // Calculate the output binning
95 const std::vector<double> binParams = getProperty("OutputBinning");
96
97 // Count histogram for normalization
98 const auto xLength = static_cast<int>(iqWS->x(0).size());
99 std::vector<double> XNorm(xLength - 1, 0.0);
100
101 // Create workspaces with each component of the resolution for debugging
102 // purposes
103 MatrixWorkspace_sptr thetaWS = WorkspaceFactory::Instance().create(iqWS);
104 declareProperty(std::make_unique<WorkspaceProperty<>>("ThetaError", "", Direction::Output));
105 setPropertyValue("ThetaError", "__" + iqWS->getName() + "_theta_error");
106 setProperty("ThetaError", thetaWS);
107 thetaWS->setSharedX(0, iqWS->sharedX(0));
108 auto &ThetaY = thetaWS->mutableY(0);
109
111 declareProperty(std::make_unique<WorkspaceProperty<>>("TOFError", "", Direction::Output));
112 setPropertyValue("TOFError", "__" + iqWS->getName() + "_tof_error");
113 setProperty("TOFError", tofWS);
114 tofWS->setSharedX(0, iqWS->sharedX(0));
115 auto &TOFY = tofWS->mutableY(0);
116
117 // Initialize Dq
118 HistogramData::HistogramDx DxOut(xLength - 1, 0.0);
119
120 const auto numberOfSpectra = static_cast<int>(reducedWS->getNumberHistograms());
121 Progress progress(this, 0.0, 1.0, numberOfSpectra);
122
123 const auto &spectrumInfo = reducedWS->spectrumInfo();
124 const double L1 = spectrumInfo.l1();
125
126 PARALLEL_FOR_IF(Kernel::threadSafe(*reducedWS, *iqWS))
127 for (int i = 0; i < numberOfSpectra; i++) {
129 if (!spectrumInfo.hasDetectors(i)) {
130 g_log.warning() << "Workspace index " << i << " has no detector assigned to it - discarding\n";
131 continue;
132 }
133 // Skip if we have a monitor or if the detector is masked.
134 if (spectrumInfo.isMonitor(i) || spectrumInfo.isMasked(i))
135 continue;
136
137 const double L2 = spectrumInfo.l2(i);
138
139 // Multiplicative factor to go from lambda to Q
140 // Don't get fooled by the function name...
141 const double theta = spectrumInfo.twoTheta(i);
142 const double factor = 4.0 * M_PI * sin(0.5 * theta);
143
144 const auto &XIn = reducedWS->x(i);
145 const auto &YIn = reducedWS->y(i);
146 const auto wlLength = static_cast<int>(XIn.size());
147
148 std::vector<double> _dx(xLength - 1, 0.0);
149 std::vector<double> _norm(xLength - 1, 0.0);
150 std::vector<double> _tofy(xLength - 1, 0.0);
151 std::vector<double> _thetay(xLength - 1, 0.0);
152
153 for (int j = 0; j < wlLength - 1; j++) {
154 const double wl = (XIn[j + 1] + XIn[j]) / 2.0;
155 const double wl_bin = XIn[j + 1] - XIn[j];
156 if (!isEmpty(min_wl) && wl < min_wl)
157 continue;
158 if (!isEmpty(max_wl) && wl > max_wl)
159 continue;
160 const double q = factor / wl;
161 int iq = 0;
162
163 // Bin assignment depends on whether we have log or linear bins
164 // TODO: change this so that we don't have to pass in the binning
165 // parameters
166 if (binParams[1] > 0.0) {
167 iq = static_cast<int>(floor((q - binParams[0]) / binParams[1]));
168 } else {
169 iq = static_cast<int>(floor(log(q / binParams[0]) / log(1.0 - binParams[1])));
170 }
171
172 const double src_to_pixel = L1 + L2;
173 const double dTheta2 =
174 (3.0 * R1 * R1 / (L1 * L1) + 3.0 * R2 * R2 * src_to_pixel * src_to_pixel / (L1 * L1 * L2 * L2) +
175 2.0 * (pixel_size_x * pixel_size_x + pixel_size_y * pixel_size_y) / (L2 * L2)) /
176 12.0;
177
178 // This term is related to the TOF resolution
179 const double dwl_over_wl = 3.9560 * getTOFResolution(wl) / (1000.0 * (L1 + L2) * wl);
180 // This term is related to the wavelength binning
181 const double wl_bin_over_wl = wl_bin / wl;
182 const double dq_over_q =
183 std::sqrt(dTheta2 / (theta * theta) + dwl_over_wl * dwl_over_wl + wl_bin_over_wl * wl_bin_over_wl);
184
185 // By using only events with a positive weight, we use only the data
186 // distribution and leave out the background events.
187 // Note: we are looping over bins, therefore the xLength-1.
188 if (iq >= 0 && iq < xLength - 1 && !std::isnan(dq_over_q) && dq_over_q > 0 && YIn[j] > 0) {
189 _dx[iq] += q * dq_over_q * YIn[j];
190 _norm[iq] += YIn[j];
191 _tofy[iq] += q * std::fabs(dwl_over_wl) * YIn[j];
192 _thetay[iq] += q * std::sqrt(dTheta2) / theta * YIn[j];
193 }
194 }
195
196 // Move over the distributions for that pixel
197 // Note: we are looping over bins, therefore the xLength-1.
198 PARALLEL_CRITICAL(iq) /* Write to shared memory - must protect */
199 for (int iq = 0; iq < xLength - 1; iq++) {
200 DxOut[iq] += _dx[iq];
201 XNorm[iq] += _norm[iq];
202 TOFY[iq] += _tofy[iq];
203 ThetaY[iq] += _thetay[iq];
204 }
205
206 progress.report("Computing Q resolution");
208 }
210
211 // Normalize according to the chosen weighting scheme
212 // Note: we are looping over bins, therefore the xLength-1.
213 for (int i = 0; i < xLength - 1; i++) {
214 if (XNorm[i] == 0)
215 continue;
216 DxOut[i] /= XNorm[i];
217 TOFY[i] /= XNorm[i];
218 ThetaY[i] /= XNorm[i];
219 }
220 iqWS->setPointStandardDeviations(0, std::move(DxOut));
221}
222} // 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_CRITICAL(name)
#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.
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
Definition: System.h:64
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
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
Definition: Algorithm.cpp:231
void setPropertyValue(const std::string &name, const std::string &value) override
Set the value of a property by string N.B.
Definition: Algorithm.cpp:1975
static bool isEmpty(const NumT toCheck)
checks that the value was not set by users, uses the value in empty double/int.
Helper class for reporting progress from algorithms.
Definition: Progress.h:25
A property class for workspaces.
virtual double getEffectiveYPixelSize()
Return the effective pixel size in the y-direction.
double m_wl_resolution
Wavelength resolution (constant for all wavelengths)
virtual double getEffectiveXPixelSize()
Return the effective pixel size in the x-direction.
void init() override
Initialisation code.
void exec() override
Execution code.
virtual double getTOFResolution(double wl)
Return the TOF resolution for a particular wavelength.
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 warning(const std::string &msg)
Logs at warning level.
Definition: Logger.cpp:86
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::shared_ptr< EventWorkspace > EventWorkspace_sptr
shared pointer to the EventWorkspace 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 double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition: EmptyValues.h:43
@ InOut
Both an input & output workspace.
Definition: Property.h:55
@ Input
An input workspace.
Definition: Property.h:53
@ Output
An output workspace.
Definition: Property.h:54