1 /***************************************************************************
2 File : PolynomialFit.cpp
3 Project : SciDAVis
4 --------------------------------------------------------------------
5 Copyright : (C) 2006 by Ion Vasilief, Tilman Benkert
6 Email (use @ for *) : ion_vasilief*yahoo.fr, thzs*gmx.net
7 Description : Polynomial Fit and Linear Fit classes
8
9 ***************************************************************************/
10
11 /***************************************************************************
12 * *
13 * This program is free software; you can redistribute it and/or modify *
14 * it under the terms of the GNU General Public License as published by *
15 * the Free Software Foundation; either version 2 of the License, or *
16 * (at your option) any later version. *
17 * *
18 * This program is distributed in the hope that it will be useful, *
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
21 * GNU General Public License for more details. *
22 * *
23 * You should have received a copy of the GNU General Public License *
24 * along with this program; if not, write to the Free Software *
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
26 * Boston, MA 02110-1301 USA *
27 * *
28 ***************************************************************************/
29 #include "PolynomialFit.h"
30
31 #include <QMessageBox>
32 #include <QLocale>
33
34 #include <gsl/gsl_multifit.h>
35 #include <gsl/gsl_fit.h>
36 using namespace std;
37
PolynomialFit(ApplicationWindow * parent,Graph * g,int order,bool legend)38 PolynomialFit::PolynomialFit(ApplicationWindow *parent, Graph *g, int order, bool legend)
39 : Fit(parent, g), d_order(order), show_legend(legend)
40 {
41 init();
42 }
43
PolynomialFit(ApplicationWindow * parent,Graph * g,QString & curveTitle,int order,bool legend)44 PolynomialFit::PolynomialFit(ApplicationWindow *parent, Graph *g, QString &curveTitle, int order,
45 bool legend)
46 : Fit(parent, g), d_order(order), show_legend(legend)
47 {
48 init();
49 setDataFromCurve(curveTitle);
50 }
51
PolynomialFit(ApplicationWindow * parent,Graph * g,QString & curveTitle,double start,double end,int order,bool legend)52 PolynomialFit::PolynomialFit(ApplicationWindow *parent, Graph *g, QString &curveTitle, double start,
53 double end, int order, bool legend)
54 : Fit(parent, g), d_order(order), show_legend(legend)
55 {
56 init();
57 setDataFromCurve(curveTitle, start, end);
58 }
59
init()60 void PolynomialFit::init()
61 {
62 setObjectName(tr("Poly"));
63 is_non_linear = false;
64 d_explanation = tr("Polynomial");
65 d_p = d_order + 1;
66 d_min_points = d_p;
67
68 covar = gsl_matrix_alloc(d_p, d_p);
69 d_results.resize(d_p);
70
71 d_formula = generateFormula(d_order);
72 d_param_names = generateParameterList(d_order);
73
74 for (unsigned i = 0; i < d_p; i++)
75 d_param_explain << "";
76 }
77
generateFormula(int order)78 QString PolynomialFit::generateFormula(int order)
79 {
80 QString formula;
81 for (int i = 0; i < order + 1; i++) {
82 QString par = "a" + QString::number(i);
83 formula += par;
84 if (i > 0)
85 formula += "*x";
86 if (i > 1)
87 formula += "^" + QString::number(i);
88 if (i != order)
89 formula += "+";
90 }
91 return formula;
92 }
93
generateParameterList(int order)94 QStringList PolynomialFit::generateParameterList(int order)
95 {
96 QStringList lst;
97 for (int i = 0; i < order + 1; i++)
98 lst << "a" + QString::number(i);
99 return lst;
100 }
101
calculateFitCurveData(const vector<double> & par,std::vector<double> & X,std::vector<double> & Y)102 bool PolynomialFit::calculateFitCurveData(const vector<double> &par, std::vector<double> &X,
103 std::vector<double> &Y)
104 {
105 generateX(X);
106 for (int i = 0; i < d_points; i++) {
107 double yi = 0.0;
108 for (unsigned j = 0; j < d_p; j++)
109 yi += par[j] * pow(X[i], j);
110 Y[i] = yi;
111 }
112 return true;
113 }
114
fit()115 void PolynomialFit::fit()
116 {
117 if (d_init_err)
118 return;
119
120 if (unsigned(d_p) > d_n) {
121 QMessageBox::critical(
122 (ApplicationWindow *)parent(), tr("Fit Error"),
123 tr("You need at least %1 data points for this fit operation. Operation aborted!")
124 .arg(d_p));
125 return;
126 }
127
128 gsl_matrix *X = gsl_matrix_alloc(d_n, d_p);
129 gsl_vector *c = gsl_vector_alloc(d_p);
130
131 for (unsigned i = 0; i < d_n; i++) {
132 for (unsigned j = 0; j < d_p; j++)
133 gsl_matrix_set(X, i, j, pow(d_x[i], j));
134 }
135
136 gsl_vector_view y = gsl_vector_view_array(d_y, d_n);
137
138 gsl_vector *weights = gsl_vector_alloc(d_n);
139 for (unsigned i = 0; i < d_n; i++)
140 gsl_vector_set(weights, i, 1.0 / pow(d_y_errors[i], 2));
141
142 gsl_multifit_linear_workspace *work = gsl_multifit_linear_alloc(d_n, d_p);
143
144 if (d_y_error_source == UnknownErrors)
145 gsl_multifit_linear(X, &y.vector, c, covar, &chi_2, work);
146 else
147 gsl_multifit_wlinear(X, weights, &y.vector, c, covar, &chi_2, work);
148
149 for (unsigned i = 0; i < d_p; i++)
150 d_results[i] = gsl_vector_get(c, i);
151
152 gsl_multifit_linear_free(work);
153 gsl_matrix_free(X);
154 gsl_vector_free(c);
155 gsl_vector_free(weights);
156
157 ApplicationWindow *app = (ApplicationWindow *)parent();
158 if (app->writeFitResultsToLog)
159 app->updateLog(logFitInfo(d_results, 0, 0, d_graph->parentPlotName()));
160
161 if (show_legend || app->pasteFitResultsToPlot)
162 showLegend();
163
164 generateFitCurve(d_results);
165 }
166
legendInfo()167 QString PolynomialFit::legendInfo()
168 {
169 ApplicationWindow *app = (ApplicationWindow *)parent();
170 QString legend = "";
171 if (show_legend) {
172 legend = "Y=" + QLocale().toString(d_results[0], 'g', d_prec);
173 for (unsigned j = 1; j < d_p; j++) {
174 double cj = d_results[j];
175 if (cj > 0 && !legend.isEmpty())
176 legend += "+";
177
178 QString s;
179 s.asprintf("%.5f", cj);
180 if (s != "1.00000")
181 legend += QLocale().toString(cj, 'g', d_prec);
182
183 legend += "X";
184 if (j > 1)
185 legend += "<sup>" + QString::number(j) + "</sup>";
186 }
187 }
188 if (app->pasteFitResultsToPlot) {
189 if (show_legend) {
190 legend += "\n";
191 }
192 legend += Fit::legendInfo();
193 }
194 return legend;
195 }
196
197 /*****************************************************************************
198 *
199 * Class LinearFit
200 *
201 *****************************************************************************/
202
LinearFit(ApplicationWindow * parent,Graph * g)203 LinearFit::LinearFit(ApplicationWindow *parent, Graph *g) : Fit(parent, g)
204 {
205 init();
206 }
207
LinearFit(ApplicationWindow * parent,Graph * g,const QString & curveTitle)208 LinearFit::LinearFit(ApplicationWindow *parent, Graph *g, const QString &curveTitle)
209 : Fit(parent, g)
210 {
211 init();
212 setDataFromCurve(curveTitle);
213 }
214
LinearFit(ApplicationWindow * parent,Graph * g,const QString & curveTitle,double start,double end)215 LinearFit::LinearFit(ApplicationWindow *parent, Graph *g, const QString &curveTitle, double start,
216 double end)
217 : Fit(parent, g)
218 {
219 init();
220 setDataFromCurve(curveTitle, start, end);
221 }
222
init()223 void LinearFit::init()
224 {
225 d_p = 2;
226 d_min_points = d_p;
227
228 covar = gsl_matrix_alloc(d_p, d_p);
229 d_results.resize(d_p);
230
231 is_non_linear = false;
232 d_formula = "A*x+B";
233 d_param_names << "B"
234 << "A";
235 d_param_explain << tr("(y-intercept)") << tr("(slope)");
236 d_explanation = tr("Linear Regression");
237 setObjectName(tr("Linear"));
238 }
239
fit()240 void LinearFit::fit()
241 {
242 if (d_init_err)
243 return;
244
245 if (d_p > d_n) {
246 QMessageBox::critical(
247 (ApplicationWindow *)parent(), tr("Fit Error"),
248 tr("You need at least %1 data points for this fit operation. Operation aborted!")
249 .arg(d_p));
250 return;
251 }
252
253 double c0, c1, cov00, cov01, cov11;
254
255 double *weights = new double[d_n];
256 for (unsigned i = 0; i < d_n; i++)
257 weights[i] = 1.0 / pow(d_y_errors[i], 2);
258
259 if (d_y_error_source == UnknownErrors)
260 gsl_fit_linear(d_x, 1, d_y, 1, d_n, &c0, &c1, &cov00, &cov01, &cov11, &chi_2);
261 else
262 gsl_fit_wlinear(d_x, 1, weights, 1, d_y, 1, d_n, &c0, &c1, &cov00, &cov01, &cov11, &chi_2);
263
264 delete[] weights;
265
266 d_results[0] = c0;
267 d_results[1] = c1;
268
269 gsl_matrix_set(covar, 0, 0, cov00);
270 gsl_matrix_set(covar, 0, 1, cov01);
271 gsl_matrix_set(covar, 1, 1, cov11);
272 gsl_matrix_set(covar, 1, 0, cov01);
273
274 ApplicationWindow *app = (ApplicationWindow *)parent();
275 if (app->writeFitResultsToLog)
276 app->updateLog(logFitInfo(d_results, 0, 0, d_graph->parentPlotName()));
277
278 generateFitCurve(d_results);
279 }
280
calculateFitCurveData(const vector<double> & par,std::vector<double> & X,std::vector<double> & Y)281 bool LinearFit::calculateFitCurveData(const vector<double> &par, std::vector<double> &X,
282 std::vector<double> &Y)
283 {
284 generateX(X);
285 for (int i = 0; i < d_points; i++)
286 Y[i] = par[0] + par[1] * X[i];
287 return true;
288 }
289