Updated all GUI stuff to new protobuf config of model containing a system, solver and solution

This commit is contained in:
Anne de Jong 2017-01-05 16:25:16 +01:00
parent c4ffca4640
commit e255b9e2c9
16 changed files with 650 additions and 635 deletions

View File

@ -1,75 +1,75 @@
#================ #================
# The TaSMET code # The TaSMET code
#================ #================
include_directories( include_directories(
${PYTHON_INCLUDE_PATH} ${PYTHON_INCLUDE_PATH}
${ARMADILLO_INCLUDE_DIRS} ${ARMADILLO_INCLUDE_DIRS}
. .
protobuf protobuf
duct duct
ductbc ductbc
# duct/cell # duct/cell
# duct/connectors # duct/connectors
# duct/eq # duct/eq
# duct/geom # duct/geom
# duct/geom/grid # duct/geom/grid
# duct/drag # duct/drag
# duct/heat # duct/heat
# mech # mech
# python # python
# seg # seg
# sol # sol
sys sys
solver solver
# var # var
# volume # volume
) )
add_library(tasmet_src add_library(tasmet_src
tasmet_tracer.cpp tasmet_tracer.cpp
tasmet_exception.cpp tasmet_exception.cpp
tasmet_assert.cpp tasmet_assert.cpp
tasmet_pyeval.cpp tasmet_pyeval.cpp
protobuf/message_tools.cpp protobuf/message_tools.cpp
duct/grid.cpp duct/grid.cpp
duct/geom.cpp duct/geom.cpp
duct/duct.cpp duct/duct.cpp
ductbc/ductbc.cpp ductbc/ductbc.cpp
ductbc/pressurebc.cpp ductbc/pressurebc.cpp
ductbc/adiabaticwall.cpp ductbc/adiabaticwall.cpp
funcs/bessel.cpp funcs/bessel.cpp
funcs/cbessj.cpp funcs/cbessj.cpp
funcs/rottfuncs.cpp funcs/rottfuncs.cpp
funcs/skewsine.cpp funcs/skewsine.cpp
funcs/sph_j.cpp funcs/sph_j.cpp
solver/solver.cpp solver/solver.cpp
solver/system.cpp solver/system.cpp
solver/newton_raphson.cpp solver/newton_raphson.cpp
solver/brent.cpp solver/brent.cpp
material/gas.cpp material/gas.cpp
material/air.cpp material/air.cpp
material/helium.cpp material/helium.cpp
material/nitrogen.cpp material/nitrogen.cpp
material/solid.cpp material/solid.cpp
material/adiabatictemp.cpp material/adiabatictemp.cpp
# sys/enginesystem.cpp # sys/enginesystem.cpp
sys/globalconf.cpp sys/globalconf.cpp
sys/tasmet_variable.cpp sys/tasmet_variable.cpp
sys/jaccol.cpp sys/jaccol.cpp
sys/jacobian.cpp sys/jacobian.cpp
sys/jacrow.cpp sys/jacrow.cpp
sys/tasystem.cpp sys/tasystem.cpp
sys/triplets.cpp sys/triplets.cpp
) )
add_subdirectory(gui) add_subdirectory(gui)
add_subdirectory(protobuf) add_subdirectory(protobuf)
target_link_libraries(tasmet_src Qt5::Widgets) target_link_libraries(tasmet_src Qt5::Widgets)

View File

