Added symbols for actions

This commit is contained in:
Anne de Jong 2020-04-28 09:33:09 +02:00
parent dd287e2793
commit e925e5a067
23 changed files with 367 additions and 66 deletions

1
.gitignore vendored
View File

@ -22,3 +22,4 @@ brent_test
tasmet
tasmet_automoc.dir
tasmet_solvemodel
tasmet_autogen

View File

@ -1,5 +1,5 @@
# CMakeList.txt for TaSMET
cmake_minimum_required (VERSION 3.6)
cmake_minimum_required (VERSION 2.8.5)
project(TaSMET)
set(PACKAGE_VERSION 0.1)
message("Running Cmake for TaSMET version ${PACKAGE_VERSION}")

View File

@ -51,14 +51,14 @@ PROJECT_BRIEF = "Thermoacoustic System Modeling Environment"
# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
# the logo to the output directory.
PROJECT_LOGO = /home/anne/wip/tasmet/src/gui/images/tasmet_small.png
PROJECT_LOGO = src/gui/images/tasmet_small.png
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
# into which the generated documentation will be written. If a relative path is
# entered, it will be relative to the location where doxygen was started. If
# left blank the current directory will be used.
OUTPUT_DIRECTORY = /home/anne/wip/tasmet/doc
OUTPUT_DIRECTORY = doc
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
# directories (in 2 levels) under the output directory of each output format and

0
doc/fig/tasys_artist.eps Executable file → Normal file
View File

0
doc/fig/tasys_artist.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

0
gui/__init__.py Normal file
View File

83
gui/about_dialog.py Normal file
View File

@ -0,0 +1,83 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'about_dialog.ui'
#
# Created by: PyQt4 UI code generator 4.12
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
class Ui_about_dialog(object):
def setupUi(self, about_dialog):
about_dialog.setObjectName(_fromUtf8("about_dialog"))
about_dialog.resize(318, 582)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Minimum)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(about_dialog.sizePolicy().hasHeightForWidth())
about_dialog.setSizePolicy(sizePolicy)
self.verticalLayout = QtGui.QVBoxLayout(about_dialog)
self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
self.label = QtGui.QLabel(about_dialog)
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans Mono"))
font.setPointSize(14)
font.setBold(True)
font.setWeight(75)
self.label.setFont(font)
self.label.setAlignment(QtCore.Qt.AlignCenter)
self.label.setObjectName(_fromUtf8("label"))
self.verticalLayout.addWidget(self.label)
self.label_4 = QtGui.QLabel(about_dialog)
self.label_4.setAlignment(QtCore.Qt.AlignCenter)
self.label_4.setObjectName(_fromUtf8("label_4"))
self.verticalLayout.addWidget(self.label_4)
self.label_5 = QtGui.QLabel(about_dialog)
self.label_5.setAlignment(QtCore.Qt.AlignCenter)
self.label_5.setObjectName(_fromUtf8("label_5"))
self.verticalLayout.addWidget(self.label_5)
self.label_2 = QtGui.QLabel(about_dialog)
self.label_2.setMinimumSize(QtCore.QSize(300, 433))
self.label_2.setMaximumSize(QtCore.QSize(300, 433))
self.label_2.setStyleSheet(_fromUtf8("background-color: rgb(255, 255, 255)"))
self.label_2.setFrameShape(QtGui.QFrame.Box)
self.label_2.setText(_fromUtf8(""))
self.label_2.setPixmap(QtGui.QPixmap(_fromUtf8("images/tasmet.png")))
self.label_2.setScaledContents(True)
self.label_2.setObjectName(_fromUtf8("label_2"))
self.verticalLayout.addWidget(self.label_2)
self.label_3 = QtGui.QLabel(about_dialog)
self.label_3.setAlignment(QtCore.Qt.AlignCenter)
self.label_3.setObjectName(_fromUtf8("label_3"))
self.verticalLayout.addWidget(self.label_3)
self.pushButton = QtGui.QPushButton(about_dialog)
self.pushButton.setObjectName(_fromUtf8("pushButton"))
self.verticalLayout.addWidget(self.pushButton)
self.retranslateUi(about_dialog)
QtCore.QObject.connect(self.pushButton, QtCore.SIGNAL(_fromUtf8("clicked()")), about_dialog.accept)
QtCore.QMetaObject.connectSlotsByName(about_dialog)
def retranslateUi(self, about_dialog):
about_dialog.setWindowTitle(_translate("about_dialog", "About TaSMET", None))
self.label.setText(_translate("about_dialog", "TaSMET", None))
self.label_4.setText(_translate("about_dialog", "Thermoacoustic System", None))
self.label_5.setText(_translate("about_dialog", "Modeling Environment Twente", None))
self.label_3.setText(_translate("about_dialog", "Copyright (c) 2017 Anne de Jong", None))
self.pushButton.setText(_translate("about_dialog", "OK", None))

