Mantid
Loading...
Searching...
No Matches
Voigt.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 +
7//----------------------------------------------------------------------------------------------
8// Includes
9//----------------------------------------------------------------------------------------------
11
13
14#include <cmath>
15#include <limits>
16
18
19using namespace CurveFitting;
21
22namespace {
24// Coefficients for approximation using 4 lorentzians
25const size_t NLORENTZIANS = 4;
26
27const double COEFFA[NLORENTZIANS] = {-1.2150, -1.3509, -1.2150, -1.3509};
28const double COEFFB[NLORENTZIANS] = {1.2359, 0.3786, -1.2359, -0.3786};
29const double COEFFC[NLORENTZIANS] = {-0.3085, 0.5906, -0.3085, 0.5906};
30const double COEFFD[NLORENTZIANS] = {0.0210, -1.1858, -0.0210, 1.1858};
31
32const char *LORENTZ_AMP = "LorentzAmp";
33const char *LORENTZ_POS = "LorentzPos";
34const char *LORENTZ_FWHM = "LorentzFWHM";
35const char *GAUSSIAN_FWHM = "GaussianFWHM";
36
37const double SQRTLN2 = std::sqrt(M_LN2);
38const double SQRTPI = std::sqrt(M_PI);
40} // namespace
41
46 declareParameter(LORENTZ_AMP, 0.0, "Value of the Lorentzian amplitude");
47 declareParameter(LORENTZ_POS, 0.0, "Position of the Lorentzian peak");
48 declareParameter(LORENTZ_FWHM, 0.0, "Value of the full-width half-maximum for the Lorentzian");
49 declareParameter(GAUSSIAN_FWHM, 0.0, "Value of the full-width half-maximum for the Gaussian");
50}
51
58void Voigt::functionLocal(double *out, const double *xValues, const size_t nData) const {
59 calculateFunctionAndDerivative(xValues, nData, out, nullptr);
60}
61
69void Voigt::functionDerivLocal(API::Jacobian *out, const double *xValues, const size_t nData) {
70 calculateFunctionAndDerivative(xValues, nData, nullptr, out);
71}
72
81void Voigt::calculateFunctionAndDerivative(const double *xValues, const size_t nData, double *functionValues,
82 API::Jacobian *derivatives) const {
83 const double a_L = getParameter(LORENTZ_AMP);
84 const double lorentzPos = getParameter(LORENTZ_POS);
85 const double gamma_L = getParameter(LORENTZ_FWHM);
86 const double gamma_G = getParameter(GAUSSIAN_FWHM);
87
88 const double rtln2oGammaG = SQRTLN2 / gamma_G;
89 const double prefactor = (a_L * SQRTPI * gamma_L * SQRTLN2 / gamma_G);
90
91 for (size_t i = 0; i < nData; ++i) {
92 const double xoffset = xValues[i] - lorentzPos;
93
94 const double X = xoffset * 2.0 * rtln2oGammaG;
95 const double Y = gamma_L * rtln2oGammaG;
96
97 double fx(0.0), dFdx(0.0), dFdy(0.0);
98 for (size_t j = 0; j < NLORENTZIANS; ++j) {
99 const double ymA(Y - COEFFA[j]);
100 const double xmB(X - COEFFB[j]);
101 const double alpha = COEFFC[j] * ymA + COEFFD[j] * xmB;
102 const double beta = ymA * ymA + xmB * xmB;
103 const double ratioab = alpha / beta;
104 fx += ratioab;
105 dFdx += (COEFFD[j] / beta) - 2.0 * (X - COEFFB[j]) * ratioab / beta;
106 dFdy += (COEFFC[j] / beta) - 2.0 * (Y - COEFFA[j]) * ratioab / beta;
107 }
108 if (functionValues) {
109 functionValues[i] = prefactor * fx;
110 }
111 if (derivatives) {
112 derivatives->set(i, 0, prefactor * fx / a_L);
113 derivatives->set(i, 1, -prefactor * dFdx * 2.0 * rtln2oGammaG);
114 derivatives->set(i, 2, prefactor * (fx / gamma_L + dFdy * rtln2oGammaG));
115 derivatives->set(i, 3, -prefactor * (fx + (rtln2oGammaG) * (2.0 * xoffset * dFdx + gamma_L * dFdy)) / gamma_G);
116 }
117 }
118}
119
124double Voigt::centre() const { return getParameter(LORENTZ_POS); }
125
130double Voigt::height() const {
131 if (getParameter(LORENTZ_AMP) == 0.0 || getParameter(LORENTZ_FWHM) == 0.0 || getParameter(GAUSSIAN_FWHM) == 0.0) {
132 return 0.0;
133 }
134 double pos = getParameter(LORENTZ_POS);
135 double h;
136 functionLocal(&h, &pos, 1);
137 return h;
138}
139
145double Voigt::fwhm() const { return (getParameter(LORENTZ_FWHM) + getParameter(GAUSSIAN_FWHM)); }
146
151void Voigt::setCentre(const double value) { this->setParameter(LORENTZ_POS, value); }
152
157void Voigt::setHeight(const double value) {
158 auto lorentzFwhm = getParameter(LORENTZ_FWHM);
159 if (lorentzFwhm == 0.0) {
160 lorentzFwhm = std::numeric_limits<double>::epsilon();
161 setParameter(LORENTZ_FWHM, lorentzFwhm);
162 }
163 auto lorentzAmp = getParameter(LORENTZ_AMP);
164 if (lorentzAmp == 0.0) {
165 lorentzAmp = std::numeric_limits<double>::epsilon();
166 setParameter(LORENTZ_AMP, lorentzAmp);
167 }
168 auto gaussFwhm = getParameter(GAUSSIAN_FWHM);
169 if (gaussFwhm == 0.0) {
170 setParameter(GAUSSIAN_FWHM, std::numeric_limits<double>::epsilon());
171 }
172 auto h = height();
173 this->setParameter(LORENTZ_AMP, lorentzAmp * value / h);
174}
175
180void Voigt::setFwhm(const double value) {
181 auto lorentzFwhm = getParameter(LORENTZ_FWHM);
182 if (lorentzFwhm == 0.0) {
183 lorentzFwhm = std::numeric_limits<double>::epsilon();
184 }
185 auto gaussFwhm = getParameter(GAUSSIAN_FWHM);
186 if (gaussFwhm == 0.0) {
187 gaussFwhm = std::numeric_limits<double>::epsilon();
188 }
189 auto ratio = lorentzFwhm / (lorentzFwhm + gaussFwhm);
190 this->setParameter(LORENTZ_FWHM, ratio * value);
191 this->setParameter(GAUSSIAN_FWHM, (1.0 - ratio) * value);
192}
193
197double Voigt::intensity() const {
198 if (getParameter(GAUSSIAN_FWHM) == 0.0) {
199 return 0.0;
200 }
201 return M_PI * getParameter(LORENTZ_AMP) * getParameter(LORENTZ_FWHM) / 2.0;
202}
203
208void Voigt::setIntensity(const double value) {
209 auto lorentzFWHM = getParameter(LORENTZ_FWHM);
210 if (lorentzFWHM == 0.0) {
211 lorentzFWHM = std::numeric_limits<double>::epsilon();
212 setParameter(LORENTZ_FWHM, lorentzFWHM);
213 }
214 auto gaussFwhm = getParameter(GAUSSIAN_FWHM);
215 if (gaussFwhm == 0.0) {
216 setParameter(GAUSSIAN_FWHM, std::numeric_limits<double>::epsilon());
217 }
218 setParameter(LORENTZ_AMP, 2.0 * value / (M_PI * lorentzFWHM));
219}
220
221} // namespace Mantid::CurveFitting::Functions
double value
The value of the point.
Definition: FitMW.cpp:51
#define DECLARE_FUNCTION(classname)
Macro for declaring a new type of function to be used with the FunctionFactory.
void setParameter(const std::string &name, const double &value, bool explicitlySet=true) override
Override parent so that we may bust the cache when a parameter is set.
Represents the Jacobian in IFitFunction::functionDeriv.
Definition: Jacobian.h:22
virtual void set(size_t iY, size_t iP, double value)=0
Set a value to a Jacobian matrix element.
void declareParameter(const std::string &name, double initValue=0, const std::string &description="") override
Declare a new parameter.
double getParameter(size_t i) const override
Get i-th parameter.
void setHeight(const double value) override
Set the height of the peak.
Definition: Voigt.cpp:157
double height() const override
Return value of height of peak.
Definition: Voigt.cpp:130
void functionLocal(double *out, const double *xValues, const size_t nData) const override
Fill out with function values at given x points.
Definition: Voigt.cpp:58
double intensity() const override
Returns the integral intensity of the peak.
Definition: Voigt.cpp:197
double fwhm() const override
Return value of FWHM of peak.
Definition: Voigt.cpp:145
void functionDerivLocal(API::Jacobian *out, const double *xValues, const size_t nData) override
Derivatives of function with respect to active parameters.
Definition: Voigt.cpp:69
void setIntensity(const double value) override
Sets the integral intensity of the peak.
Definition: Voigt.cpp:208
void setCentre(const double value) override
Set the centre of the peak.
Definition: Voigt.cpp:151
void setFwhm(const double value) override
Set the FWHM of the peak.
Definition: Voigt.cpp:180
void declareParameters() override
Declare parameters.
Definition: Voigt.cpp:45
double centre() const override
Return value of centre of peak.
Definition: Voigt.cpp:124
void calculateFunctionAndDerivative(const double *xValues, const size_t nData, double *functionValues, API::Jacobian *derivatives) const
Calculate both function & derivative together.
Definition: Voigt.cpp:81