From 0f712116023eea2ce6094a33bbfb85719eb73d66 Mon Sep 17 00:00:00 2001 From: Przemo Firszt Date: Fri, 9 Oct 2015 12:35:24 +0100 Subject: [PATCH] FEM: Move _JobControlTaskPanel class to separate file Signed-off-by: Przemo Firszt --- src/Mod/Fem/App/CMakeLists.txt | 1 + src/Mod/Fem/CMakeLists.txt | 1 + src/Mod/Fem/MechanicalAnalysis.py | 216 +-------------------------- src/Mod/Fem/_JobControlTaskPanel.py | 217 ++++++++++++++++++++++++++++ 4 files changed, 223 insertions(+), 212 deletions(-) create mode 100644 src/Mod/Fem/_JobControlTaskPanel.py diff --git a/src/Mod/Fem/App/CMakeLists.txt b/src/Mod/Fem/App/CMakeLists.txt index f81e27ed8..0b90e1748 100755 --- a/src/Mod/Fem/App/CMakeLists.txt +++ b/src/Mod/Fem/App/CMakeLists.txt @@ -83,6 +83,7 @@ SET(FemScripts_SRCS MechanicalMaterial.py ShowDisplacement.ui _ResultControlTaskPanel.py + _JobControlTaskPanel.py ) #SOURCE_GROUP("Scripts" FILES ${FemScripts_SRCS}) diff --git a/src/Mod/Fem/CMakeLists.txt b/src/Mod/Fem/CMakeLists.txt index d2c4ef75a..5edbf56b3 100755 --- a/src/Mod/Fem/CMakeLists.txt +++ b/src/Mod/Fem/CMakeLists.txt @@ -25,6 +25,7 @@ INSTALL( MechanicalAnalysis.ui ShowDisplacement.ui _ResultControlTaskPanel.py + _JobControlTaskPanel.py DESTINATION Mod/Fem ) diff --git a/src/Mod/Fem/MechanicalAnalysis.py b/src/Mod/Fem/MechanicalAnalysis.py index 94dca5204..d8be50e44 100644 --- a/src/Mod/Fem/MechanicalAnalysis.py +++ b/src/Mod/Fem/MechanicalAnalysis.py @@ -20,18 +20,13 @@ #* * #*************************************************************************** -import ccxFrdReader import FreeCAD from FemTools import FemTools -import os -import time if FreeCAD.GuiUp: import FreeCADGui import FemGui from PySide import QtCore, QtGui - from PySide.QtCore import Qt - from PySide.QtGui import QApplication __title__ = "Mechanical Analysis managment" __author__ = "Juergen Riegel" @@ -117,7 +112,8 @@ class _CommandMechanicalJobControl: 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Fem_JobControl", "Dialog to start the calculation of the mechanical anlysis")} def Activated(self): - taskd = _JobControlTaskPanel(FemGui.getActiveAnalysis()) + import _JobControlTaskPanel + taskd = _JobControlTaskPanel._JobControlTaskPanel(FemGui.getActiveAnalysis()) #taskd.obj = vobj.Object taskd.update() FreeCADGui.Control.showDialog(taskd) @@ -277,7 +273,8 @@ class _ViewProviderFemAnalysis: FemGui.setActiveAnalysis(self.Object) return True else: - taskd = _JobControlTaskPanel(self.Object) + import _JobControlTaskPanel + taskd = _JobControlTaskPanel._JobControlTaskPanel(self.Object) FreeCADGui.Control.showDialog(taskd) return True @@ -288,211 +285,6 @@ class _ViewProviderFemAnalysis: return None -class _JobControlTaskPanel: - def __init__(self, analysis_object): - self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Fem/MechanicalAnalysis.ui") - self.fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem") - ccx_binary = self.fem_prefs.GetString("ccxBinaryPath", "") - if ccx_binary: - self.CalculixBinary = ccx_binary - print "Using ccx binary path from FEM preferences: {}".format(ccx_binary) - else: - from platform import system - if system() == 'Linux': - self.CalculixBinary = 'ccx' - elif system() == 'Windows': - self.CalculixBinary = FreeCAD.getHomePath() + 'bin/ccx.exe' - else: - self.CalculixBinary = 'ccx' - self.fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem") - self.working_dir = self.fem_prefs.GetString("WorkingDir", '/tmp') - - self.analysis_object = analysis_object - self.Calculix = QtCore.QProcess() - self.Timer = QtCore.QTimer() - self.Timer.start(300) - - self.fem_console_message = '' - - #Connect Signals and Slots - QtCore.QObject.connect(self.form.tb_choose_working_dir, QtCore.SIGNAL("clicked()"), self.choose_working_dir) - QtCore.QObject.connect(self.form.pushButton_write, QtCore.SIGNAL("clicked()"), self.write_input_file_handler) - QtCore.QObject.connect(self.form.pushButton_edit, QtCore.SIGNAL("clicked()"), self.editCalculixInputFile) - QtCore.QObject.connect(self.form.pushButton_generate, QtCore.SIGNAL("clicked()"), self.runCalculix) - - QtCore.QObject.connect(self.Calculix, QtCore.SIGNAL("started()"), self.calculixStarted) - QtCore.QObject.connect(self.Calculix, QtCore.SIGNAL("stateChanged(QProcess::ProcessState)"), self.calculixStateChanged) - QtCore.QObject.connect(self.Calculix, QtCore.SIGNAL("error(QProcess::ProcessError)"), self.calculixError) - QtCore.QObject.connect(self.Calculix, QtCore.SIGNAL("finished(int)"), self.calculixFinished) - - QtCore.QObject.connect(self.Timer, QtCore.SIGNAL("timeout()"), self.UpdateText) - - self.update() - - def femConsoleMessage(self, message="", color="#000000"): - self.fem_console_message = self.fem_console_message + '{0:4.1f}: {2}
'.\ - format(time.time() - self.Start, color, message.encode('utf-8', 'replace')) - self.form.textEdit_Output.setText(self.fem_console_message) - self.form.textEdit_Output.moveCursor(QtGui.QTextCursor.End) - - def printCalculiXstdout(self): - out = self.Calculix.readAllStandardOutput() - if out.isEmpty(): - self.femConsoleMessage("CalculiX stdout is empty", "#FF0000") - else: - try: - out = unicode(out, 'utf-8', 'replace') - rx = QtCore.QRegExp("\\*ERROR.*\\n\\n") - rx.setMinimal(True) - pos = rx.indexIn(out) - while not pos < 0: - match = rx.cap(0) - FreeCAD.Console.PrintError(match.strip().replace('\n', ' ') + '\n') - pos = rx.indexIn(out, pos + 1) - out = os.linesep.join([s for s in out.splitlines() if s]) - self.femConsoleMessage(out.replace('\n', '
')) - except UnicodeDecodeError: - self.femConsoleMessage("Error converting stdout from CalculiX", "#FF0000") - - def UpdateText(self): - if(self.Calculix.state() == QtCore.QProcess.ProcessState.Running): - self.form.label_Time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start)) - - def calculixError(self, error): - print "Error()", error - self.femConsoleMessage("CalculiX execute error: {}".format(error), "#FF0000") - - def calculixStarted(self): - print "calculixStarted()" - print self.Calculix.state() - self.form.pushButton_generate.setText("Break Calculix") - - def calculixStateChanged(self, newState): - if (newState == QtCore.QProcess.ProcessState.Starting): - self.femConsoleMessage("Starting CalculiX...") - if (newState == QtCore.QProcess.ProcessState.Running): - self.femConsoleMessage("CalculiX is running...") - if (newState == QtCore.QProcess.ProcessState.NotRunning): - self.femConsoleMessage("CalculiX stopped.") - - def calculixFinished(self, exitCode): - print "calculixFinished()", exitCode - print self.Calculix.state() - - # Restore previous cwd - QtCore.QDir.setCurrent(self.cwd) - - self.printCalculiXstdout() - self.Timer.stop() - - self.femConsoleMessage("Calculix done!", "#00AA00") - - self.form.pushButton_generate.setText("Re-run Calculix") - print "Loading results...." - self.femConsoleMessage("Loading result sets...") - self.form.label_Time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start)) - fea = FemTools() - fea.reset_all() - frd_result_file = os.path.splitext(self.inp_file_name)[0] + '.frd' - if os.path.isfile(frd_result_file): - QApplication.setOverrideCursor(Qt.WaitCursor) - ccxFrdReader.importFrd(frd_result_file, FemGui.getActiveAnalysis()) - QApplication.restoreOverrideCursor() - self.femConsoleMessage("Loading results done!", "#00AA00") - else: - self.femConsoleMessage("Loading results failed! Results file doesn\'t exist", "#FF0000") - self.form.label_Time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start)) - - def getStandardButtons(self): - return int(QtGui.QDialogButtonBox.Close) - - def update(self): - 'fills the widgets' - self.form.le_working_dir.setText(self.working_dir) - return - - def accept(self): - FreeCADGui.Control.closeDialog() - - def reject(self): - FreeCADGui.Control.closeDialog() - - def choose_working_dir(self): - self.fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem") - self.working_dir = QtGui.QFileDialog.getExistingDirectory(None, - 'Choose CalculiX working directory', - self.fem_prefs.GetString("WorkingDir", '/tmp')) - if self.working_dir: - self.fem_prefs.SetString("WorkingDir", str(self.working_dir)) - self.form.le_working_dir.setText(self.working_dir) - - def write_input_file_handler(self): - QApplication.restoreOverrideCursor() - if self.check_prerequisites_helper(): - QApplication.setOverrideCursor(Qt.WaitCursor) - self.inp_file_name = "" - fea = FemTools() - fea.update_objects() - fea.write_inp_file() - if fea.inp_file_name != "": - self.inp_file_name = fea.inp_file_name - self.femConsoleMessage("Write completed.") - self.form.pushButton_edit.setEnabled(True) - self.form.pushButton_generate.setEnabled(True) - else: - self.femConsoleMessage("Write .inp file failed!", "#FF0000") - QApplication.restoreOverrideCursor() - - def check_prerequisites_helper(self): - self.Start = time.time() - self.femConsoleMessage("Check dependencies...") - self.form.label_Time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start)) - - fea = FemTools() - fea.update_objects() - message = fea.check_prerequisites() - if message != "": - QtGui.QMessageBox.critical(None, "Missing prerequisit(s)", message) - return False - return True - - def start_ext_editor(self, ext_editor_path, filename): - if not hasattr(self, "ext_editor_process"): - self.ext_editor_process = QtCore.QProcess() - if self.ext_editor_process.state() != QtCore.QProcess.Running: - self.ext_editor_process.start(ext_editor_path, [filename]) - - def editCalculixInputFile(self): - print 'editCalculixInputFile {}'.format(self.inp_file_name) - if self.fem_prefs.GetBool("UseInternalEditor", True): - FemGui.open(self.inp_file_name) - else: - ext_editor_path = self.fem_prefs.GetString("ExternalEditorPath", "") - if ext_editor_path: - self.start_ext_editor(ext_editor_path, self.inp_file_name) - else: - print "External editor is not defined in FEM preferences. Falling back to internal editor" - FemGui.open(self.inp_file_name) - - def runCalculix(self): - print 'runCalculix' - self.Start = time.time() - - self.femConsoleMessage("CalculiX binary: {}".format(self.CalculixBinary)) - self.femConsoleMessage("Run Calculix...") - - # run Calculix - print 'run Calculix at: ', self.CalculixBinary, ' with: ', os.path.splitext(self.inp_file_name)[0] - # change cwd because ccx may crash if directory has no write permission - # there is also a limit of the length of file names so jump to the document directory - self.cwd = QtCore.QDir.currentPath() - fi = QtCore.QFileInfo(self.inp_file_name) - QtCore.QDir.setCurrent(fi.path()) - self.Calculix.start(self.CalculixBinary, ['-i', fi.baseName()]) - - QApplication.restoreOverrideCursor() - - # Helpers diff --git a/src/Mod/Fem/_JobControlTaskPanel.py b/src/Mod/Fem/_JobControlTaskPanel.py new file mode 100644 index 000000000..735ec70be --- /dev/null +++ b/src/Mod/Fem/_JobControlTaskPanel.py @@ -0,0 +1,217 @@ +from FemTools import FemTools +import FreeCAD +import ccxFrdReader +import os +import time + +if FreeCAD.GuiUp: + import FreeCADGui + import FemGui + from PySide import QtCore, QtGui + from PySide.QtCore import Qt + from PySide.QtGui import QApplication + + +class _JobControlTaskPanel: + def __init__(self, analysis_object): + self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Fem/MechanicalAnalysis.ui") + self.fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem") + ccx_binary = self.fem_prefs.GetString("ccxBinaryPath", "") + if ccx_binary: + self.CalculixBinary = ccx_binary + print "Using ccx binary path from FEM preferences: {}".format(ccx_binary) + else: + from platform import system + if system() == 'Linux': + self.CalculixBinary = 'ccx' + elif system() == 'Windows': + self.CalculixBinary = FreeCAD.getHomePath() + 'bin/ccx.exe' + else: + self.CalculixBinary = 'ccx' + self.fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem") + self.working_dir = self.fem_prefs.GetString("WorkingDir", '/tmp') + + self.analysis_object = analysis_object + self.Calculix = QtCore.QProcess() + self.Timer = QtCore.QTimer() + self.Timer.start(300) + + self.fem_console_message = '' + + #Connect Signals and Slots + QtCore.QObject.connect(self.form.tb_choose_working_dir, QtCore.SIGNAL("clicked()"), self.choose_working_dir) + QtCore.QObject.connect(self.form.pushButton_write, QtCore.SIGNAL("clicked()"), self.write_input_file_handler) + QtCore.QObject.connect(self.form.pushButton_edit, QtCore.SIGNAL("clicked()"), self.editCalculixInputFile) + QtCore.QObject.connect(self.form.pushButton_generate, QtCore.SIGNAL("clicked()"), self.runCalculix) + + QtCore.QObject.connect(self.Calculix, QtCore.SIGNAL("started()"), self.calculixStarted) + QtCore.QObject.connect(self.Calculix, QtCore.SIGNAL("stateChanged(QProcess::ProcessState)"), self.calculixStateChanged) + QtCore.QObject.connect(self.Calculix, QtCore.SIGNAL("error(QProcess::ProcessError)"), self.calculixError) + QtCore.QObject.connect(self.Calculix, QtCore.SIGNAL("finished(int)"), self.calculixFinished) + + QtCore.QObject.connect(self.Timer, QtCore.SIGNAL("timeout()"), self.UpdateText) + + self.update() + + def femConsoleMessage(self, message="", color="#000000"): + self.fem_console_message = self.fem_console_message + '{0:4.1f}: {2}
'.\ + format(time.time() - self.Start, color, message.encode('utf-8', 'replace')) + self.form.textEdit_Output.setText(self.fem_console_message) + self.form.textEdit_Output.moveCursor(QtGui.QTextCursor.End) + + def printCalculiXstdout(self): + out = self.Calculix.readAllStandardOutput() + if out.isEmpty(): + self.femConsoleMessage("CalculiX stdout is empty", "#FF0000") + else: + try: + out = unicode(out, 'utf-8', 'replace') + rx = QtCore.QRegExp("\\*ERROR.*\\n\\n") + rx.setMinimal(True) + pos = rx.indexIn(out) + while not pos < 0: + match = rx.cap(0) + FreeCAD.Console.PrintError(match.strip().replace('\n', ' ') + '\n') + pos = rx.indexIn(out, pos + 1) + out = os.linesep.join([s for s in out.splitlines() if s]) + self.femConsoleMessage(out.replace('\n', '
')) + except UnicodeDecodeError: + self.femConsoleMessage("Error converting stdout from CalculiX", "#FF0000") + + def UpdateText(self): + if(self.Calculix.state() == QtCore.QProcess.ProcessState.Running): + self.form.label_Time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start)) + + def calculixError(self, error): + print "Error()", error + self.femConsoleMessage("CalculiX execute error: {}".format(error), "#FF0000") + + def calculixStarted(self): + print "calculixStarted()" + print self.Calculix.state() + self.form.pushButton_generate.setText("Break Calculix") + + def calculixStateChanged(self, newState): + if (newState == QtCore.QProcess.ProcessState.Starting): + self.femConsoleMessage("Starting CalculiX...") + if (newState == QtCore.QProcess.ProcessState.Running): + self.femConsoleMessage("CalculiX is running...") + if (newState == QtCore.QProcess.ProcessState.NotRunning): + self.femConsoleMessage("CalculiX stopped.") + + def calculixFinished(self, exitCode): + print "calculixFinished()", exitCode + print self.Calculix.state() + + # Restore previous cwd + QtCore.QDir.setCurrent(self.cwd) + + self.printCalculiXstdout() + self.Timer.stop() + + self.femConsoleMessage("Calculix done!", "#00AA00") + + self.form.pushButton_generate.setText("Re-run Calculix") + print "Loading results...." + self.femConsoleMessage("Loading result sets...") + self.form.label_Time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start)) + fea = FemTools() + fea.reset_all() + frd_result_file = os.path.splitext(self.inp_file_name)[0] + '.frd' + if os.path.isfile(frd_result_file): + QApplication.setOverrideCursor(Qt.WaitCursor) + ccxFrdReader.importFrd(frd_result_file, FemGui.getActiveAnalysis()) + QApplication.restoreOverrideCursor() + self.femConsoleMessage("Loading results done!", "#00AA00") + else: + self.femConsoleMessage("Loading results failed! Results file doesn\'t exist", "#FF0000") + self.form.label_Time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start)) + + def getStandardButtons(self): + return int(QtGui.QDialogButtonBox.Close) + + def update(self): + 'fills the widgets' + self.form.le_working_dir.setText(self.working_dir) + return + + def accept(self): + FreeCADGui.Control.closeDialog() + + def reject(self): + FreeCADGui.Control.closeDialog() + + def choose_working_dir(self): + self.fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem") + self.working_dir = QtGui.QFileDialog.getExistingDirectory(None, + 'Choose CalculiX working directory', + self.fem_prefs.GetString("WorkingDir", '/tmp')) + if self.working_dir: + self.fem_prefs.SetString("WorkingDir", str(self.working_dir)) + self.form.le_working_dir.setText(self.working_dir) + + def write_input_file_handler(self): + QApplication.restoreOverrideCursor() + if self.check_prerequisites_helper(): + QApplication.setOverrideCursor(Qt.WaitCursor) + self.inp_file_name = "" + fea = FemTools() + fea.update_objects() + fea.write_inp_file() + if fea.inp_file_name != "": + self.inp_file_name = fea.inp_file_name + self.femConsoleMessage("Write completed.") + self.form.pushButton_edit.setEnabled(True) + self.form.pushButton_generate.setEnabled(True) + else: + self.femConsoleMessage("Write .inp file failed!", "#FF0000") + QApplication.restoreOverrideCursor() + + def check_prerequisites_helper(self): + self.Start = time.time() + self.femConsoleMessage("Check dependencies...") + self.form.label_Time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start)) + + fea = FemTools() + fea.update_objects() + message = fea.check_prerequisites() + if message != "": + QtGui.QMessageBox.critical(None, "Missing prerequisit(s)", message) + return False + return True + + def start_ext_editor(self, ext_editor_path, filename): + if not hasattr(self, "ext_editor_process"): + self.ext_editor_process = QtCore.QProcess() + if self.ext_editor_process.state() != QtCore.QProcess.Running: + self.ext_editor_process.start(ext_editor_path, [filename]) + + def editCalculixInputFile(self): + print 'editCalculixInputFile {}'.format(self.inp_file_name) + if self.fem_prefs.GetBool("UseInternalEditor", True): + FemGui.open(self.inp_file_name) + else: + ext_editor_path = self.fem_prefs.GetString("ExternalEditorPath", "") + if ext_editor_path: + self.start_ext_editor(ext_editor_path, self.inp_file_name) + else: + print "External editor is not defined in FEM preferences. Falling back to internal editor" + FemGui.open(self.inp_file_name) + + def runCalculix(self): + print 'runCalculix' + self.Start = time.time() + + self.femConsoleMessage("CalculiX binary: {}".format(self.CalculixBinary)) + self.femConsoleMessage("Run Calculix...") + + # run Calculix + print 'run Calculix at: ', self.CalculixBinary, ' with: ', os.path.splitext(self.inp_file_name)[0] + # change cwd because ccx may crash if directory has no write permission + # there is also a limit of the length of file names so jump to the document directory + self.cwd = QtCore.QDir.currentPath() + fi = QtCore.QFileInfo(self.inp_file_name) + QtCore.QDir.setCurrent(fi.path()) + self.Calculix.start(self.CalculixBinary, ['-i', fi.baseName()]) + + QApplication.restoreOverrideCursor()