@ -9,11 +9,8 @@
#ifndef PRESSUREBC_H #ifndef PRESSUREBC_H
#define PRESSUREBC_H #define PRESSUREBC_H
#include "segment.h" #include "segment.h"
#include "ductbc.pb.h"
class TaSystem; class TaSystem;
namespace pb{
class DuctBc;
}
class Variable; class Variable;
class PressureBc: public Segment { class PressureBc: public Segment {

View File

@ -54,8 +54,8 @@ namespace {
TaSMETMainWindow::TaSMETMainWindow(): TaSMETMainWindow::TaSMETMainWindow():
_window(new Ui::MainWindow()), _window(new Ui::MainWindow()),
_model(pb::Model::default_instance()) _model(pb::Model::default_instance()),
_system(*_model.mutable_sytem()) _system(*_model.mutable_system())
{ {
if(!_window) throw TaSMETBadAlloc(); if(!_window) throw TaSMETBadAlloc();
@ -224,7 +224,7 @@ void TaSMETMainWindow::changed() {
windowtitle += QString::fromStdString(_filepath); windowtitle += QString::fromStdString(_filepath);
} }
else { else {
windowtitle += default_system_name; windowtitle += default_model_name;
} }
setWindowTitle(windowtitle); setWindowTitle(windowtitle);
@ -254,10 +254,11 @@ void TaSMETMainWindow::changed() {
} }
void TaSMETMainWindow::set(const pb::System& sys) { void TaSMETMainWindow::set(const pb::Model& model) {
TRACE(15,"set()"); TRACE(15,"set()");
_init = true; _init = true;
const pb::System& sys = model.system();
_window->nf->setValue(sys.nf()); _window->nf->setValue(sys.nf());
_window->freq->setText(QString::number(sys.freq())); _window->freq->setText(QString::number(sys.freq()));
_window->p0->setText(QString::number(sys.p0())); _window->p0->setText(QString::number(sys.p0()));
@ -265,7 +266,8 @@ void TaSMETMainWindow::set(const pb::System& sys) {
_window->systemtype->setCurrentIndex((int) sys.systemtype()); _window->systemtype->setCurrentIndex((int) sys.systemtype());
_window->gastype->setCurrentIndex((int) sys.gastype()); _window->gastype->setCurrentIndex((int) sys.gastype());
_system = sys; _model = model;
_system = *_model.mutable_system();
_init = false; _init = false;
changed(); changed();
@ -406,7 +408,7 @@ void TaSMETMainWindow::on_actionSolve_triggered() {
SolverDialog *d; SolverDialog *d;
try { try {
d = new SolverDialog(this,_system); d = new SolverDialog(this,_system,*_model.mutable_sparams());
} }
catch(TaSMETError &e) { catch(TaSMETError &e) {
e.show_user("Solver failed to initialize"); e.show_user("Solver failed to initialize");
@ -425,8 +427,8 @@ bool TaSMETMainWindow::isDirty() const {
if(_filepath.size()==0) return true; if(_filepath.size()==0) return true;
try { try {
pb::System filesys = loadSystem(_filepath); pb::Model filemodel = loadMessage<pb::Model>(_filepath);
bool dirty = !compareSys(filesys,_system); bool dirty = !compareMessage<pb::Model>(filemodel,_model);
VARTRACE(15,dirty); VARTRACE(15,dirty);
return dirty; return dirty;
} }

View File

@ -9,6 +9,8 @@
#include "solver_dialog.h" #include "solver_dialog.h"
#include "ui_solver_dialog.h" #include "ui_solver_dialog.h"
#include "system.pb.h" #include "system.pb.h"
#include "solver.pb.h"
#include "tasmet_exception.h" #include "tasmet_exception.h"
#include "tasmet_constants.h" #include "tasmet_constants.h"
#include "tasmet_tracer.h" #include "tasmet_tracer.h"
@ -20,9 +22,11 @@
#include <qcustomplot.h> #include <qcustomplot.h>
SolverDialog::SolverDialog(QWidget* parent, SolverDialog::SolverDialog(QWidget* parent,
pb::System& sys): pb::System& sys,
pb::SolverParams& sparams):
QDialog(parent), QDialog(parent),
_sys(sys), _sys(sys),
_sparams(sparams),
_dialog(new Ui::solver_dialog()) _dialog(new Ui::solver_dialog())
{ {
@ -85,7 +89,7 @@ SolverDialog::SolverDialog(QWidget* parent,
_plot->legend->setVisible(true); _plot->legend->setVisible(true);
_plot->replot(); _plot->replot();
set(_sys.solverparams()); set(_sparams);
setEnabled(true); setEnabled(true);
@ -113,9 +117,9 @@ void SolverDialog::set(const pb::SolverParams& sol) {
void SolverDialog::changed() { void SolverDialog::changed() {
TRACE(15,"changed"); TRACE(15,"changed");
if(_init) return; if(_init) return;
_sys.mutable_solverparams()->set_funtol(_dialog->funtol->text().toDouble()); _sparams.set_funtol(_dialog->funtol->text().toDouble());
_sys.mutable_solverparams()->set_reltol(_dialog->reltol->text().toDouble()); _sparams.set_reltol(_dialog->reltol->text().toDouble());
_sys.mutable_solverparams()->set_solvertype((pb::SolverType) _dialog->solvertype->currentIndex()); _sparams.set_solvertype((pb::SolverType) _dialog->solvertype->currentIndex());
} }
void SolverDialog::solver_progress(const SolverProgress& progress){ void SolverDialog::solver_progress(const SolverProgress& progress){
@ -123,8 +127,8 @@ void SolverDialog::solver_progress(const SolverProgress& progress){
// VARTRACE(15,progress.fun_err); // VARTRACE(15,progress.fun_err);
// VARTRACE(15,progress.iteration); // VARTRACE(15,progress.iteration);
d funtol = _sys.solverparams().funtol(); d funtol = _sparams.funtol();
d reltol = _sys.solverparams().reltol(); d reltol = _sparams.reltol();
_funer->addData(progress.iteration,progress.fun_err); _funer->addData(progress.iteration,progress.fun_err);
_reler->addData(progress.iteration,progress.rel_err); _reler->addData(progress.iteration,progress.rel_err);
@ -160,7 +164,7 @@ void SolverDialog::on_solve_clicked() {
qRegisterMetaType<SolverProgress>(); qRegisterMetaType<SolverProgress>();
_solver_worker = new SolverWorker(_sys); _solver_worker = new SolverWorker(_sys,_sparams);
QThread* thread = new QThread; QThread* thread = new QThread;
_solver_worker->moveToThread(thread); _solver_worker->moveToThread(thread);

View File

@ -15,10 +15,12 @@
namespace pb { namespace pb {
class System; class System;
class SolverParams;
} }
namespace Ui { namespace Ui {
class solver_dialog; class solver_dialog;
} }
class QCustomPlot; class QCustomPlot;
class QCPGraph; class QCPGraph;
class SolverWorker; class SolverWorker;
@ -28,6 +30,7 @@ class SolverDialog: public QDialog {
Q_OBJECT Q_OBJECT
pb::System& _sys; // Reference to system pb::System& _sys; // Reference to system
pb::SolverParams& _sparams;
Ui::solver_dialog* _dialog; Ui::solver_dialog* _dialog;
@ -41,11 +44,11 @@ class SolverDialog: public QDialog {
public: public:
SolverDialog(QWidget* parent, SolverDialog(QWidget* parent,
pb::System& sys); pb::System& sys,
pb::SolverParams& sparams);
~SolverDialog(); ~SolverDialog();
void set(const pb::SolverParams&);
public slots: public slots:
void solver_progress(const SolverProgress&); void solver_progress(const SolverProgress&);
private slots: private slots:
@ -64,6 +67,7 @@ private:
// Called whenever the user changes input values // Called whenever the user changes input values
void changed(); void changed();
void setEnabled(bool); void setEnabled(bool);
void set(const pb::SolverParams&);
}; };

View File

@ -9,13 +9,17 @@
#include "solver_worker.h" #include "solver_worker.h"
#include <functional> #include <functional>
#include "tasmet_tracer.h" #include "tasmet_tracer.h"
#include "system.pb.h" #include "system.pb.h"
#include "solver.pb.h"
#include <QThread> #include <QThread>
#include <qcustomplot.h>
SolverWorker::SolverWorker(pb::System& sys):
SolverWorker::SolverWorker(const pb::System& sys,const pb::SolverParams& sparams):
_run(false), _run(false),
_reltol(sys.solverparams().reltol()), _reltol(sparams.reltol()),
_funtol(sys.solverparams().funtol()) _funtol(sparams.funtol())
{ {
} }

View File

@ -16,6 +16,7 @@
#include <QObject> #include <QObject>
namespace pb{ namespace pb{
class System; class System;
class SolverParams;
} }
Q_DECLARE_METATYPE(SolverProgress); Q_DECLARE_METATYPE(SolverProgress);
@ -28,8 +29,7 @@ class SolverWorker: public QObject {
bool _converged = false; bool _converged = false;
d _funtol,_reltol; d _funtol,_reltol;
public: public:
SolverWorker(const pb::System& sys,const pb::SolverParams& sparams);
SolverWorker(pb::System& sys);
~SolverWorker(); ~SolverWorker();
void solver_stop(); void solver_stop();

View File

@ -1,85 +1,85 @@
// main.cpp // main.cpp
// //
// last-edit-by: J.A. de Jong // last-edit-by: J.A. de Jong
// //
// Description: // Description:
// Main program to run // Main program to run
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
#include <QApplication> #include <QApplication>
#include <QCommandLineParser> #include <QCommandLineParser>
#include <QCommandLineOption> #include <QCommandLineOption>
// For using python from within Qt // For using python from within Qt
#include <PythonQt.h> #include <PythonQt.h>
#include "tasmet_config.h" #include "tasmet_config.h"
#include "tasmet_tracer.h" #include "tasmet_tracer.h"
#include "gui/mainwindow.h" #include "gui/mainwindow.h"
#include <signal.h> #include <signal.h>
#include <unistd.h> #include <unistd.h>
void catchUnixSignals(const std::vector<int>& quitSignals, void catchUnixSignals(const std::vector<int>& quitSignals,
const std::vector<int>& ignoreSignals = std::vector<int>()) { const std::vector<int>& ignoreSignals = std::vector<int>()) {
auto handler = [](int sig) ->void { auto handler = [](int sig) ->void {
printf("\nquit the application (user request signal = %d).\n", sig); printf("\nquit the application (user request signal = %d).\n", sig);
QCoreApplication::quit(); QCoreApplication::quit();
}; };
// all these signals will be ignored. // all these signals will be ignored.
for ( int sig : ignoreSignals ) for ( int sig : ignoreSignals )
signal(sig, SIG_IGN); signal(sig, SIG_IGN);
// each of these signals calls the handler (quits the QCoreApplication). // each of these signals calls the handler (quits the QCoreApplication).
for ( int sig : quitSignals ) for ( int sig : quitSignals )
signal(sig, handler); signal(sig, handler);
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
// This can be used to store files in the application. Very useful // This can be used to store files in the application. Very useful
// when our application grows bigger // when our application grows bigger
// Q_INIT_RESOURCE(application); // Q_INIT_RESOURCE(application);
INITTRACE(15); INITTRACE(15);
// Initialize PythonQt // Initialize PythonQt
// PythonQt::init(PythonQt::IgnoreSiteModule | PythonQt::RedirectStdOut); // PythonQt::init(PythonQt::IgnoreSiteModule | PythonQt::RedirectStdOut);
PythonQt::init(); PythonQt::init();
PythonQt* pyqt = PythonQt::self(); PythonQt* pyqt = PythonQt::self();
PythonQtObjectPtr context = pyqt->getMainModule(); PythonQtObjectPtr context = pyqt->getMainModule();
QVariant rv = context.evalScript("from math import *\n"); QVariant rv = context.evalScript("from math import *\n");
if(pyqt->hadError()) { if(pyqt->hadError()) {
return -1; return -1;
} }
QApplication app(argc, argv); QApplication app(argc, argv);
catchUnixSignals({SIGQUIT, SIGINT, SIGTERM, SIGHUP}); catchUnixSignals({SIGQUIT, SIGINT, SIGTERM, SIGHUP});
// QCoreApplication::setOrganizationName("QtProject"); // QCoreApplication::setOrganizationName("QtProject");
QCoreApplication::setApplicationName(appname); QCoreApplication::setApplicationName(appname);
QCoreApplication::setApplicationVersion(appversion); QCoreApplication::setApplicationVersion(appversion);
// QCommandLineParser parser; // QCommandLineParser parser;
// parser.setApplicationDescription(QCoreApplication::applicationName()); // parser.setApplicationDescription(QCoreApplication::applicationName());
// parser.addHelpOption(); // parser.addHelpOption();
// parser.addVersionOption(); // parser.addVersionOption();
// parser.addPositionalArgument("file", "The file to open."); // parser.addPositionalArgument("file", "The file to open.");
// parser.process(app); // parser.process(app);
// if (!parser.positionalArguments().isEmpty()) // if (!parser.positionalArguments().isEmpty())
// mainWin.loadFile(parser.positionalArguments().first()); // mainWin.loadFile(parser.positionalArguments().first());
TaSMETMainWindow win; TaSMETMainWindow win;
win.show(); win.show();
return app.exec(); return app.exec();
} }
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////

View File

@ -7,7 +7,6 @@
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
#include "message_tools.h" #include "message_tools.h"
#include <fstream> #include <fstream>
#include <google/protobuf/text_format.h>
#include "tasmet_types.h" #include "tasmet_types.h"
#include "tasmet_io.h" #include "tasmet_io.h"
#include "tasmet_exception.h" #include "tasmet_exception.h"
@ -77,9 +76,14 @@ bool compareMessage(const T& s1,const T& s2) {
return (s1.SerializeAsString()==s2.SerializeAsString()); return (s1.SerializeAsString()==s2.SerializeAsString());
} }
template <> // Explicit instantiation for pb::Model
template
bool compareMessage<pb::Model>(const pb::Model& s1,const pb::Model& s2); bool compareMessage<pb::Model>(const pb::Model& s1,const pb::Model& s2);
template <>
template
pb::Model loadMessage(const string& filepath); pb::Model loadMessage(const string& filepath);
template
void saveMessage<pb::Model>(const string& filepath,const pb::Model& model);
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////

View File

@ -21,7 +21,7 @@ void saveMessage(const string& filepath,const T& sys);
// Returns true when the two systems are equal // Returns true when the two systems are equal
template<typename T> template<typename T>
bool compareSys(const T& s1,const T& s2); bool compareMessage(const T& s1,const T& s2);

View File

@ -1,97 +1,97 @@
// bracket_lin.h // bracket_lin.h
// //
// Author: J.A. de Jong // Author: J.A. de Jong
// //
// Description: Bracket a function's root given a guess value, returns // Description: Bracket a function's root given a guess value, returns
// another guess where the solution has the opposite sign // another guess where the solution has the opposite sign
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
#pragma once #pragma once
#ifndef BRACKET_LIN_H #ifndef BRACKET_LIN_H
#define BRACKET_LIN_H #define BRACKET_LIN_H
#include "system.h" #include "system.h"
#include "tasmet_tracer.h" #include "tasmet_tracer.h"
#include <limits> #include <limits>
inline int sign(d& x){ inline int sign(d& x){
return x < 0? -1: 1; return x < 0? -1: 1;
} }
const us maxiter = 100; const us maxiter = 100;
inline std::pair<d,d> bracket_root(NoGradientNonlinearSystem<d>& sys,const d guess) { inline std::pair<d,d> bracket_root(NoGradientNonlinearSystem<d>& sys,const d guess) {
TRACE(10,"bracket_root()"); TRACE(10,"bracket_root()");
d xa = guess; d xa = guess;
d fa = sys.residual(xa); d fa = sys.residual(xa);
if(fa == 0) { if(fa == 0) {
// Guess was exactly right // Guess was exactly right
return std::make_pair(xa,xa); return std::make_pair(xa,xa);
} }
d fb = fa; d fb = fa;
// We add here a small amount, such that, in case the first guess // We add here a small amount, such that, in case the first guess
// is 0, we // is 0, we
d xb = xa+std::numeric_limits<d>::epsilon(); d xb = xa+std::numeric_limits<d>::epsilon();
d factor = 1.001; d factor = 1.001;
d delta = xa/10 + std::numeric_limits<d>::epsilon(); d delta = xa/10 + std::numeric_limits<d>::epsilon();
us iter = 0; us iter = 0;
int step = 64; int step = 64;
bool switched = false; bool switched = false;
while (iter < maxiter) { while (iter < maxiter) {
VARTRACE(5,xb); VARTRACE(5,xb);
xb += delta*factor; xb += delta*factor;
fb = sys.residual(xb); fb = sys.residual(xb);
if(sign(fa) != sign(fb)) { if(sign(fa) != sign(fb)) {
// Found it! // Found it!
VARTRACE(5,xa); VARTRACE(5,xa);
VARTRACE(5,xb); VARTRACE(5,xb);
VARTRACE(5,fa); VARTRACE(5,fa);
VARTRACE(5,fb); VARTRACE(5,fb);
return std::make_pair(xa,xb); return std::make_pair(xa,xb);
} }
if (abs(fb) < abs(fa)){ if (abs(fb) < abs(fa)){
// We found a point which is closer to the real root // We found a point which is closer to the real root
xa = xb; xa = xb;
fa = fb; fa = fb;
} }
else if(!switched) { else if(!switched) {
TRACE(5,"Switching search direction"); TRACE(5,"Switching search direction");
switched = true; switched = true;
// We searched in the wrong direction // We searched in the wrong direction
factor*=-1; factor*=-1;
} }
// Heuristic: normally it's best not to increase the step sizes as we'll just end up // Heuristic: normally it's best not to increase the step sizes as we'll just end up
// with a really wide range to search for the root. However, if the initial guess was *really* // with a really wide range to search for the root. However, if the initial guess was *really*
// bad then we need to speed up the search otherwise we'll take forever if we're orders of // bad then we need to speed up the search otherwise we'll take forever if we're orders of
// magnitude out. This happens most often if the guess is a small value (say 1) and the result // magnitude out. This happens most often if the guess is a small value (say 1) and the result
// we're looking for is close to std::numeric_limits<T>::min(). // we're looking for is close to std::numeric_limits<T>::min().
// //
if((10000 - iter) % step == 0) { if((10000 - iter) % step == 0) {
factor *=2; factor *=2;
if(step > 1) step/=2; if(step > 1) step/=2;
} }
iter++; iter++;
} }
WARN("Failed to bracket root"); WARN("Failed to bracket root");
return std::make_pair(xa,xb); return std::make_pair(xa,xb);
} }
#endif // BRACKET_LIN_H #endif // BRACKET_LIN_H
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////

View File

@ -1,180 +1,180 @@
// brent.cpp // brent.cpp
// //
// last-edit-by: J.A. de Jong // last-edit-by: J.A. de Jong
// //
// Description: // Description:
// Brent's root finding algorithm as implemented from Wikipedia: // Brent's root finding algorithm as implemented from Wikipedia:
// https://en.wikipedia.org/wiki/Brent's_method // https://en.wikipedia.org/wiki/Brent's_method
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
#define TRACERPLUS (10) #define TRACERPLUS (10)
#include "brent.h" #include "brent.h"
#include "tasmet_tracer.h" #include "tasmet_tracer.h"
#include "tasmet_exception.h" #include "tasmet_exception.h"
#include <limits> #include <limits>
#include "tasmet_constants.h" #include "tasmet_constants.h"
#include <algorithm> // std::swap #include <algorithm> // std::swap
#include "bracket_root.h" #include "bracket_root.h"
const d eps = std::numeric_limits<d>::epsilon(); const d eps = std::numeric_limits<d>::epsilon();
Brent::Brent(const NoGradientNonlinearSystem<d>& sys,d reltol): Brent::Brent(const NoGradientNonlinearSystem<d>& sys,d reltol):
Solver(sys), Solver(sys),
_reltol(reltol) _reltol(reltol)
{ {
TRACE(15,"Brent::Brent"); TRACE(15,"Brent::Brent");
#ifdef TASMET_DEBUG #ifdef TASMET_DEBUG
bool ok=true; bool ok=true;
ok&=(reltol >= eps); ok&=(reltol >= eps);
if(!ok){ if(!ok){
throw TaSMETError("Brent: invalid arguments"); throw TaSMETError("Brent: invalid arguments");
} }
#endif #endif
} }
namespace { namespace {
inline bool is_between(d x,d a,d b) { inline bool is_between(d x,d a,d b) {
const d& mi = std::min(a,b); const d& mi = std::min(a,b);
const d& ma = std::max(a,b); const d& ma = std::max(a,b);
return ((mi <= x) && (x <=ma)); return ((mi <= x) && (x <=ma));
} }
} }
void Brent::start_implementation(NoGradientNonlinearSystem<d>& system, void Brent::start_implementation(NoGradientNonlinearSystem<d>& system,
progress_callback* callback) { progress_callback* callback) {
TRACE(15,"Brent::start_implementation"); TRACE(15,"Brent::start_implementation");
us niter = 0; us niter = 0;
d a = system.getSolution(); d a = system.getSolution();
std::pair<d,d> brackets = bracket_root(system,a); std::pair<d,d> brackets = bracket_root(system,a);
a = brackets.first; a = brackets.first;
d b = brackets.second; d b = brackets.second;
d fa = system.residual(a); d fa = system.residual(a);
if((fa) == 0) { if((fa) == 0) {
TRACE(15,"Found root during bracketing"); TRACE(15,"Found root during bracketing");
return; return;
} }
d fb = system.residual(b); d fb = system.residual(b);
if((fb) == 0) { if((fb) == 0) {
TRACE(15,"Found root during bracketing"); TRACE(15,"Found root during bracketing");
return; return;
} }
d c = a; d c = a;
d fc = fa; d fc = fa;
d s; // Test point d s; // Test point
d fs; // Function at test point d fs; // Function at test point
d t,u,v; d t,u,v;
d d_; d d_;
if(fa*fb>=0){ if(fa*fb>=0){
WARN("Brent solver failed: root is not bracketed"); WARN("Brent solver failed: root is not bracketed");
return; return;
} }
if(abs(fa) < abs(fb)) { if(abs(fa) < abs(fb)) {
std::swap(a,b); std::swap(a,b);
std::swap(fa,fb); std::swap(fa,fb);
} }
bool mflag = true; bool mflag = true;
bool bisec_flag; bool bisec_flag;
SolverProgress progress; SolverProgress progress;
while(true) { while(true) {
if((fa!=fc) && (fb!=fc)){ if((fa!=fc) && (fb!=fc)){
// Inverse quadratic interpolation // Inverse quadratic interpolation
TRACE(5,"IQI"); TRACE(5,"IQI");
t = a*fb*fc/((fa-fb)*(fa-fc)); t = a*fb*fc/((fa-fb)*(fa-fc));
u = b*fa*fc/((fb-fa)*(fb-fc)); u = b*fa*fc/((fb-fa)*(fb-fc));
v = c*fa*fb/((fc-fa)*(fc-fb)); v = c*fa*fb/((fc-fa)*(fc-fb));
s = t+u+v; s = t+u+v;
} }
else { else {
// Secant method // Secant method
TRACE(5,"Secant"); TRACE(5,"Secant");
s = b-fb*(b-a)/(fb-fa); s = b-fb*(b-a)/(fb-fa);
} }
bisec_flag = false; bisec_flag = false;
d abssmb = abs(s-b); d abssmb = abs(s-b);
d absbmc = abs(b-c); d absbmc = abs(b-c);
d abscmd = abs(c-d_); d abscmd = abs(c-d_);
VARTRACE(5,s); VARTRACE(5,s);
if((bisec_flag |= (!is_between(s,(3*a+b)/4,b)))) goto bflag; if((bisec_flag |= (!is_between(s,(3*a+b)/4,b)))) goto bflag;
TRACE(5,"Survived 1"); TRACE(5,"Survived 1");
if(bisec_flag |= (mflag && (abssmb >= absbmc/2))) goto bflag; if(bisec_flag |= (mflag && (abssmb >= absbmc/2))) goto bflag;
TRACE(5,"Survived 2"); TRACE(5,"Survived 2");
if(bisec_flag |= ((!mflag) && (abssmb >= abscmd/2))) goto bflag; if(bisec_flag |= ((!mflag) && (abssmb >= abscmd/2))) goto bflag;
TRACE(5,"Survived 3"); TRACE(5,"Survived 3");
if(bisec_flag |= (mflag && (absbmc < abs(_reltol)))) goto bflag;; if(bisec_flag |= (mflag && (absbmc < abs(_reltol)))) goto bflag;;
TRACE(5,"Survived 4"); TRACE(5,"Survived 4");
bflag: bflag:
if(bisec_flag || ((!mflag) && (abscmd < abs(_reltol)))) { if(bisec_flag || ((!mflag) && (abscmd < abs(_reltol)))) {
TRACE(5,"Bisection"); TRACE(5,"Bisection");
s = (a+b)/2; s = (a+b)/2;
mflag = true; mflag = true;
} }
else { else {
mflag = false; mflag = false;
} }
fs = system.residual(s); fs = system.residual(s);
d_ = c; d_ = c;
if(fa*fs < 0) { if(fa*fs < 0) {
c = b; c = b;
fc = fb; fc = fb;
b=s; b=s;
fb = fs; fb = fs;
} }
else { else {
c = a; c = a;
fc = fa; fc = fa;
a = s; a = s;
fa = fs; fa = fs;
} }
if(abs(fa)<abs(fb)) { if(abs(fa)<abs(fb)) {
std::swap(a,b); std::swap(a,b);
std::swap(fa,fb); std::swap(fa,fb);
} }
progress.fun_err = abs(fs); progress.fun_err = abs(fs);
progress.rel_err = abs(b-a); progress.rel_err = abs(b-a);
progress.iteration++; progress.iteration++;
VARTRACE(5,s); VARTRACE(5,s);
VARTRACE(5,a); VARTRACE(5,a);
VARTRACE(5,b); VARTRACE(5,b);
VARTRACE(5,c); VARTRACE(5,c);
VARTRACE(5,fa); VARTRACE(5,fa);
VARTRACE(5,fb); VARTRACE(5,fb);
VARTRACE(5,fc); VARTRACE(5,fc);
VARTRACE(5,fs); VARTRACE(5,fs);
SolverAction action = (*callback)(progress); SolverAction action = (*callback)(progress);
if(action==Stop){ if(action==Stop){
break; break;
} }
} }
system.updateSolution(b); system.updateSolution(b);
} }
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////

View File

@ -62,15 +62,15 @@ TaSystem::TaSystem(const pb::System& sys):
} }
// Copy solution vector, if valid // Copy solution vector, if valid
const auto& sol = sys.solution(); // const auto& sol = sys.solution();
us size = sol.size(), i=0; // us size = sol.size(), i=0;
if(size>0) { // if(size>0) {
_solution = vd(size); // _solution = vd(size);
for(auto& val: sol) { // for(auto& val: sol) {
_solution(i) = val; // _solution(i) = val;
i++; // i++;
} // }
} // }
} }
TaSystem::TaSystem(const TaSystem& o): TaSystem::TaSystem(const TaSystem& o):

View File

@ -105,7 +105,7 @@ namespace constants {
const int nvars_reserve=7; const int nvars_reserve=7;
const int neqs_reserve=7; const int neqs_reserve=7;
const char* const system_fileext = ".tasmet"; const char* const model_fileext = ".tasmet";
} // namespace constants } // namespace constants

View File

@ -1,70 +1,70 @@
// tasmet_solvemodel.cpp // tasmet_solvemodel.cpp
// //
// last-edit-by: J.A. de Jong // last-edit-by: J.A. de Jong
// //
// Description: // Description:
// Program which can be used to solve a TaSMET Model from the CLI // Program which can be used to solve a TaSMET Model from the CLI
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
#include "protobuf/system_tools.h" // loadSystem, saveSystem #include "protobuf/message_tools.h" // loadSystem, saveSystem
#include "tasmet_io.h" #include "tasmet_io.h"
#include "tasmet_exception.h" #include "tasmet_exception.h"
#include "sys/tasystem.h" #include "sys/tasystem.h"
#include "protobuf/model.pb.h"
// For using python from within Qt // For using python from within Qt
#include <PythonQt.h> #include <PythonQt.h>
void usage(const char* fn) { void usage(const char* fn) {
cout << "Usage: " << endl; cout << "Usage: " << endl;
cout << fn << " [Input file] " << endl; cout << fn << " [Input file] " << endl;
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
INITTRACE(10); INITTRACE(10);
// Initialize PythonQt // Initialize PythonQt
// PythonQt::init(PythonQt::IgnoreSiteModule | PythonQt::RedirectStdOut); // PythonQt::init(PythonQt::IgnoreSiteModule | PythonQt::RedirectStdOut);
PythonQt::init(); PythonQt::init();
PythonQt* pyqt = PythonQt::self(); PythonQt* pyqt = PythonQt::self();
PythonQtObjectPtr context = pyqt->getMainModule(); PythonQtObjectPtr context = pyqt->getMainModule();
QVariant rv = context.evalScript("from math import *\n"); QVariant rv = context.evalScript("from math import *\n");
if(pyqt->hadError()) { if(pyqt->hadError()) {
return -1; return -1;
} }
if(argc != 2) { if(argc != 2) {
usage(argv[0]); usage(argv[0]);
return -1; return -1;
} }
pb::System sys; pb::Model model;
string filename = argv[1]; string filename = argv[1];
try { try {
sys = loadSystem(filename); model = loadMessage<pb::Model>(filename);
} }
catch(TaSMETError &e) { catch(TaSMETError &e) {
cerr << e.what() << endl; cerr << e.what() << endl;
return -1; return -1;
} }
cout << "Loaded model: " << endl; cout << "Loaded model: " << endl;
cout << sys.DebugString(); cout << model.system().DebugString();
TaSystem* system; TaSystem* system;
try { try {
system = new TaSystem(sys); system = new TaSystem(model.system());
} }
catch(TaSMETError &e) { catch(TaSMETError &e) {
cerr << "Model initialization error: " << endl; cerr << "Model initialization error: " << endl;
cerr << e.what() << endl; cerr << e.what() << endl;
return -1; return -1;
} }
} }
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////

View File

@ -1,86 +1,86 @@
// tasmet_types.h // tasmet_types.h
// //
// Author: J.A. de Jong // Author: J.A. de Jong
// //
// Description: // Description:
// Typedefs and namespace pollution for stuff that is almost always // Typedefs and namespace pollution for stuff that is almost always
// needed. // needed.
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
#pragma once #pragma once
#ifndef TASMET_TYPES_H #ifndef TASMET_TYPES_H
#define TASMET_TYPES_H #define TASMET_TYPES_H
#include <type_traits> #include <type_traits>
// We require C++ // We require C++
#ifndef __cplusplus #ifndef __cplusplus
#error The c++ compiler should be used. #error The c++ compiler should be used.
#endif #endif
// Some header files I (almost) always need // Some header files I (almost) always need
#include <vector> // C++ std vector #include <vector> // C++ std vector
#include <string> // C++ string class #include <string> // C++ string class
#include <complex> #include <complex>
#include <armadillo> // Our linear algebra package #include <armadillo> // Our linear algebra package
typedef size_t us; /* Size type I always use */ typedef size_t us; /* Size type I always use */
#define fillwith arma::fill // Fill vector or matrix with ... #define fillwith arma::fill // Fill vector or matrix with ...
// To change the whole code to 32-bit floating points, change this to // To change the whole code to 32-bit floating points, change this to
// float. // float.
#if TASMET_FLOAT == 32 #if TASMET_FLOAT == 32
typedef float d; /* Shortcut for double */ typedef float d; /* Shortcut for double */
#elif TASMET_FLOAT == 64 #elif TASMET_FLOAT == 64
typedef double d; /* Shortcut for double */ typedef double d; /* Shortcut for double */
#else #else
static_assert(false,"TASMET_FLOAT should be either 32 or 64"); static_assert(false,"TASMET_FLOAT should be either 32 or 64");
#endif #endif
typedef std::complex<d> c; /* Shortcut for c++ complex number */ typedef std::complex<d> c; /* Shortcut for c++ complex number */
using arma::abs; using arma::abs;
using std::string; /* C++ Strings */ using std::string; /* C++ Strings */
using std::vector; // C++ Vectors using std::vector; // C++ Vectors
/* Armadillo functions and objects we often need */ /* Armadillo functions and objects we often need */
using arma::sin; using arma::sin;
using arma::cos; using arma::cos;
using arma::exp; using arma::exp;
using arma::ones; using arma::ones;
using arma::zeros; using arma::zeros;
using arma::eye; using arma::eye;
using arma::inv; using arma::inv;
using arma::det; using arma::det;
using arma::log_det; using arma::log_det;
using arma::norm; using arma::norm;
using arma::span; using arma::span;
using arma::linspace; using arma::linspace;
using arma::diagmat; using arma::diagmat;
// Constants // Constants
// I need these numbers so often, that they can be in the global namespace // I need these numbers so often, that they can be in the global namespace
const c I(0,1); //Complex unity const c I(0,1); //Complex unity
const c sqI=sqrt(I); const c sqI=sqrt(I);
const d sq2=sqrt(2.0); const d sq2=sqrt(2.0);
const c sqmI=sqrt(-1.0*I); const c sqmI=sqrt(-1.0*I);
const c minI(0,-1); //Minus complex unity const c minI(0,-1); //Minus complex unity
const d number_pi=arma::datum::pi; // The number 3.14159265359.. const d number_pi=arma::datum::pi; // The number 3.14159265359..
template<size_t i> template<size_t i>
using vdi = arma::Col<d>::fixed<i>; using vdi = arma::Col<d>::fixed<i>;
template<size_t i> template<size_t i>
using vci = arma::Col<c>::fixed<i>; using vci = arma::Col<c>::fixed<i>;
typedef arma::Col<d> vd; /* Column vector of doubles */ typedef arma::Col<d> vd; /* Column vector of doubles */
typedef arma::Col<c> vc; /* Column vector of complex numbers */ typedef arma::Col<c> vc; /* Column vector of complex numbers */
typedef arma::Col<us> vus; /* Column vector of unsigned integers */ typedef arma::Col<us> vus; /* Column vector of unsigned integers */
typedef arma::Mat<d> dmat; /* (Dense) Matrix of doubles */ typedef arma::Mat<d> dmat; /* (Dense) Matrix of doubles */
typedef arma::Mat<c> cmat; /* (Dense) matrix of complex numbers */ typedef arma::Mat<c> cmat; /* (Dense) matrix of complex numbers */
typedef arma::SpMat<d> sdmat; /* Sparse matrix of doubles */ typedef arma::SpMat<d> sdmat; /* Sparse matrix of doubles */
#endif // TASMET_TYPES_H #endif // TASMET_TYPES_H
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////