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
No related branches found
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