Skip to content
Snippets Groups Projects
Commit 837cc397 authored by Boman Romain's avatar Boman Romain
Browse files

add "convert to csv" button

parent d4f154c0
Branches devel/bb2024
No related tags found
No related merge requests found
Pipeline #18998 passed
......@@ -7,7 +7,7 @@
# if starting Qt fails with
# qt.qpa.plugin: Could not find the Qt platform plugin "windows" in ""
# this means that an application in the PATH provides another version of Qt
# which is incompatible (MikTeX)
# which is incompatible (MikTeX)
# => move MikTeX to the bottom of the user PATH.
from PyQt5.QtCore import *
......@@ -17,10 +17,16 @@ from gui.ui_fossils import Ui_Form
import sys
import os
import gui.resources
import numpy as np
import gmsh
if not gmsh.isInitialized():
gmsh.initialize()
class Window(QWidget, Ui_Form):
"""Minimal GUI asking for a file and running it
"""
def __init__(self, parent=None):
super(Window, self).__init__(parent)
self.setupUi(self)
......@@ -40,28 +46,30 @@ class Window(QWidget, Ui_Form):
# read Qt settings for the application
settings = QSettings()
# self.restoreGeometry(settings.value("Geometry", self.saveGeometry()))
self.inpFileLineEdit.setText(settings.value("inpFile", self.default_inputfile()))
self.wrkspLineEdit.setText(settings.value("workspace", self.default_wrksp()))
self.inpFileLineEdit.setText(settings.value(
"inpFile", self.default_inputfile()))
self.wrkspLineEdit.setText(settings.value(
"workspace", self.default_wrksp()))
self.action = 'cancelled'
#iconfile = os.path.join('fossils.png')
# iconfile = os.path.join('fossils.png')
self.setWindowIcon(QIcon(":/fossils.png"))
def default_inputfile(self):
testnames = [
os.path.join(os.path.dirname(__file__),'models','others','dolicorhynchops','dolicorhynchops_10k.py'),
os.path.join(os.path.dirname(__file__),'models','dolicorhynchops','dolicorhynchops_10k.py'),
testnames = [
os.path.join(os.path.dirname(__file__), 'models', 'others',
'dolicorhynchops', 'dolicorhynchops_10k.py'),
os.path.join(os.path.dirname(__file__), 'models',
'dolicorhynchops', 'dolicorhynchops_10k.py'),
]
for name in testnames:
if os.path.isfile(name):
return name
return ""
def default_wrksp(self):
for key in ['USERPROFILE', 'HOME' ]:
for key in ['USERPROFILE', 'HOME']:
try:
folder = os.environ[key]
if os.path.isdir(folder):
......@@ -70,7 +78,6 @@ class Window(QWidget, Ui_Form):
pass
return ""
def on_runPushButton_pressed(self):
if not os.path.isfile(self.inpFileLineEdit.text()):
QMessageBox.critical(self, "Error", "Input file does not exist!")
......@@ -78,8 +85,8 @@ class Window(QWidget, Ui_Form):
if not os.path.isdir(self.wrkspLineEdit.text()):
reply = QMessageBox.question(self, 'Message',
"Workspace does not exist - do you want to continue?",
QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
"Workspace does not exist - do you want to continue?",
QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
if reply == QMessageBox.No:
return
# wdir = build_workspace_name(self.wrkspLineEdit.text(), self.inpFileLineEdit.text())
......@@ -87,15 +94,23 @@ class Window(QWidget, Ui_Form):
self.action = 'run'
self.close()
def on_viewPushButton_pressed(self):
wdir = build_workspace_name(self.wrkspLineEdit.text(), self.inpFileLineEdit.text())
wdir = build_workspace_name(
self.wrkspLineEdit.text(), self.inpFileLineEdit.text())
if not os.path.isdir(wdir):
QMessageBox.critical(self, "Error", f"No results in {wdir}!")
return
self.action = 'post'
self.close()
def on_toCSVPushButton_pressed(self):
wdir = build_workspace_name(
self.wrkspLineEdit.text(), self.inpFileLineEdit.text())
if not os.path.isdir(wdir):
QMessageBox.critical(self, "Error", f"No results in {wdir}!")
return
self.action = 'csv'
self.close()
def on_inpFilePushButton_pressed(self):
# try to set a relevant starting folder
......@@ -107,11 +122,10 @@ class Window(QWidget, Ui_Form):
default = curfolder
fname = QFileDialog.getOpenFileName(
self, 'Select input file', default, filter='Python File (*.py)')
self, 'Select input file', default, filter='Python File (*.py)')
pyfile = fname[0]
if pyfile:
self.inpFileLineEdit.setText(QDir.toNativeSeparators(pyfile))
self.inpFileLineEdit.setText(QDir.toNativeSeparators(pyfile))
def on_inpFileEditPushButton_pressed(self):
"""Open input file with a text editor
......@@ -119,35 +133,30 @@ class Window(QWidget, Ui_Form):
editors = [
"C:/Program Files/Just Great Software/EditPad Pro 8/EditPadPro8.exe",
"C:/Windows/notepad.exe"
]
]
for editor in editors:
if os.path.isfile(editor):
import subprocess
subprocess.Popen([ editor, self.inpFileLineEdit.text() ])
subprocess.Popen([editor, self.inpFileLineEdit.text()])
break
def on_inpFileResetPushButton_pressed(self):
self.inpFileLineEdit.setText(self.default_inputfile())
def on_wrkspExplorePushButton_pressed(self):
"""Browse workspace folder with system explorer
"""
os.startfile(self.wrkspLineEdit.text())
def on_wrkspPushButton_pressed(self):
dir = QFileDialog.getExistingDirectory(
self, "Select output folder", self.wrkspLineEdit.text())
if dir:
self.wrkspLineEdit.setText(QDir.toNativeSeparators(dir))
self.wrkspLineEdit.setText(QDir.toNativeSeparators(dir))
def on_wrkspResetPushButton_pressed(self):
self.wrkspLineEdit.setText(self.default_wrksp())
def closeEvent(self, event):
"""save settings to registry and quit
"""
......@@ -163,20 +172,18 @@ def run_simulation(testname):
"""
# thanks to the "compile" command, the filename appears in the stack
# trace in case of errors
script = open(testname, encoding='utf-8').read()
exec(compile(script, testname, 'exec'),
{'__file__': testname, '__name__':'__main__'})
script = open(testname, encoding='utf-8').read()
exec(compile(script, testname, 'exec'),
{'__file__': testname, '__name__': '__main__'})
def view_results():
"""Load/display results in the current folder
def load_previous_results():
"""Load previously computed results from the current folder
"""
import gmsh
if not gmsh.isInitialized():
gmsh.initialize()
# load empty mesh
gmsh.merge('mesh.msh')
gmsh.option.setNumber("General.Verbosity", 3)
# load views from the option file
views = []
with open('post.opt') as f:
......@@ -192,12 +199,57 @@ def view_results():
gmsh.merge(v[1])
print('loading options...')
gmsh.merge('post.opt')
return views
def view_results():
"""Load/display results in the current folder
"""
views = load_previous_results()
print('starting Gmsh GUI, please wait...')
gmsh.fltk.run()
def convert_results_to_csv():
"""Converts results to CSV files
"""
views = load_previous_results()
# export results to csv
for v in views:
csvfile = v[1].replace('.msh', '.csv')
dataType, tags, data, time, numComp = gmsh.view.getModelData(tag=int(v[0])+1, step=0) # assume tag=index+1
print(f'exporting "{csvfile}" ({dataType})')
# export raw "data" to csv
# np.savetxt(csvfile, data, delimiter=',')
# if tensor => compute j2 for each node
if numComp == 9:
ndata = np.array(data)
data = np.array([])
ncols = ndata.shape[1]
nnods = ncols/9
for i in range(int(nnods)):
xx, xy, xz, yx, yy, yz, zx, zy, zz = ndata[:,i*9:(i+1)*9].T
j2 = np.sqrt( ((xx-yy)**2 + (yy-zz)**2 + (zz-xx)**2 )/2 + 3*(xy*xy+yz*yz+zx*zx) )
if data.any():
data = np.vstack([data,j2])
else:
data = j2
if nnods == 1:
data = data.reshape(1,-1)
data = data.T
# export "data" to csv with tags
f = open(csvfile, "w")
for x,y in zip(tags, data):
f.write("{}, {}\n".format(x, ', '.join(map(str, y))))
f.close()
def rm_folder_from_pypath(folder):
sys.path = [ p for p in sys.path if not folder in p]
sys.path = [p for p in sys.path if not folder in p]
def add_folder2pypath(folder):
......@@ -209,10 +261,10 @@ def add_folder2pypath(folder):
def rm_folder_from_path(folder):
import platform
if 'Windows' in platform.uname():
path = [ p for p in os.environ['PATH'].split(';') if not folder in p]
path = [p for p in os.environ['PATH'].split(';') if not folder in p]
os.environ['PATH'] = ';'.join(path)
# print(f'{folder} added to PATH')
# print(f"os.environ['PATH']={os.environ['PATH']}")
# print(f"os.environ['PATH']={os.environ['PATH']}")
def add_folder2path(folder):
......@@ -240,15 +292,15 @@ def setup_pythonpath():
pyexe = os.path.basename(sys.executable)
print(f'pyexe = {pyexe}')
add_folder2pypath(os.path.join(this_script_dir, 'cxxfem',
'build', 'bin')) # gcc/mingw
'build', 'bin')) # gcc/mingw
add_folder2pypath(os.path.join(this_script_dir, 'cxxfem',
'build', 'bin', 'Release')) # msvc
'build', 'bin', 'Release')) # msvc
# allows this script to be run without setting env
# rm_folder_from_path('gmsh')
# rm_folder_from_pypath('gmsh')
# add_folder2pypath(os.path.join(this_script_dir, 'lib',
# 'gmsh-sdk', 'lib')) # msvc
# 'gmsh-sdk', 'lib')) # msvc
# add_folder2path(os.path.join(this_script_dir, 'lib',
# 'gmsh-sdk', 'bin')) # gmsh
# print(f'sys.path={sys.path}')
......@@ -260,6 +312,7 @@ def setup_pythonpath():
if os.path.exists(v):
os.add_dll_directory(v)
def build_workspace_name(workspace, testname):
"""create workspace folder and chdir into it
"""
......@@ -268,7 +321,7 @@ def build_workspace_name(workspace, testname):
# => workspace + testname
common = os.path.basename(testname)
resdir = common.replace(os.sep, "_")
resdir, ext = os.path.splitext(resdir)
resdir, ext = os.path.splitext(resdir)
wdir = os.path.join(workspace, resdir)
else:
# workspace is not given:
......@@ -283,7 +336,6 @@ def build_workspace_name(workspace, testname):
wdir = os.path.abspath(os.path.join('workspace', resdir))
return wdir
if __name__ == "__main__":
......@@ -302,7 +354,8 @@ if __name__ == "__main__":
os.environ['OMP_NUM_THREADS'] = str(args.k)
cxxfem.set_num_threads(args.k)
__file__ = os.path.abspath(__file__) # relative path on Linux with python <=3.8
# relative path on Linux with python <=3.8
__file__ = os.path.abspath(__file__)
# display env variables
try:
......@@ -310,7 +363,6 @@ if __name__ == "__main__":
except:
print(f"OMP_NUM_THREADS=[not set]")
# ask for a file if not given => starts the GUI
if not args.file:
# QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
......@@ -320,7 +372,8 @@ if __name__ == "__main__":
win = Window()
win.setWindowTitle("Fossils")
win.show()
win.setWindowState(Qt.WindowActive) # try to make it appear above any other window (and particularly the console window)
# try to make it appear above any other window (and particularly the console window)
win.setWindowState(Qt.WindowActive)
app.lastWindowClosed.connect(app.quit)
app.exec_()
......@@ -329,7 +382,7 @@ if __name__ == "__main__":
testname = win.inpFileLineEdit.text()
gui = True
else:
workspace = None # use default
workspace = None # use default
if args.post:
action = 'post'
else:
......@@ -340,10 +393,10 @@ if __name__ == "__main__":
# run the simulation or display results
print(f'action = {action}')
if action=='run' or action=='post':
if action in ['run', 'post', 'csv']:
testname = os.path.normcase(testname) # F:/ => f:/ on Windows
print(f'testname = {testname}')
wdir = build_workspace_name(workspace, testname)
print('workspace =', wdir)
# sys.exit()
......@@ -353,11 +406,15 @@ if __name__ == "__main__":
try:
if action == 'run':
tee = cxxfem.Tee('stdout.txt') # split streams (stdout + logfile)
# split streams (stdout + logfile)
tee = cxxfem.Tee('stdout.txt')
run_simulation(testname)
elif action == 'post':
tee = cxxfem.Tee('post.txt')
view_results()
elif action == 'csv':
tee = cxxfem.Tee('tocsv.txt')
convert_results_to_csv()
except Exception as err:
print(f'\n** ERROR: {err}\n')
import traceback
......
......@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>745</width>
<height>154</height>
<width>756</width>
<height>116</height>
</rect>
</property>
<property name="windowTitle">
......@@ -129,7 +129,7 @@
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
......@@ -169,6 +169,19 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="toCSVPushButton">
<property name="toolTip">
<string>read/display the results stored in the folder of the workspace</string>
</property>
<property name="statusTip">
<string/>
</property>
<property name="text">
<string>to CSV</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
......
......@@ -14,7 +14,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(745, 154)
Form.resize(756, 116)
self.verticalLayout = QtWidgets.QVBoxLayout(Form)
self.verticalLayout.setObjectName("verticalLayout")
self.gridLayout = QtWidgets.QGridLayout()
......@@ -58,21 +58,25 @@ class Ui_Form(object):
self.wrkspResetPushButton.setObjectName("wrkspResetPushButton")
self.gridLayout.addWidget(self.wrkspResetPushButton, 1, 4, 1, 1)
self.verticalLayout.addLayout(self.gridLayout)
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_2.addItem(spacerItem)
self.horizontalLayout.addItem(spacerItem)
self.runPushButton = QtWidgets.QPushButton(Form)
self.runPushButton.setStatusTip("")
self.runPushButton.setObjectName("runPushButton")
self.horizontalLayout_2.addWidget(self.runPushButton)
self.horizontalLayout.addWidget(self.runPushButton)
self.viewPushButton = QtWidgets.QPushButton(Form)
self.viewPushButton.setStatusTip("")
self.viewPushButton.setObjectName("viewPushButton")
self.horizontalLayout_2.addWidget(self.viewPushButton)
self.horizontalLayout.addWidget(self.viewPushButton)
self.toCSVPushButton = QtWidgets.QPushButton(Form)
self.toCSVPushButton.setStatusTip("")
self.toCSVPushButton.setObjectName("toCSVPushButton")
self.horizontalLayout.addWidget(self.toCSVPushButton)
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_2.addItem(spacerItem1)
self.verticalLayout.addLayout(self.horizontalLayout_2)
self.horizontalLayout.addItem(spacerItem1)
self.verticalLayout.addLayout(self.horizontalLayout)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
......@@ -100,3 +104,5 @@ class Ui_Form(object):
self.runPushButton.setText(_translate("Form", "Run"))
self.viewPushButton.setToolTip(_translate("Form", "read/display the results stored in the folder of the workspace"))
self.viewPushButton.setText(_translate("Form", "View"))
self.toCSVPushButton.setToolTip(_translate("Form", "read/display the results stored in the folder of the workspace"))
self.toCSVPushButton.setText(_translate("Form", "to CSV"))
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment