Mantid
Loading...
Searching...
No Matches
HyspecScharpfCorrection.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 +
9#include "MantidAPI/Run.h"
18
19namespace Mantid::Algorithms {
20
23using namespace DataObjects;
24
25// Register the algorithm into the AlgorithmFactory
26DECLARE_ALGORITHM(HyspecScharpfCorrection)
27
28//----------------------------------------------------------------------------------------------
29
30
31const std::string HyspecScharpfCorrection::name() const { return "HyspecScharpfCorrection"; }
32
34int HyspecScharpfCorrection::version() const { return 1; }
35
37const std::string HyspecScharpfCorrection::category() const {
38 return "CorrectionFunctions\\SpecialCorrections; Inelastic\\Corrections";
39}
40
42const std::string HyspecScharpfCorrection::summary() const {
43 return "Apply polarization factor as part of getting the spin incoherent "
44 "scattering";
45}
46
47//----------------------------------------------------------------------------------------------
51 auto wsValidator = std::make_shared<Mantid::Kernel::CompositeValidator>();
52 wsValidator->add<Mantid::API::WorkspaceUnitValidator>("DeltaE");
53 wsValidator->add<Mantid::API::InstrumentValidator>();
55 std::make_unique<WorkspaceProperty<API::MatrixWorkspace>>("InputWorkspace", "", Direction::Input, wsValidator),
56 "An input workspace in units of energy transfer.");
57
58 auto angleValidator = std::make_shared<Mantid::Kernel::BoundedValidator<double>>();
59 angleValidator->setLower(-180.0);
60 angleValidator->setUpper(180.0);
61 declareProperty("PolarizationAngle", EMPTY_DBL(), angleValidator,
62 "In plane angle between polatrization and incident beam"
63 "Must be between -180 and +180 degrees");
64 auto precisionValidator = std::make_shared<Mantid::Kernel::BoundedValidator<double>>();
65 precisionValidator->setLower(0.0);
66 precisionValidator->setUpper(1.0);
67 declareProperty("Precision", 0.1, precisionValidator,
68 "If cosine of twice the "
69 "Scharpf angle is closer to 0 than the precision, the intensities "
70 "and errors will be set to 0");
71 declareProperty(std::make_unique<WorkspaceProperty<API::MatrixWorkspace>>("OutputWorkspace", "", Direction::Output),
72 "An output workspace.");
73}
74
75//----------------------------------------------------------------------------------------------
79 // Get the workspaces
80 m_inputWS = this->getProperty("InputWorkspace");
81 m_outputWS = this->getProperty("OutputWorkspace");
82 m_angle = getProperty("PolarizationAngle");
83 m_angle *= M_PI / 180.;
84 m_precision = getProperty("Precision");
85 if (m_inputWS->run().hasProperty("Ei")) {
86 m_Ei = m_inputWS->run().getPropertyValueAsType<double>("Ei");
87 } else {
88 throw std::invalid_argument("No Ei value has been set or stored within the run information.");
89 }
90
91 // Check if it is an event workspace
92 if (dynamic_cast<const Mantid::DataObjects::EventWorkspace *>(m_inputWS.get()) != nullptr) {
93 this->execEvent();
94 return;
95 }
96
97 // If input and output workspaces are not the same, create a new workspace for
98 // the output
99 if (m_outputWS != m_inputWS) {
100 m_outputWS = create<API::MatrixWorkspace>(*m_inputWS);
101 }
102
103 const auto &spectrumInfo = m_inputWS->spectrumInfo();
104
105 // Get number of spectra in this workspace
106 const auto numberOfSpectra = static_cast<int64_t>(m_inputWS->getNumberHistograms());
107 Mantid::Kernel::V3D samplePos = spectrumInfo.samplePosition();
108 const auto refFrame = m_inputWS->getInstrument()->getReferenceFrame();
109 API::Progress prog(this, 0.0, 1.0, numberOfSpectra);
111 for (int64_t i = 0; i < numberOfSpectra; ++i) {
113 auto &yOut = m_outputWS->mutableY(i);
114 auto &eOut = m_outputWS->mutableE(i);
115
116 const auto &xIn = m_inputWS->points(i); // get the centers
117 auto &yIn = m_inputWS->y(i);
118 auto &eIn = m_inputWS->e(i);
119 // Copy the energy transfer axis
120 m_outputWS->setSharedX(i, m_inputWS->sharedX(i));
121
122 prog.report();
123 // continue if no detectors, if monitor, or is masked
124 if ((!spectrumInfo.hasDetectors(i)) || spectrumInfo.isMonitor(i) || spectrumInfo.isMasked(i)) {
125 continue;
126 }
127 // get detector info and calculate the in plane angle
128 Mantid::Kernel::V3D detPos = spectrumInfo.position(i);
129 const auto l2 = detPos - samplePos;
130 const double thPlane = std::atan2(l2[refFrame->pointingHorizontal()], l2[refFrame->pointingAlongBeam()]);
131 size_t spectrumSize = xIn.size();
132 for (size_t j = 0; j < spectrumSize; ++j) {
133 double factor = 0.;
134 if (xIn[j] < m_Ei) {
135 double kfki = std::sqrt(1. - xIn[j] / m_Ei); // k_f/k_i
136 factor = static_cast<double>(this->calculateFactor(kfki, thPlane));
137 }
138 yOut[j] = yIn[j] * factor;
139 eOut[j] = eIn[j] * factor;
140 }
142 } // end for i
144 this->setProperty("OutputWorkspace", m_outputWS);
145}
146
150 g_log.information("Processing event workspace");
151
152 // If input and output workspaces are not the same, create a new workspace for
153 // the output
154 if (m_outputWS != m_inputWS) {
155 m_outputWS = m_inputWS->clone();
156 setProperty("OutputWorkspace", m_outputWS);
157 }
158
160 std::dynamic_pointer_cast<Mantid::DataObjects::EventWorkspace>(m_outputWS);
161
162 const auto &spectrumInfo = m_inputWS->spectrumInfo();
163
164 // Get number of spectra in this workspace
165 const auto numberOfSpectra = static_cast<int64_t>(m_inputWS->getNumberHistograms());
166 Mantid::Kernel::V3D samplePos = spectrumInfo.samplePosition();
167 const auto refFrame = m_inputWS->getInstrument()->getReferenceFrame();
168 API::Progress prog(this, 0.0, 1.0, numberOfSpectra);
170 for (int64_t i = 0; i < numberOfSpectra; ++i) {
172 prog.report();
173 // continue if no detectors, if monitor, or is masked
174 if ((!spectrumInfo.hasDetectors(i)) || spectrumInfo.isMonitor(i) || spectrumInfo.isMasked(i)) {
175 continue;
176 }
177 Mantid::Kernel::V3D detPos = spectrumInfo.position(i);
178 const auto l2 = detPos - samplePos;
179 const double thPlane = std::atan2(l2[refFrame->pointingHorizontal()], l2[refFrame->pointingAlongBeam()]);
180 // Do the correction
181 auto &evlist = eventWS->getSpectrum(i);
182 switch (evlist.getEventType()) {
183 case Mantid::API::TOF:
184 // Switch to weights if needed.
185 evlist.switchTo(Mantid::API::WEIGHTED);
186 /* no break */
187 // Fall through
188
190 ScharpfEventHelper(evlist.getWeightedEvents(), thPlane);
191 break;
192
194 ScharpfEventHelper(evlist.getWeightedEventsNoTime(), thPlane);
195 break;
196 }
198 } // end for i
200}
201
202template <class T> void HyspecScharpfCorrection::ScharpfEventHelper(std::vector<T> &wevector, double thPlane) {
203 for (auto it = wevector.begin(); it < wevector.end();) {
204 double Ef = m_Ei - it->tof();
205 if (Ef <= 0) {
206 it = wevector.erase(it);
207 } else {
208 double kfki = std::sqrt(Ef / m_Ei);
209
210 float factor = this->calculateFactor(kfki, thPlane);
211
212 it->m_weight *= factor;
213 it->m_errorSquared *= factor * factor;
214 ++it;
215 }
216 }
217}
218
219float HyspecScharpfCorrection::calculateFactor(const double kfki, const double thPlane) {
220 // angle between in plane Q and z axis
221 const double angleQ = std::atan2(-kfki * std::sin(thPlane), 1. - kfki * std::cos(thPlane));
222 // Scarpf agle = angle - angleQ
223 auto factor = static_cast<float>(std::cos(2. * (m_angle - angleQ)));
224 // set intensity to 0 if the Scarpf angle is close to 45 degrees
225 if (std::abs(factor) > m_precision) {
226 factor = 1.f / factor;
227 } else {
228 factor = 0.;
229 }
230
231 return (factor);
232}
233
234} // 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.
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
A validator which checks that a workspace has a valid instrument.
Helper class for reporting progress from algorithms.
Definition: Progress.h:25
A property class for workspaces.
A validator which checks that the unit of the workspace referred to by a WorkspaceProperty is the exp...
HyspecScharpfCorrection : Divide by cos(2alpha) where alpha is the angle between incident beam and th...
Mantid::API::MatrixWorkspace_const_sptr m_inputWS
The user selected (input) workspace.
void ScharpfEventHelper(std::vector< T > &wevector, double thPlane)
Execute Scharpf correction for event lists.
const std::string category() const override
Algorithm's category for identification.
void exec() override
Execute the algorithm.
void init() override
Initialize the algorithm's properties.
const std::string summary() const override
Algorithm's summary for use in the GUI and help.
double m_angle
In plane angle beween polarization and incident beam (in degrees)
int version() const override
Algorithm's version for identification.
float calculateFactor(const double kfki, const double thPlane)
calculate the Scharph angle correction factor
double m_precision
Lower limit for abs(cos(2*Scharpf angle)), below which intensities are 0.
Mantid::API::MatrixWorkspace_sptr m_outputWS
The output workspace, maybe the same as the input one.
This class is intended to fulfill the design specified in <https://github.com/mantidproject/documents...
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
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
Class for 3D vectors.
Definition: V3D.h:34
@ WEIGHTED_NOTIME
Definition: IEventList.h:18
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
STL namespace.
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