From 938fb28e9442a89fc7cd89a339eaa5e864b67631 Mon Sep 17 00:00:00 2001 From: Anne de Jong Date: Mon, 2 Jan 2017 20:06:41 +0100 Subject: [PATCH] Solver convergence checks completed --- src/gui/solver_dialog.cpp | 114 ++++++++++++++++++++++++++++++++------ src/gui/solver_dialog.h | 15 +++-- src/gui/solver_worker.cpp | 44 +++++---------- src/gui/solver_worker.h | 6 +- src/solver/solver.h | 2 +- src/tasmet_constants.h | 2 +- 6 files changed, 125 insertions(+), 58 deletions(-) diff --git a/src/gui/solver_dialog.cpp b/src/gui/solver_dialog.cpp index 7974f37..05224e3 100644 --- a/src/gui/solver_dialog.cpp +++ b/src/gui/solver_dialog.cpp @@ -14,16 +14,18 @@ #include "tasmet_tracer.h" #include "solver.pb.h" #include +#include #include "solver_worker.h" +#include +#include SolverDialog::SolverDialog(QWidget* parent, pb::System& sys): QDialog(parent), _sys(sys), - _sparams(sys.solverparams()), _dialog(new Ui::solver_dialog()) { - + TRACE(15,"SolverDialog"); if(_dialog==nullptr) throw TaSMETBadAlloc(); @@ -44,7 +46,32 @@ SolverDialog::SolverDialog(QWidget* parent, _dialog->solvertype->addItem(QString::fromStdString(SolverType_Name((pb::SolverType) solvertype))); } + // Set the residual plot settings right + _plot = _dialog->progress_plot; + + _funer = _plot->addGraph(); + _funer->setName("Residual"); + QPen funer_pen(Qt::blue); + _funer->setPen(QPen(Qt::blue)); + + _reler = _plot->addGraph(); + _reler->setName("Solution error"); + QPen reler_pen(Qt::red); + _reler->setPen(reler_pen); + + _funtol = _plot->addGraph(); + _funtol->setName("Residual tolerance"); + QPen funtol_pen(Qt::blue); + funtol_pen.setStyle(Qt::DashLine); + _funtol->setPen(funtol_pen); + + _reltol = _plot->addGraph(); + _reltol->setName("Solution tolerance"); + QPen reltol_pen(Qt::red); + reltol_pen.setStyle(Qt::DashLine); + _reltol->setPen(reltol_pen); + _plot->xAxis->setLabel("Iteration [-]"); _plot->yAxis->setLabel("Residual [-]"); @@ -52,10 +79,13 @@ SolverDialog::SolverDialog(QWidget* parent, QSharedPointer ticker(new QCPAxisTickerLog()); _plot->yAxis->setTicker(ticker); + + _plot->legend->setVisible(true); + _plot->replot(); set(_sys.solverparams()); - + _init = false; } SolverDialog::~SolverDialog() { if(_solver_worker) @@ -63,13 +93,42 @@ SolverDialog::~SolverDialog() { } void SolverDialog::set(const pb::SolverParams& sol) { TRACE(15,"set"); + int solvertype= (int) sol.solvertype(); + _dialog->solvertype->setCurrentIndex(solvertype); - _dialog->solvertype->setCurrentIndex((int) sol.solvertype()); - _dialog->funtol->setText(QString::number(sol.funtol())); - _dialog->reltol->setText(QString::number(sol.reltol())); + d funtol = sol.funtol(); + _dialog->funtol->setText(QString::number(funtol)); + + d reltol = sol.reltol(); + _dialog->reltol->setText(QString::number(reltol)); } void SolverDialog::changed() { + if(_init) return; + _sys.mutable_solverparams()->set_funtol(_dialog->funtol->text().toDouble()); + _sys.mutable_solverparams()->set_reltol(_dialog->reltol->text().toDouble()); + _sys.mutable_solverparams()->set_solvertype((pb::SolverType) _dialog->solvertype->currentIndex()); +} +void SolverDialog::solver_progress(const SolverProgress& progress){ + + TRACE(15,"SolverDialog::solver_progress()"); + + + // VARTRACE(15,progress.fun_err); + // VARTRACE(15,progress.iteration); + d funtol = _sys.solverparams().funtol(); + d reltol = _sys.solverparams().reltol(); + + _funer->addData(progress.iteration,progress.fun_err); + _reler->addData(progress.iteration,progress.rel_err); + + _funtol->addData(progress.iteration,funtol); + _reltol->addData(progress.iteration,reltol); + + _plot->xAxis->setRange(0,progress.iteration); + _plot->yAxis->setRange(std::min(funtol,reltol)/10,1e0); + + _plot->replot(); } void SolverDialog::on_stop_clicked(){ @@ -78,12 +137,14 @@ void SolverDialog::on_stop_clicked(){ } void SolverDialog::on_solve_clicked() { TRACE(15,"on_solve_clicked"); - _dialog->solve->setEnabled(false); - _dialog->singleiteration->setEnabled(false); - _dialog->stop->setEnabled(true); + + // Disable buttons + setEnabled(false); assert(!_solver_worker); + qRegisterMetaType(); + _solver_worker = new SolverWorker(_sys); QThread* thread = new QThread; @@ -105,29 +166,46 @@ void SolverDialog::on_solve_clicked() { connect(thread, &QThread::finished, _solver_worker, &SolverWorker::deleteLater); + connect(_solver_worker, &SolverWorker::progress, + this, &SolverDialog::solver_progress); thread->start(); } void SolverDialog::on_singleiteration_clicked() { - _dialog->solve->setEnabled(false); - _dialog->singleiteration->setEnabled(false); - _dialog->stop->setEnabled(true); + +} +void SolverDialog::setEnabled(bool enabled){ + _dialog->solve->setEnabled(enabled); + _dialog->singleiteration->setEnabled(enabled); + _dialog->stop->setEnabled(!enabled); + _dialog->solvertype->setEnabled(enabled); + _dialog->reltol->setEnabled(enabled); + _dialog->funtol->setEnabled(enabled); } - -void SolverDialog::solver_stopped() { - _dialog->solve->setEnabled(true); - _dialog->singleiteration->setEnabled(true); - _dialog->stop->setEnabled(false); - +void SolverDialog::solver_stopped(bool converged) { + setEnabled(true); // stop the solver and delete it if(_solver_worker!=nullptr) { _solver_worker->solver_stop(); _solver_worker = nullptr; } + + if(converged) { + QMessageBox::information(this, + "Solution converged", + "Solution found within required tolerance"); + + } + else { + QMessageBox::information(this, + "Solver failed", + "Failed to find solution"); + + } } ////////////////////////////////////////////////////////////////////// diff --git a/src/gui/solver_dialog.h b/src/gui/solver_dialog.h index 5a44f21..fe1b4c1 100644 --- a/src/gui/solver_dialog.h +++ b/src/gui/solver_dialog.h @@ -20,16 +20,21 @@ namespace Ui { class solver_dialog; } class QCustomPlot; +class QCPGraph; class SolverWorker; +class SolverProgress; + class SolverDialog: public QDialog { Q_OBJECT pb::System& _sys; // Reference to system - pb::SolverParams _sparams; Ui::solver_dialog* _dialog; + bool _init = true; + QCustomPlot* _plot; + QCPGraph *_funer,*_reler,*_funtol,*_reltol; SolverWorker* _solver_worker = nullptr; @@ -41,12 +46,12 @@ public: ~SolverDialog(); void set(const pb::SolverParams&); - - +public slots: + void solver_progress(const SolverProgress&); private slots: // Connected to the signal from the solver thread. Reactivates the // buttons - void solver_stopped(); + void solver_stopped(bool converged); void on_solve_clicked(); void on_singleiteration_clicked(); @@ -58,7 +63,7 @@ private slots: private: // Called whenever the user changes input values void changed(); - + void setEnabled(bool); }; diff --git a/src/gui/solver_worker.cpp b/src/gui/solver_worker.cpp index 9a697f3..575c623 100644 --- a/src/gui/solver_worker.cpp +++ b/src/gui/solver_worker.cpp @@ -13,7 +13,9 @@ #include #include SolverWorker::SolverWorker(pb::System& sys): - _run(false) + _run(false), + _reltol(sys.solverparams().reltol()), + _funtol(sys.solverparams().funtol()) { } @@ -35,55 +37,35 @@ void SolverWorker::solver_start() { SolverProgress p; // For testing purposes + + SolverAction action; while(true) { TRACE(15,"Solver start virtual iteration"); SolverAction action = callback(p); - if(action == Stop) break; + if(action != Continue) break; sleep(1); p.fun_err/=10; p.rel_err/=10; p.iteration++; + } - emit solver_stopped(); + emit solver_stopped(_converged); } SolverAction SolverWorker::pg_callback(SolverProgress pg) { TRACE(15,"pg_callback"); if(!_run) return Stop; + emit progress(pg); - // QCPGraph *_funer,*_reler,*_funtol,*_reltol; - - // _funer = _plot->addGraph(); - // _reler = _plot->addGraph(); - - TRACE(15,"SolverWorker::pg_callback()"); - - // VARTRACE(15,progress.fun_err); - // VARTRACE(15,progress.iteration); - // _funer->addData(progress.iteration,progress.fun_err); - // _reler->addData(progress.iteration,progress.rel_err); - - // _plot->xAxis->setRange(0,progress.iteration); - - // _plot->replot(); - - // if(progress.done) { - // // We are done! - - // QString m = "Solver reached a converged solution."; - - // QMessageBox::information(this, - // "Solver done", - // m); - - - // } - + if(pg.fun_err <= _funtol && pg.rel_err <= _reltol) { + _converged = true; + return Stop; + } return Continue; diff --git a/src/gui/solver_worker.h b/src/gui/solver_worker.h index 9b78064..e907081 100644 --- a/src/gui/solver_worker.h +++ b/src/gui/solver_worker.h @@ -25,6 +25,8 @@ class SolverWorker: public QObject { std::atomic _run; Solver* _solver; + bool _converged = false; + d _funtol,_reltol; public: SolverWorker(pb::System& sys); @@ -36,8 +38,8 @@ public slots: signals: // This signal is emitted when the solver is stopped - void solver_stopped(); - void progress(SolverProgress); + void solver_stopped(bool converged); + void progress(const SolverProgress&); private: SolverAction pg_callback(SolverProgress pg); diff --git a/src/solver/solver.h b/src/solver/solver.h index a84cdc4..5c7e314 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -29,7 +29,7 @@ struct SolverProgress enum SolverAction{ Continue=0, - Stop = 1 + Stop=1 }; typedef std::function progress_callback; diff --git a/src/tasmet_constants.h b/src/tasmet_constants.h index 64c114e..cce9f28 100644 --- a/src/tasmet_constants.h +++ b/src/tasmet_constants.h @@ -82,7 +82,7 @@ namespace constants { const d min_funtol = 1e-16; const d default_funtol = 1e-6; const d max_funtol = 1e-1; - const us funtol_decimals = 10; + const us default_maxiter = 1000; const us min_maxiter = 1;