From 6f6c96c26a4416b6ad1a025622e284d5fc79d8e4 Mon Sep 17 00:00:00 2001 From: "Kenneth C. Kleissl" Date: Thu, 17 Jan 2019 21:07:13 +0100 Subject: [PATCH] Fixed shear flow for zero N and M, incorporated version check, validity check of geometry thickness, wall length and clockwise def. --- Analysis.py | 7 +-- MyMainWindow.py => AppWindows.py | 86 ++++++++++++++++++++++++-------- Geometry.py | 14 ++++++ convert_ui.bat | 1 + design.py | 46 ++++++++++------- design.ui | 57 ++++++++++++++------- main.py | 4 +- 7 files changed, 150 insertions(+), 65 deletions(-) rename MyMainWindow.py => AppWindows.py (92%) diff --git a/Analysis.py b/Analysis.py index d8bf4f2..188f546 100644 --- a/Analysis.py +++ b/Analysis.py @@ -421,12 +421,13 @@ def dualSection(section, SF, Mat): dx = 0.001 # [m] Offset SF2 = SectionForces.SectionForces(SF.N, SF.Mx + dx * SF.Vy, SF.My - dx * SF.Vx) # SF2 = prep_dual_section(SF, dx) # nabouring SF - + # --------------- Optimize plane strain variables for the secondary section --------------- opt2 = nlopt.opt(nlopt.LN_NELDERMEAD, len(x)) opt2.set_min_objective(lambda x, grad: errorFunBending(x, section, SF2, Mat)) opt2.set_xtol_rel(1e-8) - x2 = opt2.optimize(x) + x0 = [0 if abs(x)<1e-6 else x for x in x0] # the initial guess may not contain extremely small values such as 3e-169 + x2 = opt2.optimize(x0) print("Optimized strain state2 =", x2) print("Minimized error2 value = ", opt.last_optimum_value()) @@ -434,7 +435,7 @@ def dualSection(section, SF, Mat): _, dist = BendingEQ(section, Mat, x[0], x[1], x[2]) # get distributions from first section _, dist2 = BendingEQ(section, Mat, x2[0], x2[1], x2[2]) # get distributions from first section H = shear_flow(dist, dist2, SF, section, dx) - + # --------------- SLS verification --------------- # Disk stress components theta, sigma_c, sigma_sx, sigma_sy = [], [], [], [] diff --git a/MyMainWindow.py b/AppWindows.py similarity index 92% rename from MyMainWindow.py rename to AppWindows.py index b6982f3..f53daf2 100644 --- a/MyMainWindow.py +++ b/AppWindows.py @@ -1,8 +1,6 @@ # -*- coding: utf-8 -*- """ -MainWindow class for the "Hollow section analysis tool" GUI - -Script defining the MainWindow class including functions for any interactive element +This module containes all the application window classes for the "Hollow section analysis tool" GUI History log: Version 0.1 - first working build based on UI from Qt Designer @@ -25,15 +23,19 @@ import Material import Results import Geometry -#import TableInterface import pickle +#import TableInterface -class MyMainWindow(QtWidgets.QMainWindow, design.Ui_MainWindow): # PyQt5 compatible +class HollowRCWindow(QtWidgets.QMainWindow, design.Ui_MainWindow): # PyQt5 compatible def __init__(self): super().__init__() # initialize the QMainWindow parent object from the Qt Designer file self.setupUi(self) # setup layout and widgets defined in design.py by Qt Designer #self.geometry_table = TableInterface.MyTable(self.coordinates_tableWidget) + # version tag and label + self.tag = 'v1.1' + self.label_version.setText(self.tag) + # --- Triggers --- (interactive elements such as actions and buttons with a custom function) self.exitAct.triggered.connect(self.exit_app) self.saveAct.triggered.connect(self.save_file) @@ -83,6 +85,11 @@ def __init__(self): viewStatusAct.setChecked(True) viewStatusAct.triggered.connect(self.toggle_menu) viewMenu.addAction(viewStatusAct) + + aboutMenu = self.menuBar().addMenu('About') + aboutVersionAct = QtWidgets.QAction('Check version', self) + aboutVersionAct.triggered.connect(self.version_check) + aboutMenu.addAction(aboutVersionAct) # Correcting QT Designer bug sometimes making table headers invisible self.coordinates_tableWidget.horizontalHeader().setVisible(True) # show horizontal header in Geometry table @@ -100,6 +107,9 @@ def __init__(self): # make sure to start at first tab (overrules Qt designer) self.tabWidget.setCurrentIndex(0) + # check if version is up-to-date + # self.version_check() + def tab_changed(self): # signal function if self.checkBox_analSLS_1.isChecked(): self.pushButton_analyse.setText('Analyse SLS') @@ -127,10 +137,6 @@ def refresh_plots(self): # signal/normal function except: None - def not_yet_implemented_popup(self): - msg_string = 'This feature has not yet men implemented' - self.show_msg_box(msg_string) - def save_file(self): try: # try to save file openfile = QtWidgets.QFileDialog.getSaveFileName(filter='*.pkj') # save file dialog @@ -167,21 +173,24 @@ def load_file(self): print(e) self.show_msg_box('Failed to open file') - def show_msg_box(self, info_str): + def show_msg_box(self, msg_str, title="Error Message", set_load_fac_label=False): msg = QtWidgets.QMessageBox() msg.setIcon(QtWidgets.QMessageBox.Information) - msg.setWindowTitle("Error Message") - if isinstance(info_str, str): - msg.setText(info_str) - self.load_fac_label.setText(info_str) - elif isinstance(info_str, list): - msg.setText(info_str[0]) - print(info_str) - self.load_fac_label.setText(info_str[0]) - if len(info_str) > 1: - msg.setInformativeText(info_str[1]) - self.load_fac_label.setText(info_str[0]+' '+info_str[1]) + msg.setWindowTitle(title) + if isinstance(msg_str, str): + msg.setText(msg_str) + if set_load_fac_label: + self.load_fac_label.setText(msg_str) + elif isinstance(msg_str, list): # if a list + msg.setText(msg_str[0]) # set text in msg box + print(msg_str) + if set_load_fac_label: + self.load_fac_label.setText(msg_str[0]) # update label + if len(msg_str) > 1: + msg.setInformativeText(msg_str[1]) # set info text + if set_load_fac_label: + self.load_fac_label.setText(msg_str[0] + ' ' + msg_str[1]) # msg.setDetailedText("The details are as follows: ") msg.setStandardButtons(QtWidgets.QMessageBox.Ok) @@ -202,6 +211,13 @@ def initiate_analysis(self): SF = self.getSF() Mat = self.getMaterial() + # check if geometry is valid + if not section.valid(): + self.show_msg_box(['Geometry error', 'The defined geometry is not valid']) + self.Res = None + self.refresh_plots() + return + # print(Geometry) print('SF: ' + SF.print_str()) @@ -224,7 +240,7 @@ def initiate_analysis(self): # Show message if error_msg: - self.show_msg_box(error_msg) + self.show_msg_box(error_msg, set_load_fac_label=True) else: self.load_fac_label.setText('No load-factor currently applied') @@ -809,6 +825,32 @@ def closeEvent(self, event): # reimplementing the QWidget closeEvent() event ha else: event.ignore() + def version_check(self): + # This method retreivings the latest release version from GitHub + import requests + r = requests.get('https://api.github.com/repos/Kleissl/HollowRC/releases/latest') + # print(r) + if r.status_code == 200: + # print(r.headers['content-type']) + data = r.json() + # print(data.keys()) + # for key in data: + # print(key, 'corresponds to', data[key]) + latest_tag = data['tag_name'] + published = data['published_at'] + print('The latest release (' + latest_tag +') was published at ' + published) + if latest_tag == self.tag: + print('version up-to-date') + msg_str = 'version up-to-date' + msg_info_str = 'The current version ('+ self.tag +') matches the latest release' + else: + msg_str = 'The application ('+ self.tag +') is NOT up-to-date!' + msg_info_str = 'There is a newer release (' + latest_tag + ') from ' + published + ' available for download at https://github.com/Kleissl/HollowRC/releases/latest' + print(msg_str) + self.show_msg_box([msg_str, msg_info_str], title='Information') + else: + print('Github API requests returned statuscode', r.status_code) + # # Creating my own GraphicsScene class so I can overwrite its mousePressEvent # class MyGraphicsScene(QtWidgets.QGraphicsScene): # def __init__(self, parent=None): diff --git a/Geometry.py b/Geometry.py index 7c038ba..1bc4c67 100644 --- a/Geometry.py +++ b/Geometry.py @@ -133,6 +133,20 @@ def get_e(self, local_data=False): else: return e + def valid(self): + for T in self.get_thick(): + if T <= 0: + print('Negative or zero wall thickness!') + return False + for L in self.get_wallLength(): + if L <= 0: + print('Negative or zero wall length!') + return False + if self.get_enclosed_area() > 0: # note that the correct clockwise definition yields a negative enclosed area + print('Counter-clockwise definition of cross-section!') + return False + return True + # Second Moment of Area #Ix.append(wallLength[i]*T[i]/12 * ( wallLength[i]**2 * math.cos(wallAngle[i])**2 + T[i]**2 * math.sin(wallAngle[i])**2 )) #Ix.append(wallLength[i] * T[i] / 12 * ( diff --git a/convert_ui.bat b/convert_ui.bat index 40ecd8a..6997680 100644 --- a/convert_ui.bat +++ b/convert_ui.bat @@ -1,4 +1,5 @@ "C:\Users\Kenneth\Anaconda3\Library\bin\pyside2-uic.bat" -x design.ui -o design.py "C:\Users\kekl\Anaconda3\Library\bin\pyside2-uic.bat" -x design.ui -o design.py "C:\Program Files (x86)\Python37-32\Scripts\pyside2-uic.exe" -x design.ui -o design.py +"C:\Users\kekl\AppData\Local\Programs\Python\Python37-32\Scripts\pyside2-uic.exe" -x design.ui -o design.py pause diff --git a/design.py b/design.py index 73df284..30db39d 100644 --- a/design.py +++ b/design.py @@ -3,7 +3,7 @@ # Form implementation generated from reading ui file 'design.ui', # licensing of 'design.ui' applies. # -# Created: Tue Nov 6 21:55:00 2018 +# Created: Thu Jan 17 20:10:14 2019 # by: pyside2-uic running on PySide2 5.11.2 # # WARNING! All changes made in this file will be lost! @@ -74,7 +74,7 @@ def setupUi(self, MainWindow): self.label_31.setWordWrap(True) self.label_31.setObjectName("label_31") self.label_33 = QtWidgets.QLabel(self.tab) - self.label_33.setGeometry(QtCore.QRect(10, 10, 751, 31)) + self.label_33.setGeometry(QtCore.QRect(10, 10, 521, 31)) font = QtGui.QFont() font.setPointSize(12) font.setWeight(75) @@ -99,6 +99,13 @@ def setupUi(self, MainWindow): self.label_38 = QtWidgets.QLabel(self.tab) self.label_38.setGeometry(QtCore.QRect(930, 450, 111, 101)) self.label_38.setObjectName("label_38") + self.label_version = QtWidgets.QLabel(self.tab) + self.label_version.setGeometry(QtCore.QRect(20, 630, 61, 31)) + font = QtGui.QFont() + font.setPointSize(9) + font.setItalic(True) + self.label_version.setFont(font) + self.label_version.setObjectName("label_version") self.tabWidget.addTab(self.tab, "") self.tab_geometry = QtWidgets.QWidget() self.tab_geometry.setObjectName("tab_geometry") @@ -731,6 +738,7 @@ def retranslateUi(self, MainWindow): self.label_36.setText(QtWidgets.QApplication.translate("MainWindow", "

