00001
00002
00003
00004 #include "func.h"
00005 #include "common.h"
00006 #include "bfunc.h"
00007 #include "settings.h"
00008 #include "udf.h"
00009
00010 using namespace std;
00011
00012 vector<realt> Function::calc_val_xx(1);
00013 vector<realt> Function::calc_val_yy(1);
00014
00015 Function::Function(const Settings* settings,
00016 const string &name,
00017 const Tplate::Ptr tp,
00018 const vector<string> &vars)
00019 : VariableUser(name, "%", vars),
00020 settings_(settings),
00021 tp_(tp),
00022 av_(vars.size())
00023 {
00024 }
00025
00026 void Function::init()
00027 {
00028 center_idx_ = index_of_element(tp_->fargs, "center");
00029 if (av_.size() != tp_->fargs.size())
00030 throw ExecuteError("Function " + tp_->name + " requires "
00031 + S(tp_->fargs.size()) + " argument(s), got " + S(av_.size()) + ".");
00032 }
00033
00034 Function* Function::factory(const Settings* settings,
00035 const string &name, const Tplate::Ptr tp,
00036 const vector<string> &vars)
00037 {
00038 if (false) {}
00039
00040 #define FACTORY_FUNC(NAME) \
00041 else if (tp->name == #NAME) \
00042 return new Func##NAME(settings, name, tp, vars);
00043
00044 FACTORY_FUNC(Constant)
00045 FACTORY_FUNC(Linear)
00046 FACTORY_FUNC(Quadratic)
00047 FACTORY_FUNC(Cubic)
00048 FACTORY_FUNC(Polynomial4)
00049 FACTORY_FUNC(Polynomial5)
00050 FACTORY_FUNC(Polynomial6)
00051 FACTORY_FUNC(Gaussian)
00052 FACTORY_FUNC(SplitGaussian)
00053 FACTORY_FUNC(Lorentzian)
00054 FACTORY_FUNC(Pearson7)
00055 FACTORY_FUNC(SplitPearson7)
00056 FACTORY_FUNC(PseudoVoigt)
00057 FACTORY_FUNC(Voigt)
00058 FACTORY_FUNC(VoigtA)
00059 FACTORY_FUNC(EMG)
00060 FACTORY_FUNC(DoniachSunjic)
00061 FACTORY_FUNC(PielaszekCube)
00062 FACTORY_FUNC(LogNormal)
00063 FACTORY_FUNC(Spline)
00064 FACTORY_FUNC(Polyline)
00065
00066 else
00067 return NULL;
00068 }
00069
00070 void Function::do_precomputations(const vector<Variable*> &variables)
00071 {
00072
00073 multi_.clear();
00074 for (int i = 0; i < size(var_idx); ++i) {
00075 const Variable *v = variables[var_idx[i]];
00076 av_[i] = v->get_value();
00077 v_foreach (Variable::ParMult, j, v->recursive_derivatives())
00078 multi_.push_back(Multi(i, *j));
00079 }
00080 this->more_precomputations();
00081 }
00082
00083 void Function::erased_parameter(int k)
00084 {
00085 vm_foreach (Multi, i, multi_)
00086 if (i->p > k)
00087 -- i->p;
00088 }
00089
00090
00091 void Function::calculate_value(const vector<realt> &x, vector<realt> &y) const
00092 {
00093 realt left, right;
00094 double cut_level = settings_->function_cutoff;
00095 bool r = get_nonzero_range(cut_level, left, right);
00096 if (r) {
00097 int first = lower_bound(x.begin(), x.end(), left) - x.begin();
00098 int last = upper_bound(x.begin(), x.end(), right) - x.begin();
00099 this->calculate_value_in_range(x, y, first, last);
00100 }
00101 else
00102 this->calculate_value_in_range(x, y, 0, x.size());
00103 }
00104
00105 realt Function::calculate_value(realt x) const
00106 {
00107 calc_val_xx[0] = x;
00108 calc_val_yy[0] = 0.;
00109 calculate_value_in_range(calc_val_xx, calc_val_yy, 0, 1);
00110 return calc_val_yy[0];
00111 }
00112
00113 void Function::calculate_value_deriv(const vector<realt> &x,
00114 vector<realt> &y,
00115 vector<realt> &dy_da,
00116 bool in_dx) const
00117 {
00118 realt left, right;
00119 double cut_level = settings_->function_cutoff;
00120 bool r = get_nonzero_range(cut_level, left, right);
00121 if (r) {
00122 int first = lower_bound(x.begin(), x.end(), left) - x.begin();
00123 int last = upper_bound(x.begin(), x.end(), right) - x.begin();
00124 this->calculate_value_deriv_in_range(x, y, dy_da, in_dx, first, last);
00125 }
00126 else
00127 this->calculate_value_deriv_in_range(x, y, dy_da, in_dx, 0, x.size());
00128 }
00129
00130 bool Function::get_center(realt* a) const
00131 {
00132 if (center_idx_ != -1) {
00133 *a = av_[center_idx_];
00134 return true;
00135 }
00136 return false;
00137 }
00138
00139 bool Function::get_iwidth(realt* a) const
00140 {
00141 realt area, height;
00142 if (this->get_area(&area) && this->get_height(&height)) {
00143 *a = height != 0. ? area / height : 0.;
00144 return true;
00145 }
00146 return false;
00147 }
00148
00149
00150 string Function::get_basic_assignment() const
00151 {
00152 string r = "%" + name + " = " + tp_->name + "(";
00153 v_foreach (string, i, varnames)
00154 r += (i == varnames.begin() ? "$" : ", $") + *i;
00155 r += ")";
00156 return r;
00157 }
00158
00159
00160 string Function::get_current_assignment(const vector<Variable*> &variables,
00161 const vector<realt> ¶meters) const
00162 {
00163 vector<string> vs;
00164 for (int i = 0; i < size(var_idx); ++i) {
00165 const Variable* v = variables[var_idx[i]];
00166 string t = get_param(i) + "="
00167 + (v->is_simple() ? v->get_formula(parameters) : "$" + v->name);
00168 vs.push_back(t);
00169 }
00170 return "%" + name + " = " + tp_->name + "(" + join_vector(vs, ", ") + ")";
00171 }
00172
00173 string Function::get_current_formula(const string& x) const
00174 {
00175 string t;
00176 if (contains_element(tp_->rhs, '#')) {
00177 t = tp_->name + "(" + join(av_.begin(), av_.begin() + nv(), ", ") + ")";
00178 }
00179 else {
00180 t = tp_->rhs;
00181 for (size_t i = 0; i < tp_->fargs.size(); ++i)
00182 replace_words(t, tp_->fargs[i], S(av_[i]));
00183 }
00184
00185 replace_words(t, "x", x);
00186 return t;
00187 }
00188
00189 int Function::get_param_nr(const string& param) const
00190 {
00191 int n = index_of_element(tp_->fargs, param);
00192 if (n == -1)
00193 throw ExecuteError("%" + name + " has no parameter `" + param + "'");
00194 return n;
00195 }
00196
00197 realt Function::get_param_value(const string& param) const
00198 {
00199 realt a;
00200 if (!param.empty() && islower(param[0]))
00201 return av_[get_param_nr(param)];
00202 else if (param == "Center" && get_center(&a)) {
00203 return a;
00204 }
00205 else if (param == "Height" && get_height(&a)) {
00206 return a;
00207 }
00208 else if (param == "FWHM" && get_fwhm(&a)) {
00209 return a;
00210 }
00211 else if (param == "Area" && get_area(&a)) {
00212 return a;
00213 }
00214 else
00215 throw ExecuteError("%" + name + " (" + tp_->name
00216 + ") has no parameter `" + param + "'");
00217 }
00218
00219 realt Function::numarea(realt x1, realt x2, int nsteps) const
00220 {
00221 if (nsteps <= 1)
00222 return 0.;
00223 realt xmin = min(x1, x2);
00224 realt xmax = max(x1, x2);
00225 realt h = (xmax - xmin) / (nsteps-1);
00226 vector<realt> xx(nsteps), yy(nsteps);
00227 for (int i = 0; i < nsteps; ++i)
00228 xx[i] = xmin + i*h;
00229 calculate_value(xx, yy);
00230 realt a = (yy[0] + yy[nsteps-1]) / 2.;
00231 for (int i = 1; i < nsteps-1; ++i)
00232 a += yy[i];
00233 return a*h;
00234 }
00235
00236
00237
00238
00239 realt Function::find_x_with_value(realt x1, realt x2, realt val,
00240 int max_iter) const
00241 {
00242 realt y1 = calculate_value(x1) - val;
00243 realt y2 = calculate_value(x2) - val;
00244 if ((y1 > 0 && y2 > 0) || (y1 < 0 && y2 < 0))
00245 throw ExecuteError("Value " + S(val) + " is not bracketed by "
00246 + S(x1) + "(" + S(y1+val) + ") and "
00247 + S(x2) + "(" + S(y2+val) + ").");
00248 int n = 0;
00249 v_foreach (Multi, j, multi_)
00250 n = max(j->p + 1, n);
00251 vector<realt> dy_da(n+1);
00252 if (y1 == 0)
00253 return x1;
00254 if (y2 == 0)
00255 return x2;
00256 if (y1 > 0)
00257 swap(x1, x2);
00258 realt t = (x1 + x2) / 2.;
00259 for (int i = 0; i < max_iter; ++i) {
00260
00261 if (is_eq(x1, x2))
00262 return (x1+x2) / 2.;
00263
00264
00265 calc_val_xx[0] = t;
00266 calc_val_yy[0] = 0;
00267 dy_da.back() = 0;
00268 calculate_value_deriv(calc_val_xx, calc_val_yy, dy_da);
00269 realt f = calc_val_yy[0] - val;
00270 realt df = dy_da.back();
00271
00272
00273 if (f == 0.)
00274 return t;
00275 else if (f < 0)
00276 x1 = t;
00277 else
00278 x2 = t;
00279
00280
00281 realt dx = -f/df * 1.02;
00282 if ((t+dx > x2 && t+dx > x1) || (t+dx < x2 && t+dx < x1)
00283 || i % 20 == 19) {
00284
00285 t = (x1 + x2) / 2.;
00286 }
00287 else {
00288 t += dx;
00289 }
00290 }
00291 throw ExecuteError("The search has not converged in " + S(max_iter)
00292 + " steps");
00293 }
00294
00295
00296 realt Function::find_extremum(realt x1, realt x2, int max_iter) const
00297 {
00298 int n = 0;
00299 v_foreach (Multi, j, multi_)
00300 n = max(j->p + 1, n);
00301 vector<realt> dy_da(n+1);
00302
00303
00304 calc_val_xx[0] = x1;
00305 dy_da.back() = 0;
00306 calculate_value_deriv(calc_val_xx, calc_val_yy, dy_da);
00307 realt y1 = dy_da.back();
00308
00309 calc_val_xx[0] = x2;
00310 dy_da.back() = 0;
00311 calculate_value_deriv(calc_val_xx, calc_val_yy, dy_da);
00312 realt y2 = dy_da.back();
00313
00314 if ((y1 > 0 && y2 > 0) || (y1 < 0 && y2 < 0))
00315 throw ExecuteError("Derivatives at " + S(x1) + " and " + S(x2)
00316 + " have the same sign.");
00317 if (y1 == 0)
00318 return x1;
00319 if (y2 == 0)
00320 return x2;
00321 if (y1 > 0)
00322 swap(x1, x2);
00323 for (int i = 0; i < max_iter; ++i) {
00324 realt t = (x1 + x2) / 2.;
00325
00326
00327 calc_val_xx[0] = t;
00328 dy_da.back() = 0;
00329 calculate_value_deriv(calc_val_xx, calc_val_yy, dy_da);
00330 realt df = dy_da.back();
00331
00332
00333 if (df == 0.)
00334 return t;
00335 else if (df < 0)
00336 x1 = t;
00337 else
00338 x2 = t;
00339
00340
00341 if (is_eq(x1, x2))
00342 return (x1+x2) / 2.;
00343 }
00344 throw ExecuteError("The search has not converged in " + S(max_iter)
00345 + " steps");
00346 }
00347