1 /***************************************************************************
2 File : ExpDecayDialog.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 : Fit exponential decay dialog
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 "ExpDecayDialog.h"
30 #include "Graph.h"
31 #include "ColorButton.h"
32 #include "ApplicationWindow.h"
33 #include "Fit.h"
34 #include "ExponentialFit.h"
35
36 #include <QMessageBox>
37 #include <QLayout>
38 #include <QGroupBox>
39 #include <QPushButton>
40 #include <QLabel>
41 #include <QLineEdit>
42 #include <QComboBox>
43 #include <QCloseEvent>
44
ExpDecayDialog(int type,QWidget * parent,Qt::WindowFlags fl)45 ExpDecayDialog::ExpDecayDialog(int type, QWidget *parent, Qt::WindowFlags fl) : QDialog(parent, fl)
46 {
47 slopes = type;
48
49 setWindowTitle(tr("Verify initial guesses"));
50
51 QGroupBox *gb1 = new QGroupBox();
52 QGridLayout *gl1 = new QGridLayout();
53 gl1->addWidget(new QLabel(tr("Exponential Fit of")), 0, 0);
54
55 boxName = new QComboBox();
56 connect(boxName, SIGNAL(activated(const QString &)), this,
57 SLOT(activateCurve(const QString &)));
58 gl1->addWidget(boxName, 0, 1);
59
60 if (type < 0)
61 dampingLabel = new QLabel(tr("Growth time"));
62 else if (type == 1)
63 dampingLabel = new QLabel(tr("Decay time"));
64 else
65 dampingLabel = new QLabel(tr("First decay time (t1)"));
66 gl1->addWidget(dampingLabel, 1, 0);
67
68 boxFirst = new QLineEdit();
69 boxFirst->setText(tr("1"));
70 gl1->addWidget(boxFirst, 1, 1);
71
72 if (type > 1) {
73 gl1->addWidget(new QLabel(tr("Second decay time (t2)")), 2, 0);
74
75 boxSecond = new QLineEdit();
76 boxSecond->setText(tr("1"));
77 gl1->addWidget(boxSecond, 2, 1);
78
79 thirdLabel = new QLabel(tr("Third decay time (t3)"));
80 gl1->addWidget(thirdLabel, 3, 0);
81
82 boxThird = new QLineEdit();
83 boxThird->setText(tr("1"));
84 gl1->addWidget(boxThird, 3, 1);
85
86 if (type < 3) {
87 thirdLabel->hide();
88 boxThird->hide();
89 }
90 }
91
92 if (type <= 1) {
93 gl1->addWidget(new QLabel(tr("Amplitude")), 2, 0);
94 boxAmplitude = new QLineEdit();
95 boxAmplitude->setText(tr("1"));
96 gl1->addWidget(boxAmplitude, 2, 1);
97 }
98
99 gl1->addWidget(new QLabel(tr("Y Offset")), 4, 0);
100 boxYOffset = new QLineEdit();
101 boxYOffset->setText(tr("0"));
102 gl1->addWidget(boxYOffset, 4, 1);
103
104 gl1->addWidget(new QLabel(tr("Initial time")), 5, 0);
105
106 boxStart = new QLineEdit();
107 boxStart->setText(tr("0"));
108 gl1->addWidget(boxStart, 5, 1);
109
110 gl1->addWidget(new QLabel(tr("Color")), 6, 0);
111 btnColor = new ColorButton();
112 btnColor->setColor(QColor(Qt::red));
113 gl1->addWidget(btnColor, 6, 1);
114
115 gb1->setLayout(gl1);
116
117 buttonFit = new QPushButton(tr("&Fit"));
118 buttonFit->setDefault(true);
119
120 buttonCancel = new QPushButton(tr("&Close"));
121
122 QBoxLayout *bl1 = new QBoxLayout(QBoxLayout::TopToBottom);
123 bl1->addWidget(buttonFit);
124 bl1->addWidget(buttonCancel);
125 bl1->addStretch();
126
127 QHBoxLayout *hlayout = new QHBoxLayout();
128 hlayout->addWidget(gb1);
129 hlayout->addLayout(bl1);
130 setLayout(hlayout);
131
132 // signals and slots connections
133 connect(buttonFit, SIGNAL(clicked()), this, SLOT(fit()));
134 connect(buttonCancel, SIGNAL(clicked()), this, SLOT(close()));
135 }
136
setGraph(Graph * g)137 void ExpDecayDialog::setGraph(Graph *g)
138 {
139 if (!g)
140 return;
141
142 fitter = 0;
143 graph = g;
144
145 boxName->addItems(graph->analysableCurvesList());
146
147 QString selectedCurve = g->selectedCurveTitle();
148 if (!selectedCurve.isEmpty()) {
149 int index = boxName->findText(selectedCurve);
150 boxName->setCurrentIndex(index);
151 }
152 activateCurve(boxName->currentText());
153
154 connect(graph, SIGNAL(closedGraph()), this, SLOT(close()));
155 connect(graph, SIGNAL(dataRangeChanged()), this, SLOT(changeDataRange()));
156 }
157
activateCurve(const QString & curveName)158 void ExpDecayDialog::activateCurve(const QString &curveName)
159 {
160 QwtPlotCurve *c = graph->curve(curveName);
161 if (!c)
162 return;
163
164 ApplicationWindow *app = (ApplicationWindow *)this->parent();
165 if (!app)
166 return;
167
168 int precision = app->fit_output_precision;
169 double start, end;
170 graph->range(graph->curveIndex(curveName), &start, &end);
171 boxStart->setText(QString::number(qMin(start, end)));
172 boxYOffset->setText(QString::number(c->minYValue(), 'g', precision));
173 if (slopes < 2)
174 boxAmplitude->setText(QString::number(c->maxYValue() - c->minYValue(), 'g', precision));
175 }
176
changeDataRange()177 void ExpDecayDialog::changeDataRange()
178 {
179 double start = graph->selectedXStartValue();
180 double end = graph->selectedXEndValue();
181 boxStart->setText(QString::number(qMin(start, end), 'g', 15));
182 }
183
fit()184 void ExpDecayDialog::fit()
185 {
186 QString curve = boxName->currentText();
187 QwtPlotCurve *c = graph->curve(curve);
188 QStringList curvesList = graph->analysableCurvesList();
189 if (!c || !curvesList.contains(curve)) {
190 QMessageBox::critical(
191 this, tr("Warning"),
192 tr("The curve <b> %1 </b> doesn't exist anymore! Operation aborted!").arg(curve));
193 boxName->clear();
194 boxName->addItems(curvesList);
195 return;
196 }
197
198 ApplicationWindow *app = (ApplicationWindow *)this->parent();
199 if (!app)
200 return;
201
202 int precision = app->fit_output_precision;
203
204 if (fitter)
205 delete fitter;
206
207 if (slopes == 3) {
208 double x_init[7] = { 1.0,
209 boxFirst->text().toDouble(),
210 1.0,
211 boxSecond->text().toDouble(),
212 1.0,
213 boxThird->text().toDouble(),
214 boxYOffset->text().toDouble() };
215 fitter = new ThreeExpFit(app, graph);
216 fitter->setInitialGuesses(x_init);
217 } else if (slopes == 2) {
218 double x_init[5] = { 1.0, boxFirst->text().toDouble(), 1.0, boxSecond->text().toDouble(),
219 boxYOffset->text().toDouble() };
220 fitter = new TwoExpFit(app, graph);
221 fitter->setInitialGuesses(x_init);
222 } else if (slopes == 1 || slopes == -1) {
223 double x_init[3] = { boxAmplitude->text().toDouble(), slopes / boxFirst->text().toDouble(),
224 boxYOffset->text().toDouble() };
225 fitter = new ExponentialFit(app, graph, slopes == -1);
226 fitter->setInitialGuesses(x_init);
227 }
228
229 if (fitter->setDataFromCurve(boxName->currentText(), boxStart->text().toDouble(),
230 c->maxXValue())) {
231 fitter->setColor(btnColor->color());
232 fitter->scaleErrors(app->fit_scale_errors);
233 fitter->setOutputPrecision(app->fit_output_precision);
234 fitter->generateFunction(app->generateUniformFitPoints, app->fitPoints);
235 fitter->fit();
236
237 auto &results = fitter->results();
238 boxFirst->setText(QString::number(results[1], 'g', precision));
239 if (slopes < 2) {
240 boxAmplitude->setText(QString::number(results[0], 'g', precision));
241 boxYOffset->setText(QString::number(results[2], 'g', precision));
242 } else if (slopes == 2) {
243 boxSecond->setText(QString::number(results[3], 'g', precision));
244 boxYOffset->setText(QString::number(results[4], 'g', precision));
245 } else if (slopes == 3) {
246 boxSecond->setText(QString::number(results[3], 'g', precision));
247 boxThird->setText(QString::number(results[5], 'g', precision));
248 boxYOffset->setText(QString::number(results[6], 'g', precision));
249 }
250 }
251 }
252
closeEvent(QCloseEvent * e)253 void ExpDecayDialog::closeEvent(QCloseEvent *e)
254 {
255 if (fitter) {
256 ApplicationWindow *app = (ApplicationWindow *)this->parent();
257 if (app && app->pasteFitResultsToPlot)
258 fitter->showLegend();
259
260 delete fitter;
261 }
262
263 e->accept();
264 }
265