Mantid
Loading...
Searching...
No Matches
InelasticDiffRotDiscreteCircle.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
11#include "MantidAPI/IFunction.h"
18
19#include "MantidTypes/SpectrumDefinition.h"
20
21#include <cmath>
22#include <limits>
23#include <sstream>
24
26
27namespace {
28Mantid::Kernel::Logger g_log("InelasticDiffDiffRotDiscreteCircle");
29}
30
32
33DECLARE_FUNCTION(InelasticDiffRotDiscreteCircle)
34
35
39 this->declareParameter("Intensity", 1.0, "scaling factor [no units]");
40 this->declareParameter("Radius", 1.0, "Circle radius [Angstroms]");
41 this->declareParameter("Decay", 1.0,
42 "Inverse of transition rate, in nanoseconds "
43 "if energy in micro-ev, or picoseconds if "
44 "energy in mili-eV");
45 this->declareParameter("Shift", 0.0, "Shift in the centre of the peak");
46
47 this->declareAttribute("N", API::IFunction::Attribute(3));
48 declareAttributes();
49}
50
55 // Ensure positive values for Intensity, Radius, and decay
56 auto IntensityConstraint =
57 std::make_unique<BConstraint>(this, "Intensity", std::numeric_limits<double>::epsilon(), true);
58 this->addConstraint(std::move(IntensityConstraint));
59
60 auto RadiusConstraint = std::make_unique<BConstraint>(this, "Radius", std::numeric_limits<double>::epsilon(), true);
61 this->addConstraint(std::move(RadiusConstraint));
62
63 auto DecayConstraint = std::make_unique<BConstraint>(this, "Decay", std::numeric_limits<double>::epsilon(), true);
64 this->addConstraint(std::move(DecayConstraint));
65}
66
74void InelasticDiffRotDiscreteCircle::function1D(double *out, const double *xValues, const size_t nData) const {
75
76 auto I = this->getParameter("Intensity");
77 auto R = this->getParameter("Radius");
78 auto rate = m_hbar / this->getParameter("Decay"); // micro-eV or mili-eV
79 auto N = this->getAttribute("N").asInt();
80
81 // Retrieve Q-value from the appropriate attribute
82 double Q;
83 if (this->getAttribute("Q").asDouble() == EMPTY_DBL()) {
84 if (m_qValueCache.empty()) {
85 throw std::runtime_error("No Q attribute provided and cannot retrieve from workspace.");
86 }
87 const int specIdx = this->getAttribute("WorkspaceIndex").asInt();
88 Q = m_qValueCache[specIdx];
89
90 g_log.debug() << "Get Q value for workspace index " << specIdx << ": " << Q << '\n';
91 } else {
92 Q = getAttribute("Q").asDouble();
93
94 g_log.debug() << "Using Q attribute: " << Q << '\n';
95 }
96
97 std::vector<double> sph(N);
98 for (int k = 1; k < N; k++) {
99 double x = 2 * Q * R * sin(M_PI * k / N);
100 // spherical Besell function of order zero 'j0' is sin(x)/x
101 sph[k] = sin(x) / x;
102 }
103
104 std::vector<double> ratel(N);
105 for (int l = 1; l < N; l++) {
106 // notice that 0 < l/N < 1
107 ratel[l] = rate * 4 * pow(sin(M_PI * l / N), 2);
108 }
109
110 const auto shift = this->getParameter("Shift");
111 for (size_t i = 0; i < nData; i++) {
112 double w = xValues[i] - shift;
113 double S = 0.0;
114 for (int l = 1; l < N; l++) {
115 double lorentzian = ratel[l] / (ratel[l] * ratel[l] + w * w);
116 double al = 0.0;
117 for (int k = 1; k < N; k++) { // case k==N after the loop
118 double y = 2 * M_PI * l * k / N;
119 al += cos(y) * sph[k];
120 }
121 al += 1; // limit for j0 when k==N, or x==0
122 al /= N;
123 S += al * lorentzian;
124 }
125 out[i] = I * S / M_PI;
126 }
127}
128
134void InelasticDiffRotDiscreteCircle::setWorkspace(std::shared_ptr<const API::Workspace> ws) {
135 m_qValueCache.clear();
136
137 auto workspace = std::dynamic_pointer_cast<const API::MatrixWorkspace>(ws);
138 if (!workspace)
139 return;
140
141 const auto &spectrumInfo = workspace->spectrumInfo();
142 const auto &detectorIDs = workspace->detectorInfo().detectorIDs();
143 for (size_t idx = 0; idx < spectrumInfo.size(); idx++) {
144 if (!spectrumInfo.hasDetectors(idx)) {
145 m_qValueCache.clear();
146 g_log.information("Cannot populate Q values from workspace - no detectors set.");
147 break;
148 }
149
150 const auto detectorIndex = spectrumInfo.spectrumDefinition(idx)[0].first;
151
152 try {
153 double efixed = workspace->getEFixed(detectorIDs[detectorIndex]);
154 double usingTheta = 0.5 * spectrumInfo.twoTheta(idx);
155
157
158 m_qValueCache.emplace_back(q);
159 } catch (std::runtime_error &) {
160 m_qValueCache.clear();
161 g_log.information("Cannot populate Q values from workspace - could not "
162 "find EFixed value.");
163 return;
164 }
165 }
166}
167
168} // namespace Mantid::CurveFitting::Functions
#define DECLARE_FUNCTION(classname)
Macro for declaring a new type of function to be used with the FunctionFactory.
IPeaksWorkspace_sptr workspace
Definition: IndexPeaks.cpp:114
IntArray detectorIndex
static Kernel::Logger g_log
Logger instance.
Definition: IFunction1D.h:74
Attribute is a non-fitting parameter.
Definition: IFunction.h:282
int asInt() const
Returns int value if attribute is a int, throws exception otherwise.
Definition: IFunction.cpp:726
double asDouble() const
Returns double value if attribute is a double, throws exception otherwise.
Definition: IFunction.cpp:739
virtual Attribute getAttribute(const std::string &name) const
Return a value of attribute attName.
Definition: IFunction.cpp:1394
virtual void addConstraint(std::unique_ptr< IConstraint > ic)
Add a constraint to function.
Definition: IFunction.cpp:376
double getParameter(size_t i) const override
Get i-th parameter.
A boundary constraint is designed to be used to set either upper or lower (or both) boundaries on a s...
void setWorkspace(std::shared_ptr< const API::Workspace > ws) override
Cache Q values from the workspace.
void function1D(double *out, const double *xValues, const size_t nData) const override
Calculate function values on an energy domain.
The Logger class is in charge of the publishing messages from the framework through various channels.
Definition: Logger.h:52
void debug(const std::string &msg)
Logs at debug level.
Definition: Logger.cpp:114
void information(const std::string &msg)
Logs at information level.
Definition: Logger.cpp:105
static double convertToElasticQ(const double theta, const double efixed)
Convert to ElasticQ from Energy.
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition: EmptyValues.h:43