", None, -1)) self.label_37.setText(QtWidgets.QApplication.translate("MainWindow", "

", None, -1)) self.label_38.setText(QtWidgets.QApplication.translate("MainWindow", "

", None, -1)) + self.label_version.setText(QtWidgets.QApplication.translate("MainWindow", "v1.0", None, -1)) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), QtWidgets.QApplication.translate("MainWindow", "About", None, -1)) self.label.setText(QtWidgets.QApplication.translate("MainWindow", "Define starting coordinates and properties of each wall element here:", None, -1)) self.coordinates_tableWidget.setSortingEnabled(False) @@ -746,24 +754,24 @@ def retranslateUi(self, MainWindow): __sortingEnabled = self.coordinates_tableWidget.isSortingEnabled() self.coordinates_tableWidget.setSortingEnabled(False) self.coordinates_tableWidget.item(0, 0).setText(QtWidgets.QApplication.translate("MainWindow", "0", None, -1)) - self.coordinates_tableWidget.item(0, 1).setText(QtWidgets.QApplication.translate("MainWindow", "2250", None, -1)) - self.coordinates_tableWidget.item(0, 2).setText(QtWidgets.QApplication.translate("MainWindow", "400", None, -1)) - self.coordinates_tableWidget.item(0, 3).setText(QtWidgets.QApplication.translate("MainWindow", "0.013", None, -1)) + self.coordinates_tableWidget.item(0, 1).setText(QtWidgets.QApplication.translate("MainWindow", "2000", None, -1)) + self.coordinates_tableWidget.item(0, 2).setText(QtWidgets.QApplication.translate("MainWindow", "300", None, -1)) + self.coordinates_tableWidget.item(0, 3).setText(QtWidgets.QApplication.translate("MainWindow", "0.01", None, -1)) self.coordinates_tableWidget.item(0, 4).setText(QtWidgets.QApplication.translate("MainWindow", "0.01", None, -1)) - self.coordinates_tableWidget.item(1, 0).setText(QtWidgets.QApplication.translate("MainWindow", "4000", None, -1)) - self.coordinates_tableWidget.item(1, 1).setText(QtWidgets.QApplication.translate("MainWindow", "2250", None, -1)) - self.coordinates_tableWidget.item(1, 2).setText(QtWidgets.QApplication.translate("MainWindow", "400", None, -1)) - self.coordinates_tableWidget.item(1, 3).setText(QtWidgets.QApplication.translate("MainWindow", "0.013", None, -1)) + self.coordinates_tableWidget.item(1, 0).setText(QtWidgets.QApplication.translate("MainWindow", "1500", None, -1)) + self.coordinates_tableWidget.item(1, 1).setText(QtWidgets.QApplication.translate("MainWindow", "2000", None, -1)) + self.coordinates_tableWidget.item(1, 2).setText(QtWidgets.QApplication.translate("MainWindow", "200", None, -1)) + self.coordinates_tableWidget.item(1, 3).setText(QtWidgets.QApplication.translate("MainWindow", "0.01", None, -1)) self.coordinates_tableWidget.item(1, 4).setText(QtWidgets.QApplication.translate("MainWindow", "0.01", None, -1)) - self.coordinates_tableWidget.item(2, 0).setText(QtWidgets.QApplication.translate("MainWindow", "4000", None, -1)) + self.coordinates_tableWidget.item(2, 0).setText(QtWidgets.QApplication.translate("MainWindow", "1500", None, -1)) self.coordinates_tableWidget.item(2, 1).setText(QtWidgets.QApplication.translate("MainWindow", "0", None, -1)) - self.coordinates_tableWidget.item(2, 2).setText(QtWidgets.QApplication.translate("MainWindow", "400", None, -1)) - self.coordinates_tableWidget.item(2, 3).setText(QtWidgets.QApplication.translate("MainWindow", "0.013", None, -1)) + self.coordinates_tableWidget.item(2, 2).setText(QtWidgets.QApplication.translate("MainWindow", "300", None, -1)) + self.coordinates_tableWidget.item(2, 3).setText(QtWidgets.QApplication.translate("MainWindow", "0.01", None, -1)) self.coordinates_tableWidget.item(2, 4).setText(QtWidgets.QApplication.translate("MainWindow", "0.01", None, -1)) self.coordinates_tableWidget.item(3, 0).setText(QtWidgets.QApplication.translate("MainWindow", "0", None, -1)) self.coordinates_tableWidget.item(3, 1).setText(QtWidgets.QApplication.translate("MainWindow", "0", None, -1)) - self.coordinates_tableWidget.item(3, 2).setText(QtWidgets.QApplication.translate("MainWindow", "400", None, -1)) - self.coordinates_tableWidget.item(3, 3).setText(QtWidgets.QApplication.translate("MainWindow", "0.013", None, -1)) + self.coordinates_tableWidget.item(3, 2).setText(QtWidgets.QApplication.translate("MainWindow", "200", None, -1)) + self.coordinates_tableWidget.item(3, 3).setText(QtWidgets.QApplication.translate("MainWindow", "0.01", None, -1)) self.coordinates_tableWidget.item(3, 4).setText(QtWidgets.QApplication.translate("MainWindow", "0.01", None, -1)) self.coordinates_tableWidget.setSortingEnabled(__sortingEnabled) self.addRowButton.setToolTip(QtWidgets.QApplication.translate("MainWindow", "Insert new row at the bottom", None, -1)) @@ -820,11 +828,11 @@ def retranslateUi(self, MainWindow): self.SectionForces_tableWidget.horizontalHeaderItem(5).setText(QtWidgets.QApplication.translate("MainWindow", "T [kNm]", None, -1)) __sortingEnabled = self.SectionForces_tableWidget.isSortingEnabled() self.SectionForces_tableWidget.setSortingEnabled(False) - self.SectionForces_tableWidget.item(0, 0).setText(QtWidgets.QApplication.translate("MainWindow", "-38000", None, -1)) - self.SectionForces_tableWidget.item(0, 1).setText(QtWidgets.QApplication.translate("MainWindow", "0", None, -1)) - self.SectionForces_tableWidget.item(0, 2).setText(QtWidgets.QApplication.translate("MainWindow", "50000", None, -1)) - self.SectionForces_tableWidget.item(0, 3).setText(QtWidgets.QApplication.translate("MainWindow", "5000", None, -1)) - self.SectionForces_tableWidget.item(0, 4).setText(QtWidgets.QApplication.translate("MainWindow", "0", None, -1)) + self.SectionForces_tableWidget.item(0, 0).setText(QtWidgets.QApplication.translate("MainWindow", "-15000", None, -1)) + self.SectionForces_tableWidget.item(0, 1).setText(QtWidgets.QApplication.translate("MainWindow", "20000", None, -1)) + self.SectionForces_tableWidget.item(0, 2).setText(QtWidgets.QApplication.translate("MainWindow", "0", None, -1)) + self.SectionForces_tableWidget.item(0, 3).setText(QtWidgets.QApplication.translate("MainWindow", "0", None, -1)) + self.SectionForces_tableWidget.item(0, 4).setText(QtWidgets.QApplication.translate("MainWindow", "5000", None, -1)) self.SectionForces_tableWidget.item(0, 5).setText(QtWidgets.QApplication.translate("MainWindow", "0", None, -1)) self.SectionForces_tableWidget.setSortingEnabled(__sortingEnabled) self.load_fac_label.setText(QtWidgets.QApplication.translate("MainWindow", "No load-factor currently applied", None, -1)) diff --git a/design.ui b/design.ui index 5cd5af0..078c814 100644 --- a/design.ui +++ b/design.ui @@ -23,7 +23,7 @@ - 2 + 0 @@ -168,7 +168,7 @@ 10 10 - 751 + 521 31 @@ -243,6 +243,25 @@ <html><head/><body><p><img src=":/Figures/moment_sign_convention.PNG"/></p></body></html> + + + + 20 + 630 + 61 + 31 + + + + + 9 + true + + + + v1.0 + + @@ -401,17 +420,17 @@ - 2250 + 2000 - 400 + 300 - 0.013 + 0.01 @@ -421,22 +440,22 @@ - 4000 + 1500 - 2250 + 2000 - 400 + 200 - 0.013 + 0.01 @@ -446,7 +465,7 @@ - 4000 + 1500 @@ -456,12 +475,12 @@ - 400 + 300 - 0.013 + 0.01 @@ -481,12 +500,12 @@ - 400 + 200 - 0.013 + 0.01 @@ -1289,27 +1308,27 @@ - -38000 + -15000 - 0 + 20000 - 50000 + 0 - 5000 + 0 - 0 + 5000 diff --git a/main.py b/main.py index c0046a3..f4d2c7f 100644 --- a/main.py +++ b/main.py @@ -16,7 +16,7 @@ # Third-party library modules from PySide2 import QtWidgets # Local source tree modules -from MyMainWindow import MyMainWindow # import the MainWindow class +from AppWindows import HollowRCWindow # import the MainWindow class def main(): @@ -24,7 +24,7 @@ def main(): app = QtWidgets.QApplication(sys.argv) # PyQT5 compatible # The QWidget widget is the base class of all user interface objects in PyQt4. - window = MyMainWindow() # We set the form to be our ExampleApp (design) + window = HollowRCWindow() # We set the form to be our ExampleApp (design) window.show() # Show the window/form # Exception handling