Solver works in GUI.

This commit is contained in:
Anne de Jong 2017-01-31 21:29:09 +01:00
parent e0018a6da4
commit 317cf07ee2
14 changed files with 331 additions and 197 deletions

View File

@ -141,8 +141,8 @@ void AddDuctDialog::accept(){
try {
// If duct can be built without exceptions, everything is OK
TaSystem sys(TaSystem::testSystem());
Duct duct (sys,0,_duct);
std::unique_ptr<TaSystem> sys(TaSystem::testSystem());
Duct duct (*sys,0,_duct);
}
catch(TaSMETError& e) {
@ -220,10 +220,10 @@ void AddDuctDialog::changed(){
PreviewShow pshow = (PreviewShow) _dialog->previewshow->currentIndex();
TaSystem sys = TaSystem::testSystem();
std::unique_ptr<TaSystem> sys(TaSystem::testSystem());
std::unique_ptr<Duct> duct;
try {
duct = std::unique_ptr<Duct>(new Duct(sys,0,_duct));
duct = std::unique_ptr<Duct>(new Duct(*sys,0,_duct));
}
catch(TaSMETError& e) {
return;

View File

@ -417,14 +417,43 @@ void TaSMETMainWindow::on_actionSolve_triggered() {
TRACE(15,"actionSolve()");
SolverDialog *d;
std::unique_ptr<TaSystem> sys;
try {
d = new SolverDialog(this,_system,*_model.mutable_sparams());
sys = std::unique_ptr<TaSystem>(new TaSystem(_model.system()));
if(_model.solution_size()>0) {
vd solution(_model.solution_size());
for(us i=0;i<_model.solution_size();i++) {
solution(i) = _model.solution(i);
}
// Throws in case the solution size does not match.
try {
sys->updateSolution(solution);
}
catch(...) {}
}
d = new SolverDialog(this,*sys.get(),*_model.mutable_sparams());
}
catch(TaSMETError &e) {
e.show_user("Solver failed to initialize");
return;
}
d->exec();
if(d->exec()) {
// On succes, we copy the solution to the model
const vd& sol = d->getSolution();
// Clear old solution
_model.clear_solution();
for(us i=0;i<sol.size();i++) {
_model.add_solution(sol(i));
}
}
// Solution is put in system, system updated from solver
// dialog. Therefore we are now probably dirty
@ -432,6 +461,28 @@ void TaSMETMainWindow::on_actionSolve_triggered() {
delete d;
}
void TaSMETMainWindow::on_actionPostprocess_model_triggered() {
try {
TaSystem sys(_model.system());
if(_model.solution_size() == 0)
throw TaSMETError("No solution found");
vd sol(_model.solution_size());
for(us i=0;i<sol.size();i++) {
sol(i) = _model.solution(i);
}
sys.updateSolution(sol);
if(_filepath.size() == 0)
throw TaSMETError("Model has not yet been saved");
sys.exportHDF5(_filepath + ".h5");
}
catch(TaSMETError &e) {
e.show_user("Postprocessing failed");
}
}
bool TaSMETMainWindow::isDirty() const {
TRACE(15,"isDirty()");
if(_filepath.size()==0) return true;
@ -452,5 +503,10 @@ void TaSMETMainWindow::on_actionAbout_triggered(){
AboutDialog(this).exec();
}
void TaSMETMainWindow::on_actionReinitialize_solution_triggered() {
_model.clear_solution();
changed();
}
//////////////////////////////////////////////////////////////////////

View File

@ -98,6 +98,9 @@ private slots:
void on_actionAbout_triggered(); // Show about dialog
void on_actionSolve_triggered(); // Solve the system
void on_actionReinitialize_solution_triggered();
void on_actionPostprocess_model_triggered();
void on_nf_valueChanged(int) {changed();}
void on_freq_textEdited() {changed();}
void on_gastype_currentIndexChanged(int) {changed();}

View File

@ -64,7 +64,7 @@
<item row="5" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>&amp;System type:</string>
<string>S&amp;ystem type:</string>
</property>
<property name="buddy">
<cstring>systemtype</cstring>
@ -151,7 +151,7 @@
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>&amp;Fundamental frequency: </string>
<string>F&amp;undamental frequency: </string>
</property>
<property name="buddy">
<cstring>freq</cstring>
@ -348,7 +348,7 @@
<x>0</x>
<y>0</y>
<width>683</width>
<height>21</height>
<height>18</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
@ -372,11 +372,11 @@
</widget>
<widget class="QMenu" name="menuSolver">
<property name="title">
<string>Solver</string>
<string>So&amp;lver</string>
</property>
<addaction name="actionSolve"/>
<addaction name="actionReinitialize_solver"/>
<addaction name="actionPosprocess_model"/>
<addaction name="actionReinitialize_solution"/>
<addaction name="actionPostprocess_model"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuSolver"/>
@ -446,17 +446,17 @@
</action>
<action name="actionSolve">
<property name="text">
<string>Solve...</string>
<string>&amp;Solve...</string>
</property>
</action>
<action name="actionReinitialize_solver">
<action name="actionReinitialize_solution">
<property name="text">
<string>Reinitialize solver</string>
<string>&amp;Reinitialize solution</string>
</property>
</action>
<action name="actionPosprocess_model">
<action name="actionPostprocess_model">
<property name="text">
<string>Posprocess model...</string>
<string>Create postprocessing file</string>
</property>
</action>
</widget>

View File

@ -22,7 +22,7 @@
#include <qcustomplot.h>
SolverDialog::SolverDialog(QWidget* parent,
pb::System& sys,
const GradientNonlinearSystem& sys,
pb::SolverParams& sparams):
QDialog(parent),
_sys(sys),
@ -125,8 +125,13 @@ void SolverDialog::solver_progress(const SolverProgress& progress){
TRACE(15,"SolverDialog::solver_progress()");
// VARTRACE(15,progress.fun_err);
// VARTRACE(15,progress.iteration);
if(progress.error) {
QMessageBox::warning(this,
"Solver error",
QString::fromStdString(progress.err_msg));
}
d funtol = _sparams.funtol();
d reltol = _sparams.reltol();
@ -159,17 +164,18 @@ void SolverDialog::on_solve_clicked() {
_funtol->setData(empty,empty);
_reltol->setData(empty,empty);
assert(!_solver_worker);
qRegisterMetaType<SolverProgress>();
_solver_worker = new SolverWorker(_sys,_sparams);
QThread* thread = new QThread;
if(!_solver_worker || !thread) throw TaSMETBadAlloc();
// Move the _solver_worker to its own thread
_solver_worker->moveToThread(thread);
connect(thread, &QThread::started,
_solver_worker, &SolverWorker::solver_start);
@ -192,12 +198,9 @@ void SolverDialog::on_solve_clicked() {
}
void SolverDialog::on_singleiteration_clicked() {
}
void SolverDialog::setEnabled(bool enabled){
_dialog->solve->setEnabled(enabled);
_dialog->singleiteration->setEnabled(enabled);
_dialog->stop->setEnabled(!enabled);
_dialog->solvertype->setEnabled(enabled);
@ -210,6 +213,9 @@ void SolverDialog::solver_stopped(bool converged) {
// stop the solver and delete it
if(_solver_worker!=nullptr) {
_solver_worker->solver_stop();
if(converged) {
_solution = _solver_worker->getSolution();
}
_solver_worker = nullptr;
}

View File

@ -10,7 +10,7 @@
#define SOLVER_DIALOG_H
#include <QDialog>
#include <QThread>
#include "tasmet_types.h"
#include "solver.pb.h"
namespace pb {
@ -20,7 +20,7 @@ namespace pb {
namespace Ui {
class solver_dialog;
}
class GradientNonlinearSystem;
class QCustomPlot;
class QCPGraph;
class SolverWorker;
@ -29,7 +29,6 @@ class SolverProgress;
class SolverDialog: public QDialog {
Q_OBJECT
pb::System& _sys; // Reference to system
pb::SolverParams& _sparams;
Ui::solver_dialog* _dialog;
@ -41,14 +40,21 @@ class SolverDialog: public QDialog {
SolverWorker* _solver_worker = nullptr;
const GradientNonlinearSystem& _sys;
/// Place where the final solution will be stored
vd _solution;
public:
SolverDialog(QWidget* parent,
pb::System& sys,
const GradientNonlinearSystem& sys,
pb::SolverParams& sparams);
~SolverDialog();
const vd& getSolution() const { return _solution;};
public slots:
void solver_progress(const SolverProgress&);
private slots:
@ -57,17 +63,23 @@ private slots:
void solver_stopped(bool converged);
void on_solve_clicked();
void on_singleiteration_clicked();
void on_stop_clicked();
void on_funtol_textChanged() { changed();}
void on_reltol_textChanged() { changed();}
void on_solvertype_currentIndexChanged(int) { changed();}
void on_buttons_accepted() {accept();}
void on_buttons_rejected() {reject();}
private:
// Called whenever the user changes input values
void changed();
void setEnabled(bool);
void set(const pb::SolverParams&);
};

View File

@ -13,143 +13,149 @@
<property name="windowTitle">
<string>TaSMET Solver</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QGroupBox" name="solversettings">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Solver Settings</string>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="3" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Solver type</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="solvertype"/>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="reltol">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Solution tolerance:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Residual tolerance:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="funtol">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="solve_gb">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Solve!</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPushButton" name="solve">
<property name="text">
<string>Solve</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="stop">
<property name="text">
<string>Stop</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="singleiteration">
<property name="text">
<string>Single iteration</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="progress_gb">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Progress</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<widget class="QWidget" name="widget" native="true">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QCustomPlot" name="progress_plot" native="true"/>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QGroupBox" name="solversettings">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Solver Settings</string>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="3" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Solver type</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="solvertype"/>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="reltol">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Solution tolerance:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Residual tolerance:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="funtol">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="solve_gb">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Solve!</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPushButton" name="solve">
<property name="text">
<string>Solve</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="stop">
<property name="text">
<string>Stop</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="progress_gb">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Progress</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QCustomPlot" name="progress_plot" native="true"/>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttons">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Save</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>

View File

@ -9,22 +9,38 @@
#include "solver_worker.h"
#include <functional>
#include "tasmet_tracer.h"
#include "solver.h"
#include "system.pb.h"
#include "solver.pb.h"
#include <QThread>
// Solvers available
#include "newton_raphson.h"
#include "tasystem.h"
SolverWorker::SolverWorker(const pb::System& sys,const pb::SolverParams& sparams):
SolverWorker::SolverWorker(const GradientNonlinearSystem& sys,
const pb::SolverParams& sparams):
_run(false),
_reltol(sparams.reltol()),
_funtol(sparams.funtol())
_funtol(sparams.funtol()),
_reltol(sparams.reltol())
{
TRACE(15,"SolverWorker");
switch (sparams.solvertype()) {
case pb::NewtonRaphson: {
_solver = new NewtonRaphson(sys);
break;
}
default:
tasmet_assert(false,"Not implemented solver type");
break;
}
}
SolverWorker::~SolverWorker(){
TRACE(15,"~SolverWorker");
if(_solver!=nullptr) delete _solver;
}
void SolverWorker::solver_stop() {
_run = false;
@ -39,23 +55,10 @@ void SolverWorker::solver_start() {
progress_callback callback = std::bind(&SolverWorker::pg_callback,
this,_1);
SolverProgress p;
// For testing purposes
SolverAction action;
while(true) {
TRACE(15,"Solver start virtual iteration");
tasmet_assert(_solver!=nullptr,"Solver not initialized");
SolverAction action = callback(p);
if(action != Continue) break;
sleep(1);
p.fun_err/=10;
p.rel_err/=10;
p.iteration++;
}
_solver->start(&callback);
emit solver_stopped(_converged);
}
@ -66,6 +69,10 @@ SolverAction SolverWorker::pg_callback(SolverProgress pg) {
emit progress(pg);
if(pg.error) {
_converged = false;
return Stop;
}
if(pg.fun_err <= _funtol && pg.rel_err <= _reltol) {
_converged = true;
return Stop;

View File

@ -19,18 +19,28 @@ namespace pb{
class SolverParams;
}
class TaSystem;
Q_DECLARE_METATYPE(SolverProgress);
class SolverWorker: public QObject {
Q_OBJECT
std::atomic<bool> _run;
Solver<GradientNonlinearSystem,vd>* _solver;
Solver<GradientNonlinearSystem,vd>* _solver = nullptr;
bool _converged = false;
d _funtol,_reltol;
public:
SolverWorker(const pb::System& sys,const pb::SolverParams& sparams);
SolverWorker(const GradientNonlinearSystem& sys,
const pb::SolverParams& sparams);
~SolverWorker();
vd getSolution() const { return _solver ? _solver->getSolution() : zeros<vd>(0);}
/**
* Stop the solver. Called when the user presses the `stop' button
*/
void solver_stop();
public slots:

View File

@ -40,7 +40,7 @@ int main(int argc, char *argv[]) {
// This can be used to store files in the application. Very useful
// when our application grows bigger
// Q_INIT_RESOURCE(application);
INITTRACE(15);
INITTRACE(16);
QApplication app(argc, argv);

View File

@ -9,7 +9,7 @@
#include "newton_raphson.h"
#include "tasmet_tracer.h"
#define DEBUG_TASMET_SYSTEM
// #define DEBUG_TASMET_SYSTEM
void NewtonRaphson::start_implementation(GradientNonlinearSystem& system,
progress_callback* callback) {
@ -48,7 +48,15 @@ void NewtonRaphson::start_implementation(GradientNonlinearSystem& system,
#endif // DEBUG_TASMET_SYSTEM
TRACE(15,"Solving system of eqs");
dx = -1*_dampfac*arma::spsolve(resjac.jacobian,resjac.residual,"superlu");
try {
dx = -1*_dampfac*arma::spsolve(resjac.jacobian,resjac.residual,"superlu");
}
catch(...) {
progress.error = true;
progress.err_msg = "Failed to solve linear system of equations";
(*callback)(progress);
return;
}
TRACE(15,"Solving system of eqs done");
progress.rel_err = norm(dx);

View File

@ -32,6 +32,8 @@ struct SolverProgress
Solver stops as an action of
itself. Probably due to an internal
error. */
string err_msg;
};

View File

@ -71,8 +71,7 @@ TaSystem::TaSystem(const pb::System& sys):
}
TaSystem::TaSystem(const TaSystem& o):
GlobalConf(o), // Share a ptr to the Global conf
_gas(o._gas->copy()),
_solution(o._solution)
_gas(o._gas->copy())
{
TRACE(25,"TaSystem::TaSystem(TaSystem&) copy");
@ -84,7 +83,11 @@ TaSystem::TaSystem(const TaSystem& o):
if(!seg.second) throw TaSMETBadAlloc();
}
initSolRes();
initSolRes(); // This empties the
// solution. Therefore we copy it
// after this phase.
_solution = o._solution;
}
void TaSystem::initSolRes() {
@ -272,7 +275,6 @@ void TaSystem::residualJac(ResidualJac& resjac) const {
}
}
@ -295,6 +297,7 @@ void TaSystem::residualJac(ResidualJac& resjac) const {
_residual(arbitrateMassEq)=mass - _mass;
}
// Store the Jacobian and the residual
resjac.jacobian = sdmat(triplets);
resjac.residual = _residual;
@ -302,9 +305,20 @@ void TaSystem::residualJac(ResidualJac& resjac) const {
vd TaSystem::getSolution() const {
return _solution;
}
void TaSystem::updateSolution(const vd& solution) {
if(_solution.size() == solution.size()) {
_solution = solution;
}
else {
throw TaSMETError("Solution vector size does not match.");
}
}
const SegPositionMapper& TaSystem::getSolution(const us seg_id) const {
return _solution_dofs.at(seg_id);
}
vus TaSystem::getNDofs() const {
TRACE(0,"TaSystem::getNDofs()");
vus Ndofs(_segs.size());
@ -481,7 +495,7 @@ void TaSystem::exportHDF5(const string& filename) const {
seg_.second->exportHDF5(grp_id);
// Close the group
H5Gclose(grp_id);
}

View File

@ -64,14 +64,24 @@ private:
*
*/
void initSolRes();
public:
TaSystem(const TaSystem& o);
public:
TaSystem(const pb::System&);
static TaSystem testSystem() {
return TaSystem(pb::System::default_instance());
/**
* Returns an empty TaSystem with default GlobalConf
* parameters. The caller of this function owns the object and is
* responsible for its destruction.
*
*
* @return the TaSystem instance pointer.
*/
static TaSystem* testSystem() {
return new TaSystem(pb::System::default_instance());
}
const Gas& gas() const {return *_gas;}
@ -96,7 +106,7 @@ public:
// Obtain the solution vector for the Segment with given id
const SegPositionMapper& getSolution(const us seg_id) const;
virtual void updateSolution(const vd& sol) {_solution = sol; } // Update the solution
virtual void updateSolution(const vd& sol);
// Change Nf in the system, while keeping the results.
void updateNf(us);