17const double LN2_DIV_PI = 2. * std::sqrt(M_LN2 / M_PI);
18constexpr double LN2_M4 = 4 * M_LN2;
24inline double cal_ag(
const double gamma) {
return LN2_DIV_PI / gamma; }
30inline constexpr double cal_bg(
const double gamma) {
return LN2_M4 / (gamma * gamma); }
38inline double cal_gaussian(
const double ag,
const double bg,
const double xdiffsq) {
39 return ag * std::exp(-bg * xdiffsq);
48inline constexpr double cal_lorentzian(
const double gamma_div_2,
const double gammasq_div_4,
const double xdiffsq) {
49 return gamma_div_2 / (xdiffsq + gammasq_div_4) / M_PI;
56using namespace CurveFitting;
57using namespace Constraints;
63Kernel::Logger
g_log(
"PseudoVoigt");
73 declareParameter(
"Mixing", 0.5);
74 declareParameter(
"Intensity", 1.);
75 declareParameter(
"PeakCentre", 0.);
76 declareParameter(
"FWHM", 1.);
78 auto mixingConstraint = std::make_unique<BoundaryConstraint>(
this,
"Mixing", 0.0, 1.0,
true);
79 mixingConstraint->setPenaltyFactor(1e9);
80 addConstraint(std::move(mixingConstraint));
82 auto fwhm_constraint = std::make_unique<BoundaryConstraint>(
this,
"FWHM", 1.E-20,
true);
83 fwhm_constraint->setPenaltyFactor(1e9);
84 addConstraint(std::move(fwhm_constraint));
91 m_set_history_distances.resize(4, 128);
102 const double peak_intensity =
getParameter(
"Intensity");
108 throw std::runtime_error(
"Pseudo-voigt has FWHM as 0. It will generate "
109 "infinity at center in the Lorentzian part.");
111 const double lFraction = 1.0 - gFraction;
114 const double a_g = cal_ag(gamma);
115 const double b_g = cal_bg(gamma);
116 const double gamma_div_2 = 0.5 * gamma;
117 const double gammasq_div_4 = gamma_div_2 * gamma_div_2;
119 for (
size_t i = 0; i < nData; ++i) {
120 double xDiffSquared = (xValues[i] - x0) * (xValues[i] - x0);
121 out[i] = peak_intensity * (gFraction * cal_gaussian(a_g, b_g, xDiffSquared) +
122 lFraction * cal_lorentzian(gamma_div_2, gammasq_div_4, xDiffSquared));
137 double lFraction = 1.0 - gFraction;
140 const double a_g = cal_ag(gamma);
141 const double b_g = cal_bg(gamma);
142 const double gamma_div_2 = 0.5 * gamma;
143 const double gammasq_div_4 = gamma_div_2 * gamma_div_2;
146 for (
size_t i = 0; i < nData; ++i) {
147 double xDiff = (xValues[i] - x0);
148 double xDiffSquared = xDiff * xDiff;
151 double gaussian_term = cal_gaussian(a_g, b_g, xDiffSquared);
152 double lorentzian_term = cal_lorentzian(gamma_div_2, gammasq_div_4, xDiffSquared);
155 out->
set(i, 0, peak_intensity * (gaussian_term - lorentzian_term));
158 out->
set(i, 1, gFraction * gaussian_term + lFraction * lorentzian_term);
161 const double derive_g_x0 = 2. * b_g * xDiff * gaussian_term;
162 const double derive_l_x0 = 4. * M_PI * xDiff / gamma * lorentzian_term * lorentzian_term;
163 const double deriv_x0 = peak_intensity * (gFraction * derive_g_x0 + lFraction * derive_l_x0);
164 out->
set(i, 2, deriv_x0);
167 const double t1 = -1. / gamma * gaussian_term;
168 const double t2 = 2. * b_g * xDiffSquared * gaussian_term / gamma;
169 const double t3 = lorentzian_term / gamma;
170 const double t4 = -M_PI * lorentzian_term * lorentzian_term;
171 const double derive_gamma = peak_intensity * (gFraction * (t1 + t2) + lFraction * (t3 + t4));
172 out->
set(i, 3, derive_gamma);
202 g_log.
debug() <<
"[PV] Set " << i <<
"-th parameter with value " <<
value <<
"\n";
208 if (explicitlySet && i != 2) {
209 g_log.
debug() <<
"Update set history for " << i <<
"-th parameter"
221 g_log.
debug() <<
"Time to calculate " << to_calculate_index <<
"-th parameter"
224 bool some_value_updated{
true};
225 if (to_calculate_index == 0) {
229 double mixing = (
m_height * 0.5 * M_PI * gamma / peak_intensity - 1) / (sqrt(M_PI * M_LN2) - 1);
231 g_log.
debug() <<
"Calculated mixing (eta) = " << mixing <<
" < 0. Set to 0 instead"
234 }
else if (mixing > 1) {
235 g_log.
debug() <<
"Calculated mixing (eta) = " << mixing <<
" > 1. Set to 1 instead"
242 }
else if (to_calculate_index == 1) {
246 double intensity =
m_height / 2. / (1 + (sqrt(M_PI * M_LN2) - 1) * eta) * (M_PI * gamma);
249 }
else if (to_calculate_index == 3) {
255 double gamma =
intensity * 2 * (1 + (sqrt(M_PI * M_LN2) - 1) * eta) / (M_PI *
m_height);
256 if (gamma < 1.E-10) {
257 g_log.
debug() <<
"Peak width (H or Gamma) = " << gamma <<
". Set 1.E-2 instead"
263 some_value_updated =
false;
266 return some_value_updated;
276 throw std::runtime_error(
"Parameter set up history index out of boundary");
279 for (
size_t i = 0; i < 4; ++i) {
305 size_t index_largest_distance{0};
306 size_t largest_distance{0};
307 size_t num_been_set{0};
313 index_largest_distance = i;
323 if (num_been_set < 3)
324 index_largest_distance = 128;
326 return index_largest_distance;
336 const double height = 2. * peak_intensity * (1 + (sqrt(M_PI * M_LN2) - 1) * eta) / (M_PI * gamma);
356 if (!updated_any_value) {
360 double new_intensity{1.};
362 new_intensity = old_intensity *
m_height / prev_height;
double value
The value of the point.
#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.
virtual void set(size_t iY, size_t iP, double value)=0
Set a value to a Jacobian matrix element.
double getParameter(size_t i) const override
Get i-th parameter.
void setFwhm(const double w) override
set FWHM
void functionLocal(double *out, const double *xValues, const size_t nData) const override
calculate pseudo voigt
void functionDerivLocal(API::Jacobian *out, const double *xValues, const size_t nData) override
calcualte derivative analytically
void setParameter(size_t i, const double &value, bool explicitlySet=true) override
Set i-th parameter.
void setHeight(const double h) override
set non-native parameter peak height
double height() const override
calculate effective parameter: height
size_t get_parameter_to_calculate_from_set()
get the parameter (by index) to calculate according to parameter set history
void update_set_history(size_t set_index)
The purpose of this is to track which user-specified parameter is outdated and to be calculated.
double intensity() const override
Returns the integral intensity of the peak.
bool estimate_parameter_value()
std::string name() const override
Returns the function's name.
std::vector< size_t > m_set_history_distances
historty of the order to be set
void debug(const std::string &msg)
Logs at debug level.
Kernel::Logger g_log("ExperimentInfo")
static logger object