Skip to content

Commit

Permalink
bugfix for fit error messages in loop and subtle refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
Suthiro committed Mar 9, 2021
1 parent 83a36a6 commit a7ea06c
Show file tree
Hide file tree
Showing 15 changed files with 151 additions and 175 deletions.
63 changes: 19 additions & 44 deletions libscidavis/src/ExponentialFit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,21 +100,13 @@ void ExponentialFit::storeCustomFitResults(const vector<double> &par)
d_results[1] = 1.0 / d_results[1];
}

void ExponentialFit::calculateFitCurveData(const vector<double> &par, double *X, double *Y)
bool ExponentialFit::calculateFitCurveData(const vector<double> &par, std::vector<double> &X,
std::vector<double> &Y)
{
if (d_gen_function) {
double X0 = d_x[0];
double step = (d_x[d_n - 1] - X0) / (d_points - 1);
for (int i = 0; i < d_points; i++) {
X[i] = X0 + i * step;
Y[i] = par[0] * exp(-par[1] * X[i]) + par[2];
}
} else {
for (int i = 0; i < d_points; i++) {
X[i] = d_x[i];
Y[i] = par[0] * exp(-par[1] * X[i]) + par[2];
}
}
generateX(X);
for (int i = 0; i < d_points; i++)
Y[i] = par[0] * exp(-par[1] * X[i]) + par[2];
return true;
}

