From b4630ba45d5a3c163cf67759e433028a42058a3f Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Sat, 14 May 2016 19:46:33 +0100 Subject: [PATCH] FEM: Z88: support for analysis with solver Z88 --- src/Mod/Fem/App/CMakeLists.txt | 6 + src/Mod/Fem/CMakeLists.txt | 9 + src/Mod/Fem/FemInputWriterZ88.py | 312 +++++++++++++++++++++++ src/Mod/Fem/FemSolverZ88.py | 39 +++ src/Mod/Fem/FemToolsZ88.py | 172 +++++++++++++ src/Mod/Fem/Gui/Workbench.cpp | 2 + src/Mod/Fem/InitGui.py | 1 + src/Mod/Fem/_CommandRunSolver.py | 11 + src/Mod/Fem/_CommandSolverZ88.py | 53 ++++ src/Mod/Fem/_FemSolverZ88.py | 61 +++++ src/Mod/Fem/_ViewProviderFemSolverZ88.py | 74 ++++++ 11 files changed, 740 insertions(+) create mode 100644 src/Mod/Fem/FemInputWriterZ88.py create mode 100644 src/Mod/Fem/FemSolverZ88.py create mode 100644 src/Mod/Fem/FemToolsZ88.py create mode 100644 src/Mod/Fem/_CommandSolverZ88.py create mode 100644 src/Mod/Fem/_FemSolverZ88.py create mode 100644 src/Mod/Fem/_ViewProviderFemSolverZ88.py diff --git a/src/Mod/Fem/App/CMakeLists.txt b/src/Mod/Fem/App/CMakeLists.txt index 322256202..5b90a508a 100755 --- a/src/Mod/Fem/App/CMakeLists.txt +++ b/src/Mod/Fem/App/CMakeLists.txt @@ -80,10 +80,12 @@ SET(FemScripts_SRCS _CommandRunSolver.py _CommandShellThickness.py _CommandSolverCalculix.py + _CommandSolverZ88.py _FemAnalysis.py _FemBeamSection.py _FemShellThickness.py _FemSolverCalculix.py + _FemSolverZ88.py _MechanicalMaterial.py _TaskPanelFemBeamSection.py _TaskPanelFemShellThickness.py @@ -94,6 +96,7 @@ SET(FemScripts_SRCS _ViewProviderFemBeamSection.py _ViewProviderFemShellThickness.py _ViewProviderFemSolverCalculix.py + _ViewProviderFemSolverZ88.py _ViewProviderMechanicalMaterial.py ccxDatReader.py ccxFrdReader.py @@ -106,11 +109,14 @@ SET(FemScripts_SRCS FemBeamSection.py FemInputWriter.py FemInputWriterCcx.py + FemInputWriterZ88.py FemMeshTools.py FemShellThickness.py FemSolverCalculix.py + FemSolverZ88.py FemTools.py FemToolsCcx.py + FemToolsZ88.py MechanicalMaterial.py FemSelectionObserver.py TestFem.py diff --git a/src/Mod/Fem/CMakeLists.txt b/src/Mod/Fem/CMakeLists.txt index 83aff94d6..4fda50380 100755 --- a/src/Mod/Fem/CMakeLists.txt +++ b/src/Mod/Fem/CMakeLists.txt @@ -67,7 +67,16 @@ INSTALL( _TaskPanelFemSolverCalculix.py TaskPanelFemSolverCalculix.ui + # solver Z88 importZ88Mesh.py + FemInputWriterZ88.py + FemToolsZ88.py + FemSolverZ88.py + _FemSolverZ88.py + _ViewProviderFemSolverZ88.py + _CommandSolverZ88.py + _TaskPanelFemSolverZ88.py + TaskPanelFemSolverZ88.ui DESTINATION Mod/Fem diff --git a/src/Mod/Fem/FemInputWriterZ88.py b/src/Mod/Fem/FemInputWriterZ88.py new file mode 100644 index 000000000..807f52036 --- /dev/null +++ b/src/Mod/Fem/FemInputWriterZ88.py @@ -0,0 +1,312 @@ +# *************************************************************************** +# * * +# * Copyright (c) 2016 - Bernd Hahnebach * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + + +__title__ = "FemInputWriterZ88" +__author__ = "Bernd Hahnebach" +__url__ = "http://www.freecadweb.org" + + +import FreeCAD +import FemMeshTools +import importZ88Mesh +import FemInputWriter + + +class FemInputWriterZ88(FemInputWriter.FemInputWriter): + def __init__(self, analysis_obj, mesh_obj, mat_obj, + fixed_obj, + force_obj, pressure_obj, + displacement_obj, + beamsection_obj, shellthickness_obj, + analysis_type=None, eigenmode_parameters=None, + dir_name=None): + FemInputWriter.FemInputWriter.__init__(self, analysis_obj, mesh_obj, mat_obj, + fixed_obj, + force_obj, pressure_obj, + displacement_obj, + beamsection_obj, shellthickness_obj, + analysis_type, eigenmode_parameters, + dir_name) + self.file_name = self.dir_name + '/z88' + print('FemInputWriterZ88 --> self.dir_name --> ' + self.dir_name) + print('FemInputWriterZ88 --> self.file_name --> ' + self.file_name) + + def write_z88_input(self): + if not self.femnodes_mesh: + self.femnodes_mesh = self.femmesh.Nodes + if not self.femelement_table: + self.femelement_table = FemMeshTools.get_femelement_table(self.femmesh) + self.element_count = len(self.femelement_table) + self.set_z88_elparam() + self.write_z88_mesh() + self.write_z88_contraints() + self.write_z88_face_loads() + self.write_z88_materials() + self.write_z88_elements_properties() + self.write_z88_integration_properties() + self.write_z88_memory_parameter() + self.write_z88_solver_parameter() + return self.dir_name + + def set_z88_elparam(self): + # TODO: z88_param should be moved to the solver object like the known analysis + z8804 = {'INTORD': '0', 'INTOS': '0', 'IHFLAG': '0', 'ISFLAG': '1'} # seg2 --> stab4 + z8824 = {'INTORD': '7', 'INTOS': '7', 'IHFLAG': '1', 'ISFLAG': '1'} # tria6 --> schale24 + z8823 = {'INTORD': '3', 'INTOS': '0', 'IHFLAG': '1', 'ISFLAG': '0'} # quad8 --> schale23 + z8817 = {'INTORD': '4', 'INTOS': '0', 'IHFLAG': '0', 'ISFLAG': '0'} # tetra4 --> volume17 + z8816 = {'INTORD': '4', 'INTOS': '0', 'IHFLAG': '0', 'ISFLAG': '0'} # tetra10 --> volume16 + z8801 = {'INTORD': '2', 'INTOS': '2', 'IHFLAG': '0', 'ISFLAG': '1'} # hexa8 --> volume1 + z8810 = {'INTORD': '3', 'INTOS': '0', 'IHFLAG': '0', 'ISFLAG': '0'} # hexa20 --> volume10 + z88_param = {4: z8804, 24: z8824, 23: z8823, 17: z8817, 16: z8816, 1: z8801, 10: z8810} + self.z88_param = z88_param + # elemente 17, 16, 10, INTORD etc ... testen !!! + self.z88_element_type = importZ88Mesh.get_z88_element_type(self.femmesh, self.femelement_table) + self.z88_elparam = self.z88_param[self.z88_element_type] + print(self.z88_elparam) + + def write_z88_mesh(self): + mesh_file_path = self.file_name + 'i1.txt' + f = open(mesh_file_path, 'w') + importZ88Mesh.write_z88_mesh_to_file(self.femnodes_mesh, self.femelement_table, self.z88_element_type, f) + f.close() + + def write_z88_contraints(self): + constraints_data = [] # will be a list of tuple for better sorting + + # fixed constraints + # get nodes + self.get_constraints_fixed_nodes() + # write nodes to constraints_data (different from writing to file in ccxInpWriter) + for femobj in self.fixed_objects: + for n in femobj['Nodes']: + constraints_data.append((n, str(n) + ' 1 2 0\n')) + constraints_data.append((n, str(n) + ' 2 2 0\n')) + constraints_data.append((n, str(n) + ' 3 2 0\n')) + + # forces constraints + # check shape type of reference shape and get node loads + self.get_constraints_force_nodeloads() + # write node loads to constraints_data (a bit different from writing to file for ccxInpWriter) + for femobj in self.force_objects: # femobj --> dict, FreeCAD document object is femobj['Object'] + direction_vec = femobj['Object'].DirectionVector + for ref_shape in femobj['NodeLoadTable']: + for n in sorted(ref_shape[1]): + node_load = ref_shape[1][n] + if (direction_vec.x != 0.0): + v1 = direction_vec.x * node_load + constraints_data.append((n, str(n) + ' 1 1 ' + str(v1) + '\n')) + if (direction_vec.y != 0.0): + v2 = direction_vec.y * node_load + constraints_data.append((n, str(n) + ' 2 1 ' + str(v2) + '\n')) + if (direction_vec.z != 0.0): + v3 = direction_vec.z * node_load + constraints_data.append((n, str(n) + ' 3 1 ' + str(v3) + '\n')) + + # write constraints_data to file + contraints_file_path = self.file_name + 'i2.txt' + f = open(contraints_file_path, 'w') + f.write(str(len(constraints_data)) + '\n') + for c in sorted(constraints_data): + f.write(c[1]) + f.close() + + def write_z88_face_loads(self): + # not yet supported + face_load_file_path = self.file_name + 'i5.txt' + f = open(face_load_file_path, 'w') + f.write(' 0') + f.write('\n') + f.close() + + def write_z88_materials(self): + if len(self.material_objects) == 1: + material_data_file_name = '51.txt' + materials_file_path = self.file_name + 'mat.txt' + fms = open(materials_file_path, 'w') + fms.write('1\n') + fms.write('1 ' + str(self.element_count) + ' ' + material_data_file_name) + fms.write('\n') + fms.close() + material_data_file_path = self.dir_name + '/' + material_data_file_name + fmd = open(material_data_file_path, 'w') + mat_obj = self.material_objects[0]['Object'] + YM = FreeCAD.Units.Quantity(mat_obj.Material['YoungsModulus']) + YM_in_MPa = YM.getValueAs('MPa') + PR = float(mat_obj.Material['PoissonRatio']) + fmd.write('{0} {1:.3f}'.format(YM_in_MPa, PR)) + fmd.write('\n') + fmd.close() + else: + print("Multiple Materials for Z88 not yet supported!") + + def write_z88_elements_properties(self): + element_properties_file_path = self.file_name + 'elp.txt' + elements_data = [] + if FemMeshTools.is_edge_femmesh(self.femmesh): + if len(self.beamsection_objects) == 1: + beam_obj = self.beamsection_objects[0]['Object'] + width = beam_obj.Width.getValueAs('mm') + height = beam_obj.Height.getValueAs('mm') + area = str(width * height) + elements_data.append('1 ' + str(self.element_count) + ' ' + area + ' 0 0 0 0 0 0 ') + print("Be aware, only trusses are supported for edge meshes!") + else: + print("Multiple beamsections for Z88 not yet supported!") + elif FemMeshTools.is_face_femmesh(self.femmesh): + if len(self.shellthickness_objects) == 1: + thick_obj = self.shellthickness_objects[0]['Object'] + thickness = str(thick_obj.Thickness.getValueAs('mm')) + elements_data.append('1 ' + str(self.element_count) + ' ' + thickness + ' 0 0 0 0 0 0 ') + else: + print("Multiple thicknesses for Z88 not yet supported!") + elif FemMeshTools.is_solid_femmesh(self.femmesh): + elements_data.append('1 ' + str(self.element_count) + ' 0 0 0 0 0 0 0') + else: + print("Error!") + f = open(element_properties_file_path, 'w') + f.write(str(len(elements_data)) + '\n') + for e in elements_data: + f.write(e) + f.write('\n') + f.close() + + def write_z88_integration_properties(self): + integration_data = [] + integration_data.append('1 ' + str(self.element_count) + ' ' + self.z88_elparam['INTORD'] + ' ' + self.z88_elparam['INTOS']) + integration_properties_file_path = self.file_name + 'int.txt' + f = open(integration_properties_file_path, 'w') + f.write(str(len(integration_data)) + '\n') + for i in integration_data: + f.write(i) + f.write('\n') + f.close() + + def write_z88_solver_parameter(self): + global z88_man_template + z88_man_template = z88_man_template.replace("$z88_param_ihflag", str(self.z88_elparam['IHFLAG'])) + z88_man_template = z88_man_template.replace("$z88_param_isflag", str(self.z88_elparam['ISFLAG'])) + solver_parameter_file_path = self.file_name + 'man.txt' + f = open(solver_parameter_file_path, 'w') + f.write(z88_man_template) + f.close() + + def write_z88_memory_parameter(self): + # self.z88_param_maxgs = 6000000 + self.z88_param_maxgs = 50000000 # vierkantrohr + global z88_dyn_template + z88_dyn_template = z88_dyn_template.replace("$z88_param_maxgs", str(self.z88_param_maxgs)) + solver_parameter_file_path = self.file_name + '.dyn' + f = open(solver_parameter_file_path, 'w') + f.write(z88_dyn_template) + f.close() + +# for solver parameter file Z88man.txt +z88_man_template = '''DYNAMIC START +--------------------------------------------------------------------------- +Z88V14OS +--------------------------------------------------------------------------- + +--------------------------------------------------------------------------- +GLOBAL +--------------------------------------------------------------------------- + +GLOBAL START + IBFLAG 0 + IPFLAG 0 + IHFLAG $z88_param_ihflag +GLOBAL END + +--------------------------------------------------------------------------- +LINEAR SOLVER +--------------------------------------------------------------------------- + +SOLVER START + MAXIT 10000 + EPS 1e-007 + RALPHA 0.0001 + ROMEGA 1.1 +SOLVER END + +--------------------------------------------------------------------------- +STRESS +--------------------------------------------------------------------------- + +STRESS START + KDFLAG 0 + ISFLAG $z88_param_isflag +STRESS END + +DYNAMIC END +''' + +# for memory parameter file z88.dyn +z88_dyn_template = '''DYNAMIC START +--------------------------------------------------------------------------- +Z88 new version 14OS Z88 neue Version 14OS +--------------------------------------------------------------------------- + +--------------------------------------------------------------------------- +LANGUAGE SPRACHE +--------------------------------------------------------------------------- +GERMAN + +--------------------------------------------------------------------------- +Entries for mesh generator Z88N Daten fuer Netzgenerator +--------------------------------------------------------------------------- + NET START + MAXSE 40000 + MAXESS 800 + MAXKSS 4000 + MAXAN 15 + NET END + +--------------------------------------------------------------------------- +Common entries for all modules gemeinsame Daten fuer alle Module +--------------------------------------------------------------------------- + + COMMON START + MAXGS $z88_param_maxgs + MAXKOI 1200000 + MAXK 60000 + MAXE 300000 + MAXNFG 200000 + MAXMAT 32 + MAXPEL 32 + MAXJNT 32 + MAXPR 10000 + MAXRBD 15000 + MAXIEZ 6000000 + MAXGP 2000000 + COMMON END + +--------------------------------------------------------------------------- +Entries for Cuthill-McKee Z88H Daten fuer Cuthill- McKee Programm +--------------------------------------------------------------------------- + CUTKEE START + MAXGRA 200 + MAXNDL 1000 + CUTKEE END + + +DYNAMIC END +''' diff --git a/src/Mod/Fem/FemSolverZ88.py b/src/Mod/Fem/FemSolverZ88.py new file mode 100644 index 000000000..12dc2a5e7 --- /dev/null +++ b/src/Mod/Fem/FemSolverZ88.py @@ -0,0 +1,39 @@ +# *************************************************************************** +# * * +# * Copyright (c) 2016 - Bernd Hahnebach * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + +__title__ = "FemSolverZ88" +__author__ = "Bernd Hahnebach" +__url__ = "http://www.freecadweb.org" + + +import FreeCAD +import _FemSolverZ88 + + +def makeFemSolverZ88(name="Z88"): + '''makeSolverZ88(name): makes a Z88 solver object''' + obj = FreeCAD.ActiveDocument.addObject("Fem::FemSolverObjectPython", name) + _FemSolverZ88._FemSolverZ88(obj) + if FreeCAD.GuiUp: + import _ViewProviderFemSolverZ88 + _ViewProviderFemSolverZ88._ViewProviderFemSolverZ88(obj.ViewObject) + return obj diff --git a/src/Mod/Fem/FemToolsZ88.py b/src/Mod/Fem/FemToolsZ88.py new file mode 100644 index 000000000..4d8500dbc --- /dev/null +++ b/src/Mod/Fem/FemToolsZ88.py @@ -0,0 +1,172 @@ +# *************************************************************************** +# * * +# * Copyright (c) 2016 - Bernd Hahnebach * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + + +__title__ = "FemToolsZ88" +__author__ = "Bernd Hahnebach" +__url__ = "http://www.freecadweb.org" + + +import FemTools +from PySide import QtCore +from PySide.QtGui import QApplication + + +class FemToolsZ88(FemTools.FemTools): + + known_analysis_types = ["static"] + + ## The constructor + # @param analysis - analysis object to be used as the core object. + # @param test_mode - True indicates that no real calculations will take place, so ccx bianry is not required. Used by test module. + # "__init__" tries to use current active analysis in analysis is left empty. + # Rises exception if analysis is not set and there is no active analysis + def __init__(self, analysis=None, test_mode=False): + if analysis: + ## @var analysis + # FEM analysis - the core object. Has to be present. + # It's set to analysis passed in "__init__" or set to current active analysis by default if nothing has been passed to "__init__". + self.analysis = analysis + else: + import FemGui + self.analysis = FemGui.getActiveAnalysis() + if self.analysis: + self.update_objects() + self.base_name = "" + if self.solver: + self.set_analysis_type() + self.setup_working_dir() + else: + raise Exception('FEM: No solver found!') + else: + raise Exception('FEM: No active analysis found!') + + self.z88_binary = "/home/hugo/z88progr/z88v14os/bin/unix64/z88r" + self.z88_is_running = False + self.z88_testrun = QtCore.QProcess() + self.z88_solverun = QtCore.QProcess() + QtCore.QObject.connect(self.z88_testrun, QtCore.SIGNAL("started()"), self.z88_testrun_started) + QtCore.QObject.connect(self.z88_testrun, QtCore.SIGNAL("finished(int)"), self.z88_testrun_finished) + QtCore.QObject.connect(self.z88_solverun, QtCore.SIGNAL("started()"), self.z88_solverun_started) + QtCore.QObject.connect(self.z88_solverun, QtCore.SIGNAL("finished(int)"), self.z88_solverun_finished) + + def write_inp_file(self): + import FemInputWriterZ88 as iw + import sys + self.inp_file_name = "" + try: + inp_writer = iw.FemInputWriterZ88(self.analysis, self.mesh, self.materials, + self.fixed_constraints, + self.force_constraints, self.pressure_constraints, + self.displacement_constraints, + self.beam_sections, self.shell_thicknesses, + self.analysis_type, None, + self.working_dir) + self.inp_file_name = inp_writer.write_z88_input() + except: + print("Unexpected error when writing Z88 input files:", sys.exc_info()[0]) + raise + + def run(self): + # TODO: reimplement the process handling for z88 binary + message = self.check_prerequisites() + if not message: + self.write_inp_file() + self.cwd = QtCore.QDir.currentPath() + self.calc_path = QtCore.QFileInfo(self.working_dir + '/pseudofile.txt') + print(self.cwd) + print(self.inp_file_name) + print(self.calc_path.path()) + self.z88_test_run() + else: + print("Running analysis failed! {}".format(message)) + + def z88_test_run(self): + # z88_testrun for memory + QtCore.QDir.setCurrent(self.calc_path.path()) + if not self.z88_is_running: + #self.z88_binary = "/home/hugo/z88progr/z88v14os/bin/unix64/z88r" + #self.z88_testrun.start(self.z88_binary, ["-c -choly"]) + z88_testrun_binary = self.z88_binary + " -t -choly" + print("Testrun Z88") + print(z88_testrun_binary) + self.z88_is_running = True + self.z88_testrun.start(z88_testrun_binary) + else: + print("Can not stat CalculiX, because it runs (testrun)!") + QtCore.QDir.setCurrent(self.cwd) + QApplication.restoreOverrideCursor() + + def z88_solve_run(self): + # z88_solve run + QtCore.QDir.setCurrent(self.calc_path.path()) + if not self.z88_is_running: + z88_solverun_binary = self.z88_binary + " -c -choly" + print("Solverun Z88") + print(z88_solverun_binary) + self.z88_is_running = True + self.z88_solverun.start(z88_solverun_binary) + else: + print("Can not stat CalculiX, because it runs (solverun)!") + QtCore.QDir.setCurrent(self.cwd) + QApplication.restoreOverrideCursor() + + def z88_testrun_started(self): + print(" z88_testrun_started()") + # print(self.z88_testrun.state()) + + def z88_testrun_finished(self, exitCode): + self.z88_is_running = False + print(" z88_testrun_finished() --> " + str(exitCode)) + # print(self.z88_testrun.state()) + # out = self.z88_testrun.readAllStandardOutput() + # print(out + '\n') # in some cases output will be cutted, see gmsh macro --> same problem + # TODO search out for "Vektor GS" and "Vektor KOI" and print values, may be compare with z88_params value + self.z88_solve_run() + + def z88_solverun_started(self): + print(" z88_solverun_started()") + # print(self.z88_solverun.state()) + + def z88_solverun_finished(self, exitCode): + self.z88_is_running = False + print(" z88_solverun_finished() --> " + str(exitCode)) + # print(self.z88_solverun.state()) + self.load_results() + + def load_results(self): + self.results_present = False + self.load_results_o2() + + def load_results_o2(self): + import os + import z88DispReader + disp_result_file = self.working_dir + '/z88o2.txt' + if os.path.isfile(disp_result_file): + z88DispReader.import_z88_disp(disp_result_file, self.analysis) + for m in self.analysis.Member: + if m.isDerivedFrom("Fem::FemResultObject"): + self.result_object = m + if self.result_object: + self.results_present = True + else: + raise Exception('FEM: No results found at {}!'.format(disp_result_file)) diff --git a/src/Mod/Fem/Gui/Workbench.cpp b/src/Mod/Fem/Gui/Workbench.cpp index 51569dab5..2756f3019 100755 --- a/src/Mod/Fem/Gui/Workbench.cpp +++ b/src/Mod/Fem/Gui/Workbench.cpp @@ -57,6 +57,7 @@ Gui::ToolBarItem* Workbench::setupToolBars() const fem->setCommand("FEM"); *fem << "Fem_Analysis" << "Fem_SolverCalculix" + // << "Fem_SolverZ88" << "Fem_MeshFromShape" << "Fem_MechanicalMaterial" << "Fem_BeamSection" @@ -89,6 +90,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const fem->setCommand("&FEM"); *fem << "Fem_Analysis" << "Fem_SolverCalculix" + << "Fem_SolverZ88" << "Fem_MeshFromShape" << "Fem_MechanicalMaterial" << "Fem_BeamSection" diff --git a/src/Mod/Fem/InitGui.py b/src/Mod/Fem/InitGui.py index caae6f14a..12b66069e 100644 --- a/src/Mod/Fem/InitGui.py +++ b/src/Mod/Fem/InitGui.py @@ -57,6 +57,7 @@ class FemWorkbench (Workbench): import _CommandBeamSection import _CommandMechanicalMaterial import _CommandSolverCalculix + import _CommandSolverZ88 import subprocess from platform import system diff --git a/src/Mod/Fem/_CommandRunSolver.py b/src/Mod/Fem/_CommandRunSolver.py index 84355fc9a..e3771ceab 100644 --- a/src/Mod/Fem/_CommandRunSolver.py +++ b/src/Mod/Fem/_CommandRunSolver.py @@ -61,6 +61,17 @@ class _CommandRunSolver(FemCommands): return self.fea.finished.connect(load_results) QtCore.QThreadPool.globalInstance().start(self.fea) + elif FreeCADGui.Selection.getSelection()[0].SolverType == "FemSolverZ88": + import FemToolsZ88 + self.fea = FemToolsZ88.FemToolsZ88() + self.fea.reset_all() + message = self.fea.check_prerequisites() + if message: + QtGui.QMessageBox.critical(None, "Missing prerequisite", message) + return + self.fea.run() # test z88 + #self.fea.finished.connect(load_results) + #QtCore.QThreadPool.globalInstance().start(self.fea) else: QtGui.QMessageBox.critical(None, "Not known solver type", message) diff --git a/src/Mod/Fem/_CommandSolverZ88.py b/src/Mod/Fem/_CommandSolverZ88.py new file mode 100644 index 000000000..5755e32bb --- /dev/null +++ b/src/Mod/Fem/_CommandSolverZ88.py @@ -0,0 +1,53 @@ +# *************************************************************************** +# * * +# * Copyright (c) 2016 - Bernd Hahnebach * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + +__title__ = "_CommandSolverZ88" +__author__ = "Bernd Hahnebach" +__url__ = "http://www.freecadweb.org" + + +import FreeCAD +from FemCommands import FemCommands + +if FreeCAD.GuiUp: + import FreeCADGui + from PySide import QtCore + + +class _CommandSolverZ88(FemCommands): + "The Fem_SolverZ88 command definition" + def __init__(self): + super(_CommandSolverZ88, self).__init__() + self.resources = {'Pixmap': 'fem-solver', + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Fem_SolverZ88", "Solver Z88"), + 'Accel': "S, Z", + 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Fem_SolverZ88", "Creates a FEM solver Z88")} + self.is_active = 'with_analysis_without_solver' + + def Activated(self): + FreeCAD.ActiveDocument.openTransaction("Create SolverZ88") + FreeCADGui.addModule("FemSolverZ88") + FreeCADGui.doCommand("FemGui.getActiveAnalysis().Member = FemGui.getActiveAnalysis().Member + [FemSolverZ88.makeFemSolverZ88()]") + + +if FreeCAD.GuiUp: + FreeCADGui.addCommand('Fem_SolverZ88', _CommandSolverZ88()) diff --git a/src/Mod/Fem/_FemSolverZ88.py b/src/Mod/Fem/_FemSolverZ88.py new file mode 100644 index 000000000..5466a3aab --- /dev/null +++ b/src/Mod/Fem/_FemSolverZ88.py @@ -0,0 +1,61 @@ +# *************************************************************************** +# * * +# * Copyright (c) 2016 - Bernd Hahnebach * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + +__title__ = "_FemSolverZ88" +__author__ = "Bernd Hahnebach" +__url__ = "http://www.freecadweb.org" + + +import FreeCAD +import FemToolsZ88 + + +class _FemSolverZ88(): + """The Fem::FemSolver's Proxy python type, add solver specific properties + """ + def __init__(self, obj): + self.Type = "FemSolverZ88" + self.Object = obj # keep a ref to the DocObj for nonGui usage + obj.Proxy = self # link between App::DocumentObject to this object + + obj.addProperty("App::PropertyString", "SolverType", "Base", "Type of the solver", 1) # the 1 set the property to ReadOnly + obj.SolverType = str(self.Type) + + fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem") + + obj.addProperty("App::PropertyPath", "WorkingDir", "Fem", "Working directory for calculations") + obj.WorkingDir = fem_prefs.GetString("WorkingDir", "") + + obj.addProperty("App::PropertyEnumeration", "AnalysisType", "Fem", "Type of the analysis") + obj.AnalysisType = FemToolsZ88.FemToolsZ88.known_analysis_types + analysis_type = fem_prefs.GetInt("AnalysisType", 0) + obj.AnalysisType = FemToolsZ88.FemToolsZ88.known_analysis_types[analysis_type] + + def execute(self, obj): + return + + def __getstate__(self): + return self.Type + + def __setstate__(self, state): + if state: + self.Type = state diff --git a/src/Mod/Fem/_ViewProviderFemSolverZ88.py b/src/Mod/Fem/_ViewProviderFemSolverZ88.py new file mode 100644 index 000000000..23724989c --- /dev/null +++ b/src/Mod/Fem/_ViewProviderFemSolverZ88.py @@ -0,0 +1,74 @@ +# *************************************************************************** +# * * +# * Copyright (c) 2015 - Bernd Hahnebach * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + +__title__ = "_FemViewProviderSolverZ88" +__author__ = "Bernd Hahnebach" +__url__ = "http://www.freecadweb.org" + + +import FreeCAD +import FreeCADGui +import FemGui + + +class _ViewProviderFemSolverZ88: + "A View Provider for the FemSolverZ88 object" + def __init__(self, vobj): + vobj.Proxy = self + + def getIcon(self): + return ":/icons/fem-solver.svg" + + def attach(self, vobj): + self.ViewObject = vobj + self.Object = vobj.Object + + def updateData(self, obj, prop): + return + + def onChanged(self, vobj, prop): + return + + def doubleClicked(self, vobj): + doc = FreeCADGui.getDocument(vobj.Object.Document) + if not doc.getInEdit(): + # may be go the other way around and just activate the analysis the user has doubleClicked on ?! + if FemGui.getActiveAnalysis() is not None: + if FemGui.getActiveAnalysis().Document is FreeCAD.ActiveDocument: + if self.Object in FemGui.getActiveAnalysis().Member: + FreeCAD.Console.PrintError('Not yet supported, use property editor and "run analysis" button!\n') + # doc.setEdit(vobj.Object.Name) + else: + FreeCAD.Console.PrintError('Activate the analysis this solver belongs to!\n') + else: + FreeCAD.Console.PrintError('Active Analysis is not in active Document!\n') + else: + FreeCAD.Console.PrintError('No active Analysis found!\n') + else: + FreeCAD.Console.PrintError('Active Task Dialog found! Please close this one first!\n') + return True + + def __getstate__(self): + return None + + def __setstate__(self, state): + return None