00001
00002
00003
00004
00005 #include "bfunc.h"
00006
00007 #include <boost/math/special_functions/gamma.hpp>
00008
00009 #include "voigt.h"
00010 #include "numfuncs.h"
00011
00012 using namespace std;
00013 using boost::math::lgamma;
00014
00015
00016 #define CALCULATE_VALUE_BEGIN(NAME) \
00017 void NAME::calculate_value_in_range(vector<realt> const &xx, vector<realt> &yy,\
00018 int first, int last) const\
00019 {\
00020 for (int i = first; i < last; ++i) {\
00021 realt x = xx[i];
00022
00023
00024 #define CALCULATE_VALUE_END(VAL) \
00025 yy[i] += (VAL);\
00026 }\
00027 }
00028
00029 #define CALCULATE_DERIV_BEGIN(NAME) \
00030 void NAME::calculate_value_deriv_in_range(vector<realt> const &xx, \
00031 vector<realt> &yy, \
00032 vector<realt> &dy_da, \
00033 bool in_dx, \
00034 int first, int last) const \
00035 { \
00036 int dyn = dy_da.size() / xx.size(); \
00037 vector<realt> dy_dv(nv(), 0.); \
00038 for (int i = first; i < last; ++i) { \
00039 realt x = xx[i]; \
00040 realt dy_dx;
00041
00042
00043 #define CALCULATE_DERIV_END(VAL) \
00044 if (!in_dx) { \
00045 yy[i] += (VAL); \
00046 v_foreach (Multi, j, multi_) \
00047 dy_da[dyn*i+j->p] += dy_dv[j->n] * j->mult;\
00048 dy_da[dyn*i+dyn-1] += dy_dx;\
00049 }\
00050 else { \
00051 v_foreach (Multi, j, multi_) \
00052 dy_da[dyn*i+j->p] += dy_da[dyn*i+dyn-1] * dy_dv[j->n]*j->mult;\
00053 } \
00054 } \
00055 }
00056
00057
00058
00059
00060 void FuncConstant::calculate_value_in_range(vector<realt> const&,
00061 vector<realt>& yy,
00062 int first, int last) const
00063 {
00064 for (int i = first; i < last; ++i)
00065 yy[i] += av_[0];
00066 }
00067
00068 CALCULATE_DERIV_BEGIN(FuncConstant)
00069 (void) x;
00070 dy_dv[0] = 1.;
00071 dy_dx = 0;
00072 CALCULATE_DERIV_END(av_[0])
00073
00074
00075
00076 CALCULATE_VALUE_BEGIN(FuncLinear)
00077 CALCULATE_VALUE_END(av_[0] + x*av_[1])
00078
00079 CALCULATE_DERIV_BEGIN(FuncLinear)
00080 dy_dv[0] = 1.;
00081 dy_dv[1] = x;
00082 dy_dx = av_[1];
00083 CALCULATE_DERIV_END(av_[0] + x*av_[1])
00084
00085
00086
00087 CALCULATE_VALUE_BEGIN(FuncQuadratic)
00088 CALCULATE_VALUE_END(av_[0] + x*av_[1] + x*x*av_[2])
00089
00090 CALCULATE_DERIV_BEGIN(FuncQuadratic)
00091 dy_dv[0] = 1.;
00092 dy_dv[1] = x;
00093 dy_dv[2] = x*x;
00094 dy_dx = av_[1] + 2*x*av_[2];
00095 CALCULATE_DERIV_END(av_[0] + x*av_[1] + x*x*av_[2])
00096
00097
00098
00099 CALCULATE_VALUE_BEGIN(FuncCubic)
00100 CALCULATE_VALUE_END(av_[0] + x*av_[1] + x*x*av_[2] + x*x*x*av_[3])
00101
00102 CALCULATE_DERIV_BEGIN(FuncCubic)
00103 dy_dv[0] = 1.;
00104 dy_dv[1] = x;
00105 dy_dv[2] = x*x;
00106 dy_dv[3] = x*x*x;
00107 dy_dx = av_[1] + 2*x*av_[2] + 3*x*x*av_[3];
00108 CALCULATE_DERIV_END(av_[0] + x*av_[1] + x*x*av_[2] + x*x*x*av_[3])
00109
00110
00111
00112 CALCULATE_VALUE_BEGIN(FuncPolynomial4)
00113 CALCULATE_VALUE_END(av_[0] + x*av_[1] + x*x*av_[2] + x*x*x*av_[3]
00114 + x*x*x*x*av_[4])
00115
00116 CALCULATE_DERIV_BEGIN(FuncPolynomial4)
00117 dy_dv[0] = 1.;
00118 dy_dv[1] = x;
00119 dy_dv[2] = x*x;
00120 dy_dv[3] = x*x*x;
00121 dy_dv[4] = x*x*x*x;
00122 dy_dx = av_[1] + 2*x*av_[2] + 3*x*x*av_[3] + 4*x*x*x*av_[4];
00123 CALCULATE_DERIV_END(av_[0] + x*av_[1] + x*x*av_[2] + x*x*x*av_[3]
00124 + x*x*x*x*av_[4])
00125
00126
00127
00128 CALCULATE_VALUE_BEGIN(FuncPolynomial5)
00129 CALCULATE_VALUE_END(av_[0] + x*av_[1] + x*x*av_[2]
00130 + x*x*x*av_[3] + x*x*x*x*av_[4] + x*x*x*x*x*av_[5])
00131
00132 CALCULATE_DERIV_BEGIN(FuncPolynomial5)
00133 dy_dv[0] = 1.;
00134 dy_dv[1] = x;
00135 dy_dv[2] = x*x;
00136 dy_dv[3] = x*x*x;
00137 dy_dv[4] = x*x*x*x;
00138 dy_dv[5] = x*x*x*x*x;
00139 dy_dx = av_[1] + 2*x*av_[2] + 3*x*x*av_[3] + 4*x*x*x*av_[4]
00140 + 5*x*x*x*x*av_[5];
00141 CALCULATE_DERIV_END(av_[0] + x*av_[1] + x*x*av_[2]
00142 + x*x*x*av_[3] + x*x*x*x*av_[4] + x*x*x*x*x*av_[5])
00143
00144
00145
00146 CALCULATE_VALUE_BEGIN(FuncPolynomial6)
00147 CALCULATE_VALUE_END(av_[0] + x*av_[1] + x*x*av_[2] + x*x*x*av_[3] +
00148 x*x*x*x*av_[4] + x*x*x*x*x*av_[5] + x*x*x*x*x*x*av_[6])
00149
00150 CALCULATE_DERIV_BEGIN(FuncPolynomial6)
00151 dy_dv[0] = 1.;
00152 dy_dv[1] = x;
00153 dy_dv[2] = x*x;
00154 dy_dv[3] = x*x*x;
00155 dy_dv[4] = x*x*x*x;
00156 dy_dv[5] = x*x*x*x*x;
00157 dy_dv[6] = x*x*x*x*x*x;
00158 dy_dx = av_[1] + 2*x*av_[2] + 3*x*x*av_[3] + 4*x*x*x*av_[4]
00159 + 5*x*x*x*x*av_[5] + 6*x*x*x*x*x*av_[6];
00160 CALCULATE_DERIV_END(av_[0] + x*av_[1] + x*x*av_[2] + x*x*x*av_[3] +
00161 x*x*x*x*av_[4] + x*x*x*x*x*av_[5] + x*x*x*x*x*x*av_[6])
00162
00163
00164
00165 void FuncGaussian::more_precomputations()
00166 {
00167 if (fabs(av_[2]) < epsilon)
00168 av_[2] = epsilon;
00169 }
00170
00171 CALCULATE_VALUE_BEGIN(FuncGaussian)
00172 realt xa1a2 = (x - av_[1]) / av_[2];
00173 realt ex = exp(- M_LN2 * xa1a2 * xa1a2);
00174 CALCULATE_VALUE_END(av_[0] * ex)
00175
00176 CALCULATE_DERIV_BEGIN(FuncGaussian)
00177 realt xa1a2 = (x - av_[1]) / av_[2];
00178 realt ex = exp(- M_LN2 * xa1a2 * xa1a2);
00179 dy_dv[0] = ex;
00180 realt dcenter = 2 * M_LN2 * av_[0] * ex * xa1a2 / av_[2];
00181 dy_dv[1] = dcenter;
00182 dy_dv[2] = dcenter * xa1a2;
00183 dy_dx = -dcenter;
00184 CALCULATE_DERIV_END(av_[0]*ex)
00185
00186 bool FuncGaussian::get_nonzero_range(double level,
00187 realt &left, realt &right) const
00188 {
00189 if (level == 0)
00190 return false;
00191 else if (fabs(level) >= fabs(av_[0]))
00192 left = right = 0;
00193 else {
00194 realt w = sqrt(log(fabs(av_[0]/level)) / M_LN2) * av_[2];
00195 left = av_[1] - w;
00196 right = av_[1] + w;
00197 }
00198 return true;
00199 }
00200
00201 bool FuncGaussian::get_area(realt* a) const
00202 {
00203 *a = av_[0] * fabs(av_[2]) * sqrt(M_PI / M_LN2);
00204 return true;
00205 }
00206
00207
00208
00209 void FuncSplitGaussian::more_precomputations()
00210 {
00211 if (fabs(av_[2]) < epsilon)
00212 av_[2] = epsilon;
00213 if (fabs(av_[3]) < epsilon)
00214 av_[3] = epsilon;
00215 }
00216
00217 CALCULATE_VALUE_BEGIN(FuncSplitGaussian)
00218 realt hwhm = (x < av_[1] ? av_[2] : av_[3]);
00219 realt xa1a2 = (x - av_[1]) / hwhm;
00220 realt ex = exp(- M_LN2 * xa1a2 * xa1a2);
00221 CALCULATE_VALUE_END(av_[0] * ex)
00222
00223 CALCULATE_DERIV_BEGIN(FuncSplitGaussian)
00224 realt hwhm = (x < av_[1] ? av_[2] : av_[3]);
00225 realt xa1a2 = (x - av_[1]) / hwhm;
00226 realt ex = exp(- M_LN2 * xa1a2 * xa1a2);
00227 dy_dv[0] = ex;
00228 realt dcenter = 2 * M_LN2 * av_[0] * ex * xa1a2 / hwhm;
00229 dy_dv[1] = dcenter;
00230 if (x < av_[1]) {
00231 dy_dv[2] = dcenter * xa1a2;
00232 dy_dv[3] = 0;
00233 }
00234 else {
00235 dy_dv[2] = 0;
00236 dy_dv[3] = dcenter * xa1a2;
00237 }
00238 dy_dx = -dcenter;
00239 CALCULATE_DERIV_END(av_[0]*ex)
00240
00241 bool FuncSplitGaussian::get_nonzero_range(double level,
00242 realt &left, realt &right) const
00243 {
00244 if (level == 0)
00245 return false;
00246 else if (fabs(level) >= fabs(av_[0]))
00247 left = right = 0;
00248 else {
00249 realt w1 = sqrt (log (fabs(av_[0]/level)) / M_LN2) * av_[2];
00250 realt w2 = sqrt (log (fabs(av_[0]/level)) / M_LN2) * av_[3];
00251 left = av_[1] - w1;
00252 right = av_[1] + w2;
00253 }
00254 return true;
00255 }
00256
00257 bool FuncSplitGaussian::get_area(realt* a) const
00258 {
00259 *a = av_[0] * (fabs(av_[2])+fabs(av_[3])) / 2. * sqrt(M_PI/M_LN2);
00260 return true;
00261 }
00262
00263
00264
00265 void FuncLorentzian::more_precomputations()
00266 {
00267 if (fabs(av_[2]) < epsilon)
00268 av_[2] = epsilon;
00269 }
00270
00271 CALCULATE_VALUE_BEGIN(FuncLorentzian)
00272 realt xa1a2 = (x - av_[1]) / av_[2];
00273 realt inv_denomin = 1. / (1 + xa1a2 * xa1a2);
00274 CALCULATE_VALUE_END(av_[0] * inv_denomin)
00275
00276 CALCULATE_DERIV_BEGIN(FuncLorentzian)
00277 realt xa1a2 = (x - av_[1]) / av_[2];
00278 realt inv_denomin = 1. / (1 + xa1a2 * xa1a2);
00279 dy_dv[0] = inv_denomin;
00280 realt dcenter = 2 * av_[0] * xa1a2 / av_[2] * inv_denomin * inv_denomin;
00281 dy_dv[1] = dcenter;
00282 dy_dv[2] = dcenter * xa1a2;
00283 dy_dx = -dcenter;
00284 CALCULATE_DERIV_END(av_[0] * inv_denomin)
00285
00286 bool FuncLorentzian::get_nonzero_range(double level,
00287 realt &left, realt &right) const
00288 {
00289 if (level == 0)
00290 return false;
00291 else if (fabs(level) >= fabs(av_[0]))
00292 left = right = 0;
00293 else {
00294 realt w = sqrt(fabs(av_[0]/level) - 1) * av_[2];
00295 left = av_[1] - w;
00296 right = av_[1] + w;
00297 }
00298 return true;
00299 }
00300
00301
00302
00303 void FuncPearson7::more_precomputations()
00304 {
00305 if (fabs(av_[2]) < epsilon)
00306 av_[2] = epsilon;
00307 if (av_.size() != 5)
00308 av_.resize(5);
00309
00310 av_[4] = pow(2, 1. / av_[3]) - 1;
00311 }
00312
00313 CALCULATE_VALUE_BEGIN(FuncPearson7)
00314 realt xa1a2 = (x - av_[1]) / av_[2];
00315 realt xa1a2sq = xa1a2 * xa1a2;
00316 realt pow_2_1_a3_1 = av_[4];
00317 realt denom_base = 1 + xa1a2sq * pow_2_1_a3_1;
00318 realt inv_denomin = pow(denom_base, - av_[3]);
00319 CALCULATE_VALUE_END(av_[0] * inv_denomin)
00320
00321 CALCULATE_DERIV_BEGIN(FuncPearson7)
00322 realt xa1a2 = (x - av_[1]) / av_[2];
00323 realt xa1a2sq = xa1a2 * xa1a2;
00324 realt pow_2_1_a3_1 = av_[4];
00325 realt denom_base = 1 + xa1a2sq * pow_2_1_a3_1;
00326 realt inv_denomin = pow(denom_base, - av_[3]);
00327 dy_dv[0] = inv_denomin;
00328 realt dcenter = 2 * av_[0] * av_[3] * pow_2_1_a3_1 * xa1a2 * inv_denomin /
00329 (denom_base * av_[2]);
00330 dy_dv[1] = dcenter;
00331 dy_dv[2] = dcenter * xa1a2;
00332 dy_dv[3] = av_[0] * inv_denomin * (M_LN2 * (pow_2_1_a3_1 + 1)
00333 * xa1a2sq / (denom_base * av_[3]) - log(denom_base));
00334 dy_dx = -dcenter;
00335 CALCULATE_DERIV_END(av_[0] * inv_denomin)
00336
00337
00338 bool FuncPearson7::get_nonzero_range(double level,
00339 realt &left, realt &right) const
00340 {
00341 if (level == 0)
00342 return false;
00343 else if (fabs(level) >= fabs(av_[0]))
00344 left = right = 0;
00345 else {
00346 realt t = (pow(fabs(av_[0]/level), 1./av_[3]) - 1)
00347 / (pow(2, 1./av_[3]) - 1);
00348 realt w = sqrt(t) * av_[2];
00349 left = av_[1] - w;
00350 right = av_[1] + w;
00351 }
00352 return true;
00353 }
00354
00355 bool FuncPearson7::get_area(realt* a) const
00356 {
00357 if (av_[3] <= 0.5)
00358 return false;
00359 realt g = exp(lgamma(av_[3] - 0.5) - lgamma(av_[3]));
00360
00361 *a = av_[0] * 2 * fabs(av_[2]) * sqrt(M_PI) * g / (2 * sqrt(av_[4]));
00362 return true;
00363 }
00364
00365
00366
00367 void FuncSplitPearson7::more_precomputations()
00368 {
00369 if (fabs(av_[2]) < epsilon)
00370 av_[2] = epsilon;
00371 if (fabs(av_[3]) < epsilon)
00372 av_[3] = epsilon;
00373 if (av_.size() != 8)
00374 av_.resize(8);
00375
00376 av_[6] = pow(2, 1. / av_[4]) - 1;
00377 av_[7] = pow(2, 1. / av_[5]) - 1;
00378 }
00379
00380 CALCULATE_VALUE_BEGIN(FuncSplitPearson7)
00381 int lr = x < av_[1] ? 0 : 1;
00382 realt xa1a2 = (x - av_[1]) / av_[2+lr];
00383 realt xa1a2sq = xa1a2 * xa1a2;
00384 realt pow_2_1_a3_1 = av_[6+lr];
00385 realt denom_base = 1 + xa1a2sq * pow_2_1_a3_1;
00386 realt inv_denomin = pow(denom_base, - av_[4+lr]);
00387 CALCULATE_VALUE_END(av_[0] * inv_denomin)
00388
00389 CALCULATE_DERIV_BEGIN(FuncSplitPearson7)
00390 int lr = x < av_[1] ? 0 : 1;
00391 realt hwhm = av_[2+lr];
00392 realt shape = av_[4+lr];
00393 realt xa1a2 = (x - av_[1]) / hwhm;
00394 realt xa1a2sq = xa1a2 * xa1a2;
00395 realt pow_2_1_a3_1 = av_[6+lr];
00396 realt denom_base = 1 + xa1a2sq * pow_2_1_a3_1;
00397 realt inv_denomin = pow (denom_base, -shape);
00398 dy_dv[0] = inv_denomin;
00399 realt dcenter = 2 * av_[0] * shape * pow_2_1_a3_1 * xa1a2 * inv_denomin /
00400 (denom_base * hwhm);
00401 dy_dv[1] = dcenter;
00402 dy_dv[2] = dy_dv[3] = dy_dv[4] = dy_dv[5] = 0;
00403 dy_dv[2+lr] = dcenter * xa1a2;
00404 dy_dv[4+lr] = av_[0] * inv_denomin * (M_LN2 * (pow_2_1_a3_1 + 1)
00405 * xa1a2sq / (denom_base * shape) - log(denom_base));
00406 dy_dx = -dcenter;
00407 CALCULATE_DERIV_END(av_[0] * inv_denomin)
00408
00409
00410 bool FuncSplitPearson7::get_nonzero_range(double level,
00411 realt &left, realt &right) const
00412 {
00413 if (level == 0)
00414 return false;
00415 else if (fabs(level) >= fabs(av_[0]))
00416 left = right = 0;
00417 else {
00418 realt t1 = (pow(fabs(av_[0]/level), 1./av_[4]) - 1)
00419 / (pow(2, 1./av_[4]) - 1);
00420 realt w1 = sqrt(t1) * av_[2];
00421 realt t2 = (pow(fabs(av_[0]/level), 1./av_[5]) - 1)
00422 / (pow(2, 1./av_[5]) - 1);
00423 realt w2 = sqrt(t2) * av_[3];
00424 left = av_[1] - w1;
00425 right = av_[1] + w2;
00426 }
00427 return true;
00428 }
00429
00430 bool FuncSplitPearson7::get_area(realt* a) const
00431 {
00432 if (av_[4] <= 0.5 || av_[5] <= 0.5)
00433 return false;
00434 realt g1 = exp(lgamma(av_[4] - 0.5) - lgamma(av_[4]));
00435 realt g2 = exp(lgamma(av_[5] - 0.5) - lgamma(av_[5]));
00436 *a = av_[0] * fabs(av_[2]) * sqrt(M_PI) * g1 / (2 * sqrt(av_[6]))
00437 + av_[0] * fabs(av_[3]) * sqrt(M_PI) * g2 / (2 * sqrt(av_[7]));
00438 return true;
00439 }
00440
00441
00442
00443 void FuncPseudoVoigt::more_precomputations()
00444 {
00445 if (fabs(av_[2]) < epsilon)
00446 av_[2] = epsilon;
00447 }
00448
00449 CALCULATE_VALUE_BEGIN(FuncPseudoVoigt)
00450 realt xa1a2 = (x - av_[1]) / av_[2];
00451 realt ex = exp(- M_LN2 * xa1a2 * xa1a2);
00452 realt lor = 1. / (1 + xa1a2 * xa1a2);
00453 realt without_height = (1-av_[3]) * ex + av_[3] * lor;
00454 CALCULATE_VALUE_END(av_[0] * without_height)
00455
00456 CALCULATE_DERIV_BEGIN(FuncPseudoVoigt)
00457 realt xa1a2 = (x - av_[1]) / av_[2];
00458 realt ex = exp(- M_LN2 * xa1a2 * xa1a2);
00459 realt lor = 1. / (1 + xa1a2 * xa1a2);
00460 realt without_height = (1-av_[3]) * ex + av_[3] * lor;
00461 dy_dv[0] = without_height;
00462 realt dcenter = 2 * av_[0] * xa1a2 / av_[2]
00463 * (av_[3]*lor*lor + (1-av_[3])*M_LN2*ex);
00464 dy_dv[1] = dcenter;
00465 dy_dv[2] = dcenter * xa1a2;
00466 dy_dv[3] = av_[0] * (lor - ex);
00467 dy_dx = -dcenter;
00468 CALCULATE_DERIV_END(av_[0] * without_height)
00469
00470 bool FuncPseudoVoigt::get_nonzero_range(double level,
00471 realt &left, realt &right) const
00472 {
00473 if (level == 0)
00474 return false;
00475 else if (fabs(level) >= fabs(av_[0]))
00476 left = right = 0;
00477 else {
00478
00479 realt w = (sqrt (av_[3] * fabs(av_[0]/level) - 1) + 4.) * av_[2];
00480 left = av_[1] - w;
00481 right = av_[1] + w;
00482 }
00483 return true;
00484 }
00485
00486 bool FuncPseudoVoigt::get_area(realt* a) const
00487 {
00488 *a = av_[0] * fabs(av_[2])
00489 * ((av_[3] * M_PI) + (1 - av_[3]) * sqrt(M_PI / M_LN2));
00490 return true;
00491 }
00492
00493
00494
00495 void FuncVoigt::more_precomputations()
00496 {
00497 if (av_.size() != 6)
00498 av_.resize(6);
00499 float k, l, dkdx, dkdy;
00500 humdev(0, fabs(av_[3]), k, l, dkdx, dkdy);
00501 av_[4] = 1. / k;
00502 av_[5] = dkdy / k;
00503
00504 if (fabs(av_[2]) < epsilon)
00505 av_[2] = epsilon;
00506 }
00507
00508 CALCULATE_VALUE_BEGIN(FuncVoigt)
00509
00510 float k;
00511 realt xa1a2 = (x - av_[1]) / av_[2];
00512 k = humlik(xa1a2, fabs(av_[3]));
00513 CALCULATE_VALUE_END(av_[0] * av_[4] * k)
00514
00515 CALCULATE_DERIV_BEGIN(FuncVoigt)
00516
00517
00518 float k;
00519 realt xa1a2 = (x-av_[1]) / av_[2];
00520 realt a0a4 = av_[0] * av_[4];
00521 float l, dkdx, dkdy;
00522 humdev(xa1a2, fabs(av_[3]), k, l, dkdx, dkdy);
00523 dy_dv[0] = av_[4] * k;
00524 realt dcenter = -a0a4 * dkdx / av_[2];
00525 dy_dv[1] = dcenter;
00526 dy_dv[2] = dcenter * xa1a2;
00527 dy_dv[3] = a0a4 * (dkdy - k * av_[5]);
00528 if (av_[3] < 0)
00529 dy_dv[3] = -dy_dv[3];
00530 dy_dx = -dcenter;
00531 CALCULATE_DERIV_END(a0a4 * k)
00532
00533 bool FuncVoigt::get_nonzero_range(double level,
00534 realt &left, realt &right) const
00535 {
00536 if (level == 0)
00537 return false;
00538 else if (fabs(level) >= fabs(av_[0]))
00539 left = right = 0;
00540 else {
00541
00542 return false;
00543 }
00544 return true;
00545 }
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555 static realt voigt_fwhm(realt a2, realt a3)
00556 {
00557 realt sigma = fabs(a2) / M_SQRT2;
00558 realt gamma = fabs(a2) * a3;
00559
00560 realt fG = 2 * sigma * sqrt(2 * M_LN2);
00561 realt fL = 2 * gamma;
00562
00563 realt fV = 0.5346 * fL + sqrt(0.2166 * fL * fL + fG * fG);
00564 return fV;
00565 }
00566
00567 bool FuncVoigt::get_fwhm(realt* a) const
00568 {
00569 *a = voigt_fwhm(av_[2], av_[3]);
00570 return true;
00571 }
00572
00573 bool FuncVoigt::get_area(realt* a) const
00574 {
00575 *a = av_[0] * fabs(av_[2] * sqrt(M_PI) * av_[4]);
00576 return true;
00577 }
00578
00579 const vector<string>& FuncVoigt::get_other_prop_names() const
00580 {
00581 static const vector<string> p = vector2(string("GaussianFWHM"),
00582 string("LorentzianFWHM"));
00583 return p;
00584 }
00585
00586 realt FuncVoigt::get_other_prop(string const& name) const
00587 {
00588 if (name == "GaussianFWHM") {
00589 realt sigma = fabs(av_[2]) / M_SQRT2;
00590 return 2 * sigma * sqrt(2 * M_LN2);
00591 }
00592 else if (name == "LorentzianFWHM") {
00593 realt gamma = fabs(av_[2]) * av_[3];
00594 return 2 * gamma;
00595 }
00596 else
00597 return 0.;
00598 }
00599
00600
00601
00602 void FuncVoigtA::more_precomputations()
00603 {
00604 if (av_.size() != 6)
00605 av_.resize(6);
00606 av_[4] = 1. / humlik(0, fabs(av_[3]));
00607
00608 if (fabs(av_[2]) < epsilon)
00609 av_[2] = epsilon;
00610 }
00611
00612 CALCULATE_VALUE_BEGIN(FuncVoigtA)
00613
00614 float k;
00615 realt xa1a2 = (x - av_[1]) / av_[2];
00616 k = humlik(xa1a2, fabs(av_[3]));
00617 CALCULATE_VALUE_END(av_[0] / (sqrt(M_PI) * av_[2]) * k)
00618
00619 CALCULATE_DERIV_BEGIN(FuncVoigtA)
00620
00621
00622 float k;
00623 realt xa1a2 = (x-av_[1]) / av_[2];
00624 realt f = av_[0] / (sqrt(M_PI) * av_[2]);
00625 float l, dkdx, dkdy;
00626 humdev(xa1a2, fabs(av_[3]), k, l, dkdx, dkdy);
00627 dy_dv[0] = k / (sqrt(M_PI) * av_[2]);
00628 realt dcenter = -f * dkdx / av_[2];
00629 dy_dv[1] = dcenter;
00630 dy_dv[2] = dcenter * xa1a2 - f * k / av_[2];
00631 dy_dv[3] = f * dkdy;
00632 if (av_[3] < 0)
00633 dy_dv[3] = -dy_dv[3];
00634 dy_dx = -dcenter;
00635 CALCULATE_DERIV_END(f * k)
00636
00637 bool FuncVoigtA::get_nonzero_range(double level,
00638 realt &left, realt &right) const
00639 {
00640 if (level == 0)
00641 return false;
00642 else if (fabs(level) >= fabs(av_[0]))
00643 left = right = 0;
00644 else {
00645
00646 return false;
00647 }
00648 return true;
00649 }
00650
00651 bool FuncVoigtA::get_fwhm(realt* a) const
00652 {
00653 *a = voigt_fwhm(av_[2], av_[3]);
00654 return true;
00655 }
00656
00657 bool FuncVoigtA::get_height(realt* a) const
00658 {
00659 *a = av_[0] / fabs(av_[2] * sqrt(M_PI) * av_[4]);
00660 return true;
00661 }
00662
00663
00664
00665
00666 void FuncEMG::more_precomputations()
00667 {
00668 }
00669
00670 bool FuncEMG::get_nonzero_range(double,
00671 realt&, realt&) const
00672 {
00673 return false;
00674 }
00675
00676
00677
00678
00679
00680 static double erfcexp_x4(double x)
00681 {
00682 double ax = fabs(x);
00683 assert(ax >= 4.);
00684 const double p[4] = { 3.05326634961232344e-1, 3.60344899949804439e-1,
00685 1.25781726111229246e-1, 1.60837851487422766e-2 };
00686 const double q[4] = { 2.56852019228982242, 1.87295284992346047,
00687 5.27905102951428412e-1, 6.05183413124413191e-2 };
00688 double rsq = 1 / (ax * ax);
00689 double xnum = 1.63153871373020978e-2 * rsq;
00690 double xden = rsq;
00691 for (int i = 0; i < 4; ++i) {
00692 xnum = (xnum + p[i]) * rsq;
00693 xden = (xden + q[i]) * rsq;
00694 }
00695 double t = rsq * (xnum + 6.58749161529837803e-4)
00696 / (xden + 2.33520497626869185e-3);
00697 double v = (1/sqrt(M_PI) - t) / ax;
00698 return x >= 0 ? v : 2*exp(x*x) - v;
00699 }
00700
00701 CALCULATE_VALUE_BEGIN(FuncEMG)
00702 realt a = av_[0];
00703 realt bx = av_[1] - x;
00704 realt c = av_[2];
00705 realt d = av_[3];
00706 realt fact = c*sqrt(M_PI/2)/d;
00707 realt erf_arg = (bx/c + c/d) / M_SQRT2;
00708
00709
00710
00711 realt t;
00712
00713 if (fabs(erf_arg) < 20) {
00714 realt e_arg = bx/d + c*c/(2*d*d);
00715
00716 t = fact * exp(e_arg) * (d >= 0 ? erfc(erf_arg) : -erfc(-erf_arg));
00717 }
00718 else if ((d >= 0 && erf_arg > -26) || (d < 0 && -erf_arg > -26)) {
00719 realt h = exp(-bx*bx/(2*c*c));
00720 realt ee = d >= 0 ? erfcexp_x4(erf_arg) : -erfcexp_x4(-erf_arg);
00721 t = fact * h * ee;
00722 }
00723 else
00724 t = 0;
00725 CALCULATE_VALUE_END(a*t)
00726
00727 CALCULATE_DERIV_BEGIN(FuncEMG)
00728 realt a = av_[0];
00729 realt bx = av_[1] - x;
00730 realt c = av_[2];
00731 realt d = av_[3];
00732 realt fact = c*sqrt(M_PI/2)/d;
00733 realt erf_arg = (bx/c + c/d) / M_SQRT2;
00734 realt ee;
00735 if (fabs(erf_arg) < 20)
00736 ee = exp(erf_arg*erf_arg) * (d >= 0 ? erfc(erf_arg) : -erfc(-erf_arg));
00737 else if ((d >= 0 && erf_arg > -26) || (d < 0 && -erf_arg > -26))
00738 ee = d >= 0 ? erfcexp_x4(erf_arg) : -erfcexp_x4(-erf_arg);
00739 else
00740 ee = 0;
00741 realt h = exp(-bx*bx/(2*c*c));
00742 realt t = fact * h * ee;
00743 dy_dv[0] = t;
00744 dy_dv[1] = -a/d * h + a*t/d;
00745 dy_dv[2] = -a/(c*d*d) * (h * (c*c - bx*d) - t * (c*c + d*d));
00746 dy_dv[3] = a/(d*d*d) * (h * c*c - t * (c*c + d*d + bx*d));
00747 dy_dx = - dy_dv[1];
00748 CALCULATE_DERIV_END(a*t)
00749
00750
00751
00752 bool FuncDoniachSunjic::get_nonzero_range(double,
00753 realt&, realt&) const
00754 {
00755 return false;
00756 }
00757
00758 CALCULATE_VALUE_BEGIN(FuncDoniachSunjic)
00759 realt h = av_[0];
00760 realt a = av_[1];
00761 realt F = av_[2];
00762 realt xE = x - av_[3];
00763 realt t = h * cos(M_PI*a/2 + (1-a)*atan(xE/F)) / pow(F*F+xE*xE, (1-a)/2);
00764 CALCULATE_VALUE_END(t)
00765
00766 CALCULATE_DERIV_BEGIN(FuncDoniachSunjic)
00767 realt h = av_[0];
00768 realt a = av_[1];
00769 realt F = av_[2];
00770 realt xE = x - av_[3];
00771 realt fe2 = F*F+xE*xE;
00772 realt ac = 1-a;
00773 realt p = pow(fe2, -ac/2);
00774 realt at = atan(xE/F);
00775 realt cos_arg = M_PI*a/2 + ac*at;
00776 realt co = cos(cos_arg);
00777 realt si = sin(cos_arg);
00778 realt t = co * p;
00779 dy_dv[0] = t;
00780 dy_dv[1] = h * p * (co/2 * log(fe2) + (at-M_PI/2) * si);
00781 dy_dv[2] = h * ac*p/fe2 * (xE*si - F*co);
00782 dy_dv[3] = h * ac*p/fe2 * (xE*co + si*F);
00783 dy_dx = -dy_dv[3];
00784 CALCULATE_DERIV_END(h*t)
00785
00786
00787
00788 CALCULATE_VALUE_BEGIN(FuncPielaszekCube)
00789 realt height = av_[0];
00790 realt center = av_[1];
00791 realt R = av_[2];
00792 realt s = av_[3];
00793 realt s2 = s*s;
00794 realt s4 = s2*s2;
00795 realt R2 = R*R;
00796
00797 realt q = (x-center);
00798 realt q2 = q*q;
00799 realt t = height * (-3*R*(-1 - (R2*(-1 +
00800 pow(1 + (q2*s4)/R2, 1.5 - R2/(2.*s2))
00801 * cos(2*(-1.5 + R2/(2.*s2)) * atan((q*s2)/R))))/
00802 (2.*q2*(-1.5 + R2/(2.*s2))* (-1 + R2/(2.*s2))*s4)))/
00803 (sqrt(2*M_PI)*q2*(-0.5 + R2/(2.*s2))* s2);
00804 CALCULATE_VALUE_END(t)
00805
00806 CALCULATE_DERIV_BEGIN(FuncPielaszekCube)
00807 realt height = av_[0];
00808 realt center = av_[1];
00809 realt R = av_[2];
00810 realt s = av_[3];
00811 realt s2 = s*s;
00812 realt s3 = s*s2;
00813 realt s4 = s2*s2;
00814 realt R2 = R*R;
00815 realt R4 = R2*R2;
00816 realt R3 = R*R2;
00817
00818 realt q = (x-center);
00819 realt q2 = q*q;
00820 realt t = (-3*R*(-1 - (R2*(-1 +
00821 pow(1 + (q2*s4)/R2, 1.5 - R2/(2.*s2))
00822 * cos(2*(-1.5 + R2/(2.*s2)) * atan((q*s2)/R))))/
00823 (2.*q2*(-1.5 + R2/(2.*s2))* (-1 + R2/(2.*s2))*s4)))/
00824 (sqrt(2*M_PI)*q2*(-0.5 + R2/(2.*s2))* s2);
00825
00826 realt dcenter = height * (
00827 (3*sqrt(2/M_PI)*R*(-1 -
00828 (R2* (-1 + pow(1 + (q2*s4)/R2, 1.5 - R2/(2.*s2))*
00829 cos(2*(-1.5 + R2/(2.*s2))* atan((q*s2)/R))))/
00830 (2.*q2*(-1.5 + R2/(2.*s2))* (-1 + R2/(2.*s2))*s4)))/
00831 (q*q2*(-0.5 + R2/(2.*s2))*s2) - (3*R*((R2*(-1 +
00832 pow(1 + (q2*s4)/R2, 1.5 - R2/(2.*s2))*
00833 cos(2*(-1.5 + R2/(2.*s2))* atan((q*s2)/R))))/
00834 (q*q2*(-1.5 + R2/(2.*s2))* (-1 + R2/(2.*s2))*s4) -
00835 (R2*((2*q*(1.5 - R2/(2.*s2))* s4*
00836 pow(1 + (q2*s4)/R2, 0.5 - R2/(2.*s2))*
00837 cos(2*(-1.5 + R2/(2.*s2))* atan((q*s2)/R)))/R2 -
00838 (2*(-1.5 + R2/(2.*s2))*s2* pow(1 + (q2*s4)/R2,
00839 0.5 - R2/(2.*s2))* sin(2*(-1.5 + R2/(2.*s2))*
00840 atan((q*s2)/R)))/R))/
00841 (2.*q2*(-1.5 + R2/(2.*s2))* (-1 + R2/(2.*s2))*s4)))/
00842 (sqrt(2*M_PI)*q2*(-0.5 + R2/(2.*s2))* s2));
00843
00844 realt dR = height * (
00845 (3*R2*(-1 - (R2* (-1 + pow(1 + (q2*s4)/R2,
00846 1.5 - R2/(2.*s2))* cos(2*(-1.5 + R2/(2.*s2))*
00847 atan((q*s2)/R))))/ (2.*q2*(-1.5 + R2/(2.*s2))*
00848 (-1 + R2/(2.*s2))*s4)))/ (sqrt(2*M_PI)*q2*pow(-0.5 + R2/(2.*s2),2)*
00849 s4) - (3*(-1 - (R2*(-1 + pow(1 + (q2*s4)/R2,
00850 1.5 - R2/(2.*s2))* cos(2*(-1.5 + R2/(2.*s2))*
00851 atan((q*s2)/R))))/ (2.*q2*(-1.5 + R2/(2.*s2))*
00852 (-1 + R2/(2.*s2))*s4)))/ (sqrt(2*M_PI)*q2*(-0.5 + R2/(2.*s2))*
00853 s2) - (3*R*((R3* (-1 + pow(1 + (q2*s4)/R2,
00854 1.5 - R2/(2.*s2))* cos(2*(-1.5 + R2/(2.*s2))*
00855 atan((q*s2)/R))))/ (2.*q2*(-1.5 + R2/(2.*s2))*
00856 pow(-1 + R2/(2.*s2),2)*s4*s2) + (R3*(-1 + pow(1 + (q2*s4)/R2,
00857 1.5 - R2/(2.*s2))* cos(2*(-1.5 + R2/(2.*s2))* atan((q*s2)/R))))/
00858 (2.*q2*pow(-1.5 + R2/(2.*s2),2)* (-1 + R2/(2.*s2))*(s4*s2)) -
00859 (R*(-1 + pow(1 + (q2*s4)/R2, 1.5 - R2/(2.*s2))*
00860 cos(2*(-1.5 + R2/(2.*s2))* atan((q*s2)/R))))/
00861 (q2*(-1.5 + R2/(2.*s2))* (-1 + R2/(2.*s2))*s4) -
00862 (R2*(pow(1 + (q2*s4)/R2, 1.5 - R2/(2.*s2))*
00863 cos(2*(-1.5 + R2/(2.*s2))* atan((q*s2)/R))*
00864 ((-2*q2*(1.5 - R2/(2.*s2))* s4)/ (R3*
00865 (1 + (q2*s4)/R2)) - (R*log(1 + (q2*s4)/R2))/ s2) +
00866 pow(1 + (q2*s4)/R2, 1.5 - R2/(2.*s2))* ((2*q*(-1.5 + R2/(2.*s2))*
00867 s2)/ (R2* (1 + (q2*s4)/R2)) - (2*R*atan((q*s2)/R))/s2)*
00868 sin(2*(-1.5 + R2/(2.*s2))* atan((q*s2)/R))))/
00869 (2.*q2*(-1.5 + R2/(2.*s2))* (-1 + R2/(2.*s2))*s4)))/
00870 (sqrt(2*M_PI)*q2*(-0.5 + R2/(2.*s2))* s2));
00871
00872 realt ds = height * (
00873 (-3*R3*(-1 - (R2* (-1 + pow(1 + (q2*s4)/R2,
00874 1.5 - R2/(2.*s2))* cos(2*(-1.5 + R2/(2.*s2))*
00875 atan((q*s2)/R))))/ (2.*q2*(-1.5 + R2/(2.*s2))*
00876 (-1 + R2/(2.*s2))*s4)))/
00877 (sqrt(2*M_PI)*q2*pow(-0.5 + R2/(2.*s2),2)* (s4*s)) + (3*sqrt(2/M_PI)*R*
00878 (-1 - (R2*(-1 + pow(1 + (q2*s4)/R2, 1.5 - R2/(2.*s2))*
00879 cos(2*(-1.5 + R2/(2.*s2))* atan((q*s2)/R))))/
00880 (2.*q2*(-1.5 + R2/(2.*s2))* (-1 + R2/(2.*s2))*s4)))/
00881 (q2*(-0.5 + R2/(2.*s2))*s3) - (3*R*(-(R4*(-1 +
00882 pow(1 + (q2*s4)/R2, 1.5 - R2/(2.*s2))*
00883 cos(2*(-1.5 + R2/(2.*s2))* atan((q*s2)/R))))/
00884 (2.*q2*(-1.5 + R2/(2.*s2))* pow(-1 + R2/(2.*s2),2)*(s4*s3)) -
00885 (R4*(-1 + pow(1 + (q2*s4)/R2, 1.5 - R2/(2.*s2))*
00886 cos(2*(-1.5 + R2/(2.*s2))* atan((q*s2)/R))))/
00887 (2.*q2*pow(-1.5 + R2/(2.*s2),2)* (-1 + R2/(2.*s2))*(s4*s3)) +
00888 (2*R2*(-1 + pow(1 + (q2*s4)/R2,
00889 1.5 - R2/(2.*s2))* cos(2*(-1.5 + R2/(2.*s2))*
00890 atan((q*s2)/R))))/ (q2*(-1.5 + R2/(2.*s2))*
00891 (-1 + R2/(2.*s2))*(s4*s)) - (R2*(pow(1 + (q2*s4)/R2,
00892 1.5 - R2/(2.*s2))* cos(2*(-1.5 + R2/(2.*s2))*
00893 atan((q*s2)/R))* ((4*q2*(1.5 - R2/(2.*s2))* s3)/
00894 (R2* (1 + (q2*s4)/R2)) + (R2*log(1 +
00895 (q2*s4)/R2))/ s3) +
00896 pow(1 + (q2*s4)/R2, 1.5 - R2/(2.*s2))*
00897 ((-4*q*(-1.5 + R2/(2.*s2))*s)/ (R*(1 + (q2*s4)/R2)) +
00898 (2*R2*atan((q*s2)/R))/ s3)*
00899 sin(2*(-1.5 + R2/(2.*s2))* atan((q*s2)/R))))/
00900 (2.*q2*(-1.5 + R2/(2.*s2))* (-1 + R2/(2.*s2))*s4)))/
00901 (sqrt(2*M_PI)*q2*(-0.5 + R2/(2.*s2))* s2));
00902
00903 dy_dv[0] = t;
00904 dy_dv[1] = -dcenter;
00905 dy_dv[2] = dR;
00906 dy_dv[3] = ds;
00907 dy_dx = dcenter;
00908 CALCULATE_DERIV_END(height*t);
00909
00910
00911
00912
00913
00914
00915 void FuncLogNormal::more_precomputations()
00916 {
00917 if (av_.size() != 4)
00918 av_.resize(4);
00919 if (fabs(av_[2]) < epsilon)
00920 av_[2] = epsilon;
00921 if (fabs(av_[3]) < epsilon)
00922 av_[3] = 0.001;
00923 }
00924
00925 CALCULATE_VALUE_BEGIN(FuncLogNormal)
00926 realt a = 2.0 * av_[3] * (x - av_[1]) / av_[2];
00927 realt ex = 0.0;
00928 if (a > -1.0) {
00929 realt b = log(1 + a) / av_[3];
00930 ex = av_[0] * exp(-M_LN2 * b * b);
00931 }
00932 CALCULATE_VALUE_END(ex)
00933
00934 CALCULATE_DERIV_BEGIN(FuncLogNormal)
00935 realt a = 2.0 * av_[3] * (x - av_[1]) / av_[2];
00936 realt ex;
00937 if (a > -1.0) {
00938 realt b = log(1 + a) / av_[3];
00939 ex = exp(-M_LN2 * b * b);
00940 dy_dv[0] = ex;
00941 ex *= av_[0];
00942 dy_dv[1] = 4.0*M_LN2/(av_[2]*(a+1))*ex*b;
00943 dy_dv[2] = 4.0*(x-av_[1])*M_LN2/(av_[2]*av_[2]*(a+1))*ex*b;
00944 dy_dv[3] = ex*(2.0*M_LN2*b*b/av_[3]
00945 -4.0*(x-av_[1])*log(a+1)*M_LN2/(av_[2]*av_[3]*av_[3]*(a+1)));
00946 dy_dx = -4.0*M_LN2/(av_[2]*(a+1))*ex*b;
00947 }
00948 else {
00949 ex = 0.0;
00950 dy_dv[0] = 0.0;
00951 dy_dv[1] = 0.0;
00952 dy_dv[2] = 0.0;
00953 dy_dv[3] = 0.0;
00954 dy_dx = 0.0;
00955 }
00956 CALCULATE_DERIV_END(ex)
00957
00958 bool FuncLogNormal::get_nonzero_range(double level,
00959 realt &left, realt &right) const
00960 {
00961 if (level == 0)
00962 return false;
00963 else if (fabs(level) >= fabs(av_[0]))
00964 left = right = 0;
00965 else {
00966
00967 realt w1 = (1-exp(sqrt(log(fabs(av_[0]/level))/M_LN2)*av_[3]))*av_[2]
00968 /2.0/av_[3]+av_[1];
00969 realt w0 = (1-exp(-sqrt(log(fabs(av_[0]/level))/M_LN2)*av_[3]))*av_[2]
00970 /2.0/av_[3]+av_[1];
00971 if (w1>w0) {
00972 left = w0;
00973 right = w1;
00974 }
00975 else {
00976 left = w1;
00977 right = w0;
00978 }
00979 }
00980 return true;
00981 }
00982
00983
00984 bool FuncLogNormal::get_fwhm(realt* a) const
00985 {
00986 *a = av_[2]*sinh(av_[3])/av_[3];
00987 return true;
00988 }
00989
00990 bool FuncLogNormal::get_area(realt* a) const
00991 {
00992 *a = av_[0]/sqrt(M_LN2/M_PI) / (2.0/av_[2]) / exp(-av_[3]*av_[3]/4.0/M_LN2);
00993 return true;
00994 }
00995
00996
00997
00998 void FuncSpline::more_precomputations()
00999 {
01000 q_.resize(nv() / 2);
01001 for (size_t i = 0; i < q_.size(); ++i) {
01002 q_[i].x = av_[2*i];
01003 q_[i].y = av_[2*i+1];
01004 }
01005 prepare_spline_interpolation(q_);
01006
01007 }
01008
01009 CALCULATE_VALUE_BEGIN(FuncSpline)
01010 realt t = get_spline_interpolation(q_, x);
01011 CALCULATE_VALUE_END(t)
01012
01013 CALCULATE_DERIV_BEGIN(FuncSpline)
01014 dy_dx = 0;
01015
01016 realt t = get_spline_interpolation(q_, x);
01017 CALCULATE_DERIV_END(t)
01018
01019
01020
01021 void FuncPolyline::more_precomputations()
01022 {
01023 q_.resize(nv() / 2);
01024 for (size_t i = 0; i < q_.size(); ++i) {
01025 q_[i].x = av_[2*i];
01026 q_[i].y = av_[2*i+1];
01027 }
01028 }
01029
01030 CALCULATE_VALUE_BEGIN(FuncPolyline)
01031 realt t = get_linear_interpolation(q_, x);
01032 CALCULATE_VALUE_END(t)
01033
01034 CALCULATE_DERIV_BEGIN(FuncPolyline)
01035 double value;
01036 if (q_.empty()) {
01037 dy_dx = 0;
01038 value = 0.;
01039 }
01040 else if (q_.size() == 1) {
01041
01042 dy_dv[1] = 1;
01043 dy_dx = 0;
01044 value = q_[0].y;
01045 }
01046 else {
01047
01048 vector<PointD>::iterator pos = get_interpolation_segment(q_, x);
01049 double lx = (pos + 1)->x - pos->x;
01050 double ly = (pos + 1)->y - pos->y;
01051 double d = x - pos->x;
01052 double a = ly / lx;
01053 size_t npos = pos - q_.begin();
01054 dy_dv[2*npos+0] = a*d/lx - a;
01055 dy_dv[2*npos+1] = 1 - d/lx;
01056 dy_dv[2*npos+2] = -a*d/lx;
01057 dy_dv[2*npos+3] = d/lx;
01058 dy_dx = a;
01059 value = pos->y + a * d;
01060 }
01061 CALCULATE_DERIV_END(value)
01062
01063
01064