130
gui/about_dialog.ui Normal file
View File

@ -0,0 +1,130 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>about_dialog</class>
<widget class="QDialog" name="about_dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>318</width>
<height>582</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>About TaSMET</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="font">
<font>
<family>DejaVu Sans Mono</family>
<pointsize>14</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>TaSMET</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Thermoacoustic System</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>Modeling Environment Twente</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="minimumSize">
<size>
<width>300</width>
<height>433</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>300</width>
<height>433</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(255, 255, 255)</string>
</property>
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap>images/tasmet.png</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Copyright (c) 2017 Anne de Jong</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>OK</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>pushButton</sender>
<signal>clicked()</signal>
<receiver>about_dialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>158</x>
<y>562</y>
</hint>
<hint type="destinationlabel">
<x>158</x>
<y>290</y>
</hint>
</hints>
</connection>
</connections>
</ui>

BIN
images/document-new.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
images/document-open.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

BIN
images/document-save-as.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
images/document-save.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
images/tasmet.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

BIN
images/tasmet_small.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

0
src/gui/images/tasmet.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

0
src/gui/images/tasmet_small.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

@ -11,14 +11,6 @@
#include <sstream>
#include <QString>
#include <QSettings>
#include <QWidget>
#include <QDoubleValidator>
#include <QIntValidator>
#include <QFileDialog>
#include <QStandardPaths>
#include "tasmet_config.h"
#include "tasmet_tracer.h"
#include "tasmet_assert.h"
@ -31,6 +23,16 @@
#include "solver_dialog.h"
#include "message_tools.h"
#include <QString>
#include <QSettings>
#include <QWidget>
#include <QDoubleValidator>
#include <QIntValidator>
#include <QFileDialog>
#include <QStandardPaths>
#include <QProcess>
const QString default_model_name = QString("Unsaved TaSMET Model") +
constants::model_fileext;
const QString default_segment_name = "Unnamed segment";
@ -38,6 +40,7 @@ const QString start_file_location = QStandardPaths::
writableLocation(QStandardPaths::DocumentsLocation);
const QString filetype = QString("TaSMET Model files (*") + constants::model_fileext + ")";
const QString window_title_part = "TaSMET Model Builder - ";
namespace {
int saveFileFirstQuestion(QWidget* parent) {
@ -55,6 +58,7 @@ namespace {
TaSMETMainWindow::TaSMETMainWindow():
_window(new Ui::MainWindow()),
_model(pb::Model::default_instance()),
_saved_model(_model),
_system(*_model.mutable_system())
{
@ -120,6 +124,7 @@ TaSMETMainWindow::~TaSMETMainWindow(){
void TaSMETMainWindow::newModel() {
TRACE(15,"newModel");
_model = pb::Model::default_instance();
_saved_model = _model;
_filepath = "";
set(_model);
}
@ -148,7 +153,11 @@ void TaSMETMainWindow::loadModel(const string* filepath_s) {
try {
TRACE(15,"Setting loaded model");
_filepath = *filepath_s;
set(loadMessage<pb::Model>(*filepath_s));
_model = loadMessage<pb::Model>(*filepath_s);
_saved_model = _model;
_system = *_model.mutable_system();
set(_model);
}
catch(TaSMETError &e) {
_filepath = "";
@ -172,6 +181,7 @@ void TaSMETMainWindow::saveModel(string* filepath) {
}
try {
saveMessage<pb::Model>(*filepath,_model);
_saved_model = _model;
_filepath = *filepath;
changed();
}
@ -282,8 +292,6 @@ void TaSMETMainWindow::set(const pb::Model& model) {
_window->backlog->setPlainText(QString::fromStdString(model.backlog()));
_model = model;
_system = *_model.mutable_system();
_init = false;
changed();
@ -311,6 +319,9 @@ void TaSMETMainWindow::closeEvent(QCloseEvent *event) {
}
}
// If we are here, the model is not dirty anymore. We can savely
// close the application.
// Save window configuration to settings
QSettings settings(company,appname);
settings.setValue("geometry", saveGeometry());
@ -470,10 +481,12 @@ void TaSMETMainWindow::on_actionSolve_triggered() {
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);
}
@ -483,6 +496,21 @@ void TaSMETMainWindow::on_actionPostprocess_model_triggered() {
throw TaSMETError("Model has not yet been saved");
sys.exportHDF5(_filepath + ".h5");
QString command = "python";
QString appfilepath = QCoreApplication::applicationDirPath();
QString postprocessor_program = appfilepath +
QDir::separator() + "tasmet_postprocessor.py";
QString filepath_post = QString::fromStdString(_filepath) + ".h5";
QStringList params;
params << postprocessor_program;
params << filepath_post;
// Start the process, which is destroyed whenever the program
// is killed
QProcess *p = new QProcess(this);
// connect(p,&QProcess::finished,p,&QProcess::deleteLater);
p->startDetached(command,params);
}
catch(TaSMETError &e) {
e.show_user("Postprocessing failed");
@ -491,18 +519,7 @@ void TaSMETMainWindow::on_actionPostprocess_model_triggered() {
}
bool TaSMETMainWindow::isDirty() const {
TRACE(15,"isDirty()");
if(_filepath.size()==0) return true;
try {
pb::Model filemodel = loadMessage<pb::Model>(_filepath);
bool dirty = !compareMessage<pb::Model>(filemodel,_model);
VARTRACE(15,dirty);
return dirty;
}
catch(TaSMETError& e) {
TRACE(15,"Files could not be compared");
return true;
}
return !compareMessage(_model,_saved_model);
}
void TaSMETMainWindow::on_actionAbout_triggered(){

View File

@ -26,6 +26,10 @@ class TaSMETMainWindow: public QMainWindow {
// In-memory model
pb::Model _model;
pb::Model _saved_model; /**< Last saved state of the model, to
compare with to check whether we
are dirty yes or no */
pb::System& _system; /**< In constructor set to the
_model.mutable_system() */

View File

@ -348,7 +348,7 @@
<x>0</x>
<y>0</y>
<width>683</width>
<height>18</height>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
@ -456,7 +456,7 @@
</action>
<action name="actionPostprocess_model">
<property name="text">
<string>Create postprocessing file</string>
<string>Start &amp;postprocessor...</string>
</property>
</action>
</widget>

View File

@ -96,7 +96,7 @@ public:
// add two Variableiables
Variable operator+(const Variable& other) const;
//Subtract two Variableiables
Variable operator-(const Variable& Variable2) const;
Variable operator-(const Variable& other) const;
// with Note multiplication is defined outside of the class
// If we need to multiply two numbers in frequency domain, this

View File

@ -457,10 +457,11 @@ void TaSystem::exportHDF5(const string& filename) const {
// H5Eset_auto(error_stack, old_func, old_client_data); /// Disable HDF5 error printing
if(file_id < 0)
throw TaSMETError("Creation of export file failed. "
"This could mean that the file is blocked "
"by another program, or the user has insufficient "
"privileges to create the file at the given path."
throw TaSMETError("Creation of export file failed. This is probably "
"because the postprocessor is already running. "
"However, this could also mean that the file is blocked "
"by another program, or you have insufficient "
"privileges to create the postprocessing file."
);
/// Enable HDF5 error printing

131
tasmet_postprocessor.py Executable file → Normal file
View File

@ -5,17 +5,26 @@ Created on Thu Feb 2 08:33:53 2017
@author: anne
"""
qt = 5
# Here we provide the necessary imports.
# The basic GUI widgets are located in QtGui module.
import sys, h5py
import numpy as np
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QIcon,QDoubleValidator
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5 import NavigationToolbar2QT as NavigationToolbar
if qt==4:
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4 import NavigationToolbar2QT as NavigationToolbar
else:
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QIcon,QDoubleValidator
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5 import NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure
import time
from matplotlib.animation import FuncAnimation
from gui.about_dialog import Ui_about_dialog
scale = [('nano',-9,'n'),
@ -68,7 +77,7 @@ class TaSMETFigure(Figure):
def __init__(self, width=5, height=4, dpi=100):
Figure.__init__(self,figsize=(width, height), dpi=dpi)
Figure.__init__(self, figsize=(width, height), dpi=dpi)
self._axes = self.add_subplot(111)
@ -76,6 +85,9 @@ class TaSMETFigure(Figure):
self._plots = []
self._grid = False
def setCanvas(self,canvas):
self._canvas = canvas
def addPlot(self,plot,one):
if one:
self._plots = [plot]
@ -94,7 +106,8 @@ class TaSMETFigure(Figure):
self._axes.grid(self._grid,'both')
self.canvas.draw_idle()
self.canvas.draw()
def setGrid(self,grid):
self._grid = grid
self.rePlot()
@ -107,7 +120,44 @@ class TaSMETFigure(Figure):
self._plots = []
self.rePlot()
def animate(self, data):
line = self._axes.get_lines()[0]
max_val = np.max(data)
min_val = np.min(data)
self._axes.set_ylim((min_val,max_val))
# Number of frames available in a period
frames_per_period = data.shape[1]
# Time to pass to show one period
time_per_period = 1.0
# interval in seconds
interval = time_per_period/frames_per_period
# We need a max, here because due to a bug intervals lower than 200
# are going plain wrong in matplotlib
interval_ms = max(int(interval*1000),200)
def animate_i(i):
line.set_ydata(data[:,i%frames_per_period])
return line,
ani = FuncAnimation(self,
animate_i,
interval = max(200,interval_ms),
frames = frames_per_period,
blit=True,
repeat = True,
save_count = 300 # High value here as animate_i repeats itself
)
self.canvas.draw()
# for i in range(100):
# print(i)
# animate_i(i)
#
class TaSMETCanvas(FigureCanvas):
def __init__(self, parent, figure):
@ -120,7 +170,7 @@ class TaSMETCanvas(FigureCanvas):
QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
figure.setCanvas(self)
class MainWindow(QMainWindow):
@ -277,7 +327,7 @@ class MainWindow(QMainWindow):
# Plot menu
plot_menu = QMenu('&Plot', self)
self._grid_option = QAction('Enable grid')
self._grid_option = QAction('Enable grid',plot_menu)
self._grid_option.setCheckable(True)
self._grid_option.triggered.connect(self._figure.setGrid)
plot_menu.addAction(self._grid_option)
@ -335,8 +385,28 @@ class MainWindow(QMainWindow):
def output(self):
print('output')
def disableAll(self):
self._seg_box.setEnabled(False)
self._qty_box.setEnabled(False)
self._vspos.setEnabled(False)
self._vstime.setEnabled(False)
self._vs_instance.setEnabled(False)
self._plot_button.setEnabled(False)
self._output_button.setEnabled(False)
self._animate_button.setEnabled(False)
def animate(self):
print('animate')
self.disableAll()
self._hold_button.setChecked(False)
self.plot()
try:
data,datatype = self.getCurrentData()
except:
return
self._figure.animate(data[:,:])
self.qtyItemChanged()
def getCurrentData(self):
"""
@ -353,13 +423,12 @@ class MainWindow(QMainWindow):
datatype = data.attrs['datatype'].decode('utf-8')
return data,datatype
def segItemChanged(self,item):
def segItemChanged(self,item=None):
"""
Update the combobox with quantities
"""
self._suppressed = True
self._qty_box.clear()
one = False
@ -373,14 +442,14 @@ class MainWindow(QMainWindow):
self._suppressed = False
self._qty_box.setCurrentIndex(0)
self.qtyItemChanged(0)
self.qtyItemChanged()
def qtyItemChanged(self,item):
def qtyItemChanged(self,item=None):
"""
The quantity item has been changed
"""
if self._suppressed: return
try:
data,datatype = self.getCurrentData()
except:
@ -388,16 +457,15 @@ class MainWindow(QMainWindow):
segitemno = self._seg_box.currentText()
if data is None:
self._vstime.setChecked(False)
self._vspos.setEnabled(False)
self._vstime.setEnabled(False)
self._vs_instance.setEnabled(False)
self._plot_button.setEnabled(False)
self._output_button.setEnabled(False)
self._animate_button.setEnabled(False)
return
self.disableAll()
self._seg_box.setEnabled(True)
self._qty_box.setEnabled(True)
if data is None:
return
self._plot_button.setEnabled(True)
self._output_button.setEnabled(True)
@ -405,9 +473,6 @@ class MainWindow(QMainWindow):
if datatype == 'time':
self._vstime.setChecked(True)
self._vspos.setEnabled(False)
self._vstime.setEnabled(False)
self._vs_instance.setEnabled(False)
self._animate_button.setEnabled(False)
elif datatype == 'pos':
self._vspos.setChecked(True)
@ -429,6 +494,7 @@ class MainWindow(QMainWindow):
self._vspos.setEnabled(True)
self._vstime.setEnabled(True)
self._vs_instance.setEnabled(True)
self._animate_button.setEnabled(True)
def initGui(self):
self.defaultOutput()
@ -552,8 +618,7 @@ def usage():
if __name__ == '__main__':
if(len(sys.argv) < 2):
usage()
file_ = '../second_duct_sinomgt.tasmet.h5'
# return -1
exit(-1)
else:
file_ = sys.argv[1]
@ -573,4 +638,4 @@ if __name__ == '__main__':
w.show() # The show() method displays the widget on the screen.
sys.exit(app.exec_()) # Finally, we enter the mainloop of the application.
sys.exit(app.exec_()) # Finally, we enter the mainloop of the application.