/*****************************************************************************
Expand Down Expand Up @@ -175,21 +167,13 @@ void TwoExpFit::storeCustomFitResults(const vector<double> &par)
d_results[3] = 1.0 / d_results[3];
}

void TwoExpFit::calculateFitCurveData(const vector<double> &par, double *X, double *Y)
bool TwoExpFit::calculateFitCurveData(const vector<double> &par, std::vector<double> &X,
std::vector<double> &Y)
{
if (d_gen_function) {
double X0 = d_x[0];
double step = (d_x[d_n - 1] - X0) / (d_points - 1);
for (int i = 0; i < d_points; i++) {
X[i] = X0 + i * step;
Y[i] = par[0] * exp(-par[1] * X[i]) + par[2] * exp(-par[3] * X[i]) + par[4];
}
} else {
for (int i = 0; i < d_points; i++) {
X[i] = d_x[i];
Y[i] = par[0] * exp(-par[1] * X[i]) + par[2] * exp(-par[3] * X[i]) + par[4];
}
}
generateX(X);
for (int i = 0; i < d_points; i++)
Y[i] = par[0] * exp(-par[1] * X[i]) + par[2] * exp(-par[3] * X[i]) + par[4];
return true;
}

/*****************************************************************************
Expand Down Expand Up @@ -254,21 +238,12 @@ void ThreeExpFit::storeCustomFitResults(const vector<double> &par)
d_results[5] = 1.0 / d_results[5];
}

void ThreeExpFit::calculateFitCurveData(const vector<double> &par, double *X, double *Y)
bool ThreeExpFit::calculateFitCurveData(const vector<double> &par, std::vector<double> &X,
std::vector<double> &Y)
{
if (d_gen_function) {
double X0 = d_x[0];
double step = (d_x[d_n - 1] - X0) / (d_points - 1);
for (int i = 0; i < d_points; i++) {
X[i] = X0 + i * step;
Y[i] = par[0] * exp(-X[i] * par[1]) + par[2] * exp(-X[i] * par[3])
+ par[4] * exp(-X[i] * par[5]) + par[6];
}
} else {
for (int i = 0; i < d_points; i++) {
X[i] = d_x[i];
Y[i] = par[0] * exp(-X[i] * par[1]) + par[2] * exp(-X[i] * par[3])
+ par[4] * exp(-X[i] * par[5]) + par[6];
}
}
generateX(X);
for (int i = 0; i < d_points; i++)
Y[i] = par[0] * exp(-X[i] * par[1]) + par[2] * exp(-X[i] * par[3])
+ par[4] * exp(-X[i] * par[5]) + par[6];
return true;
}
9 changes: 6 additions & 3 deletions libscidavis/src/ExponentialFit.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ class ExponentialFit : public Fit
private:
void init();
void storeCustomFitResults(const std::vector<double> &) override;
void calculateFitCurveData(const std::vector<double> &, double *, double *) override;
bool calculateFitCurveData(const std::vector<double> &, std::vector<double> &,
std::vector<double> &) override;

bool is_exp_growth;
};
Expand All @@ -63,7 +64,8 @@ class TwoExpFit : public Fit
private:
void init();
void storeCustomFitResults(const std::vector<double> &) override;
void calculateFitCurveData(const std::vector<double> &, double *, double *) override;
bool calculateFitCurveData(const std::vector<double> &, std::vector<double> &,
std::vector<double> &) override;
};

class ThreeExpFit : public Fit
Expand All @@ -79,6 +81,7 @@ class ThreeExpFit : public Fit
private:
void init();
void storeCustomFitResults(const std::vector<double> &par) override;
void calculateFitCurveData(const std::vector<double> &, double *, double *) override;
bool calculateFitCurveData(const std::vector<double> &, std::vector<double> &,
std::vector<double> &) override;
};
#endif
54 changes: 41 additions & 13 deletions libscidavis/src/Fit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,9 @@ vector<double> Fit::fitGslMultifit(int &iterations, int &status)
break;
}
gsl_multifit_fdfsolver *s = gsl_multifit_fdfsolver_alloc(T, d_n, d_p);
gsl_multifit_fdfsolver_set(s, &f, d_param_init);
status = gsl_multifit_fdfsolver_set(s, &f, d_param_init);
if (status)
return result;

// iterate solver algorithm
for (iterations = 0; iterations < d_max_iterations; iterations++) {
Expand Down Expand Up @@ -496,7 +498,8 @@ void Fit::fit()
ApplicationWindow *app = (ApplicationWindow *)parent();
if (app->writeFitResultsToLog)
app->updateLog(logFitInfo(d_results, iterations, status, d_graph->parentPlotName()));

disconnect(d_script.get(), SIGNAL(error(const QString &, const QString &, int)), this,
SLOT(scriptError(const QString &, const QString &, int)));
QApplication::restoreOverrideCursor();
}

Expand All @@ -512,9 +515,13 @@ int Fit::evaluate_f(const gsl_vector *x, gsl_vector *f)
d_script->setDouble(gsl_vector_get(x, i), d_param_names[i].toUtf8());
}
for (unsigned j = 0; j < d_n; j++) {
d_script->setDouble(d_x[j], "x");
if (!d_script->setDouble(d_x[j], "x"))
return GSL_EINVAL;
bool success;
gsl_vector_set(f, j, (d_script->eval().toDouble(&success) - d_y[j]) / d_y_errors[j]);
auto y = d_script->eval();
if (y.isNull())
return GSL_EINVAL;
gsl_vector_set(f, j, (y.toDouble(&success) - d_y[j]) / d_y_errors[j]);
if (!success)
return GSL_EINVAL;
}
Expand Down Expand Up @@ -585,27 +592,36 @@ void Fit::generateFitCurve(const vector<double> &par)
if (!d_gen_function)
d_points = d_n;

double *X = new double[d_points];
double *Y = new double[d_points];
std::vector<double> X(d_points);
std::vector<double> Y(d_points);

calculateFitCurveData(par, X, Y);
if (!calculateFitCurveData(par, X, Y)) {
QMessageBox::critical(0, tr("Fit failed"), tr("An error occurred during fit!"));
return;
}

if (d_gen_function) {
insertFitFunctionCurve(objectName() + tr("Fit"), X, Y);
d_graph->replot();
delete[] X;
delete[] Y;
} else
d_graph->addFitCurve(addResultCurve(X, Y));
} else {
auto x = new double[d_points];
std::copy(X.cbegin(), X.cend(), x);
auto y = new double[d_points];
std::copy(Y.cbegin(), Y.cend(), y);
// according to addFitCurve docstring "..and frees the input data from memory."
d_graph->addFitCurve(addResultCurve(x, y));
}
}

void Fit::insertFitFunctionCurve(const QString &name, double *x, double *y, int penWidth)
void Fit::insertFitFunctionCurve(const QString &name, std::vector<double> &x,
std::vector<double> &y, int penWidth)
{
QString title = d_graph->generateFunctionName(name);
FunctionCurve *c =
new FunctionCurve((ApplicationWindow *)parent(), FunctionCurve::Normal, title);
c->setPen(QPen(d_curveColor, penWidth));
c->setData(x, y, d_points);
// "Set data by copying x- and y-values from specified memory blocks."
c->setData(x.data(), y.data(), d_points);
c->setRange(d_x[0], d_x[d_n - 1]);

QString formula;
Expand All @@ -628,3 +644,15 @@ Fit::~Fit()

gsl_matrix_free(covar);
}

void Fit::generateX(std::vector<double> &X) const
{
if (d_gen_function) {
double X0 = d_x[0];
double step = (d_x[d_n - 1] - X0) / (d_points - 1);
for (int i = 0; i < d_points; i++)
X[i] = X0 + i * step;
} else
for (int i = 0; i < d_points; i++)
X[i] = d_x[i];
}
12 changes: 10 additions & 2 deletions libscidavis/src/Fit.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,14 +122,22 @@ protected slots:
virtual void storeCustomFitResults(const std::vector<double> &par) { d_results = par; }

protected:
//! Generates argument values wrt to d_gen_function
void generateX(std::vector<double> &X) const;

//! Adds the result curve as a FunctionCurve to the plot, if d_gen_function = true
void insertFitFunctionCurve(const QString &name, double *x, double *y, int penWidth = 1);
void insertFitFunctionCurve(const QString &name, std::vector<double> &, std::vector<double> &,
int penWidth = 1);

//! Adds the result curve to the plot
virtual void generateFitCurve(const std::vector<double> &);

//! Calculates the data for the output fit curve and store itin the X an Y vectors
virtual void calculateFitCurveData(const std::vector<double> &, double *, double *) { }
virtual bool calculateFitCurveData(const std::vector<double> &, std::vector<double> &,
std::vector<double> &)
{
return false;
}

//! Output string added to the result log
virtual QString logFitInfo(const std::vector<double> &par, int iterations, int status,
Expand Down
2 changes: 1 addition & 1 deletion libscidavis/src/FitDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,7 @@ void FitDialog::saveUserFunction()
}
if (editBox->toPlainText().contains(boxName->text())) {
QMessageBox::critical(this, tr("Input function error"),
tr("You can't define functions recursevely!"));
tr("You can't define functions recursively!"));
editBox->setFocus();
return;
}
Expand Down
39 changes: 16 additions & 23 deletions libscidavis/src/MultiPeakFit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ void MultiPeakFit::storeCustomFitResults(const vector<double> &par)
}
}

void MultiPeakFit::insertPeakFunctionCurve(double *x, double *y, int peak)
void MultiPeakFit::insertPeakFunctionCurve(std::vector<double> &x, std::vector<double> &y, int peak)
{
QStringList curves = d_graph->curvesList();
int index = 0;
Expand All @@ -210,7 +210,8 @@ void MultiPeakFit::insertPeakFunctionCurve(double *x, double *y, int peak)
FunctionCurve *c =
new FunctionCurve((ApplicationWindow *)parent(), FunctionCurve::Normal, title);
c->setPen(QPen(d_peaks_color, 1));
c->setData(x, y, d_points);
//"Set data by copying x- and y-values from specified memory blocks."
c->setData(x.data(), y.data(), d_points);
c->setRange(d_x[0], d_x[d_n - 1]);

QString formula;
Expand Down Expand Up @@ -240,8 +241,8 @@ void MultiPeakFit::generateFitCurve(const vector<double> &par)
return;
}

double *X = new double[d_points];
double *Y = new double[d_points];
std::vector<double> X(d_points);
std::vector<double> Y(d_points);
int i, j;
int peaks_aux = d_peaks;
if (d_peaks == 1)
Expand Down Expand Up @@ -322,7 +323,8 @@ void MultiPeakFit::generateFitCurve(const vector<double> &par)
c->setPen(QPen(d_curveColor, 2));
else
c->setPen(QPen(d_curveColor, 1));
c->setData(X, Y, d_points);
//"Set data by copying x- and y-values from specified memory blocks."
c->setData(X.data(), Y.data(), d_points);
d_graph->insertPlotItem(c, Graph::Line);
d_graph->addFitCurve(c);

Expand All @@ -334,16 +336,15 @@ void MultiPeakFit::generateFitCurve(const vector<double> &par)
label = tableName + "_" + tr("peak") + QString::number(i + 1);
c = new DataCurve(t, tableName + "_" + columns.at(0)->name(), label);
c->setPen(QPen(d_peaks_color, 1));
c->setData(X, Y, d_points);
//"Set data by copying x- and y-values from specified memory blocks."
c->setData(X.data(), Y.data(), d_points);
d_graph->insertPlotItem(c, Graph::Line);
d_graph->addFitCurve(c);
}
}
}
d_graph->replot();

delete[] X;
delete[] Y;
gsl_matrix_free(m);
}

Expand Down Expand Up @@ -493,22 +494,14 @@ void GaussAmpFit::init()
d_formula = "y0+A*exp(-(x-xc)^2/(2*w^2))";
}

void GaussAmpFit::calculateFitCurveData(const vector<double> &par, double *X, double *Y)
bool GaussAmpFit::calculateFitCurveData(const vector<double> &par, std::vector<double> &X,
std::vector<double> &Y)
{
generateX(X);
double w2 = par[3] * par[3];
if (d_gen_function) {
double X0 = d_x[0];
double step = (d_x[d_n - 1] - X0) / (d_points - 1);
for (int i = 0; i < d_points; i++) {
X[i] = X0 + i * step;
double diff = X[i] - par[2];
Y[i] = par[1] * exp(-0.5 * diff * diff / w2) + par[0];
}
} else {
for (int i = 0; i < d_points; i++) {
X[i] = d_x[i];
double diff = X[i] - par[2];
Y[i] = par[1] * exp(-0.5 * diff * diff / w2) + par[0];
}
for (int i = 0; i < d_points; i++) {
double diff = X[i] - par[2];
Y[i] = par[1] * exp(-0.5 * diff * diff / w2) + par[0];
}
return true;
}
5 changes: 3 additions & 2 deletions libscidavis/src/MultiPeakFit.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class MultiPeakFit : public Fit
void generateFitCurve(const std::vector<double> &) override;
static QString peakFormula(int peakIndex, PeakProfile profile);
//! Inserts a peak function curve into the plot
void insertPeakFunctionCurve(double *x, double *y, int peak);
void insertPeakFunctionCurve(std::vector<double> &x, std::vector<double> &y, int peak);
void storeCustomFitResults(const std::vector<double> &) override;

//! Used by the GaussFit and LorentzFit derived classes to calculate initial values for the parameters
Expand Down Expand Up @@ -117,6 +117,7 @@ class GaussAmpFit : public Fit

private:
void init();
void calculateFitCurveData(const std::vector<double> &, double *, double *) override;
bool calculateFitCurveData(const std::vector<double> &, std::vector<double> &,
std::vector<double> &) override;
};
#endif
35 changes: 18 additions & 17 deletions libscidavis/src/NonLinearFit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,24 +100,25 @@ void NonLinearFit::setParametersList(const QStringList &lst)
d_param_explain << "";
}

void NonLinearFit::calculateFitCurveData(const vector<double> &par, double *X, double *Y)
bool NonLinearFit::calculateFitCurveData(const vector<double> &par, std::vector<double> &X,
std::vector<double> &Y)
{
for (unsigned i = 0; i < d_p; i++)
d_script->setDouble(par[i], d_param_names[i].toUtf8());

if (d_gen_function) {
double X0 = d_x[0];
double step = (d_x[d_n - 1] - X0) / (d_points - 1);
for (int i = 0; i < d_points; i++) {
X[i] = X0 + i * step;
d_script->setDouble(X[i], "x");
Y[i] = d_script->eval().toDouble();
}
} else {
for (int i = 0; i < d_points; i++) {
X[i] = d_x[i];
d_script->setDouble(X[i], "x");
Y[i] = d_script->eval().toDouble();
}
if (!d_script->setDouble(par[i], d_param_names[i].toUtf8()))
return false;

bool ok = false;
generateX(X);

for (int i = 0; i < d_points; i++) {
if (!d_script->setDouble(X[i], "x"))
return false;
auto y = d_script->eval();
if (y.isNull())
return false;
Y[i] = y.toDouble(&ok);
if (!ok)
return false;
}
return true;
}
Loading

0 comments on commit a7ea06c

Please sign in to comment.