diff --git a/src/Mod/Fem/App/CMakeLists.txt b/src/Mod/Fem/App/CMakeLists.txt index 66230eaa84..2786ba8bfd 100644 --- a/src/Mod/Fem/App/CMakeLists.txt +++ b/src/Mod/Fem/App/CMakeLists.txt @@ -129,6 +129,13 @@ SET(FemSolver_SRCS femsolver/signal.py ) +SET(FemZ88_SRCS + femsolver/z88/__init__.py + femsolver/z88/solver.py + femsolver/z88/tasks.py + femsolver/z88/writer.py +) + SET(FemGuiScripts_SRCS PyGui/FemCommands.py PyGui/FemSelectionObserver.py @@ -332,6 +339,7 @@ fc_target_copy_resource(Fem ${FemGuiScripts_SRCS} ${FemTests_SRCS} ${FemSolver_SRCS} + ${FemZ88_SRCS} ) SET_BIN_DIR(Fem Fem /Mod/Fem) diff --git a/src/Mod/Fem/CMakeLists.txt b/src/Mod/Fem/CMakeLists.txt index e3ed9ec5cd..91790f436d 100755 --- a/src/Mod/Fem/CMakeLists.txt +++ b/src/Mod/Fem/CMakeLists.txt @@ -84,6 +84,16 @@ INSTALL( Mod/Fem/femsolver ) +INSTALL( + FILES + femsolver/z88/__init__.py + femsolver/z88/solver.py + femsolver/z88/tasks.py + femsolver/z88/writer.py + DESTINATION + Mod/Fem/femsolver/z88 +) + INSTALL( FILES PyGui/FemCommands.py diff --git a/src/Mod/Fem/ObjectsFem.py b/src/Mod/Fem/ObjectsFem.py index 0b4e6b78e6..d4829673cd 100644 --- a/src/Mod/Fem/ObjectsFem.py +++ b/src/Mod/Fem/ObjectsFem.py @@ -321,14 +321,10 @@ def makeSolverCalculix(doc, name="CalculiX"): return obj -def makeSolverZ88(doc, name="Z88"): +def makeSolverZ88(doc, name="SolverZ88"): '''makeSolverZ88(document, [name]): makes a Z88 solver object''' - obj = doc.addObject("Fem::FemSolverObjectPython", name) - import PyObjects._FemSolverZ88 - PyObjects._FemSolverZ88._FemSolverZ88(obj) - if FreeCAD.GuiUp: - import PyGui._ViewProviderFemSolverZ88 - PyGui._ViewProviderFemSolverZ88._ViewProviderFemSolverZ88(obj.ViewObject) + import femsolver.z88.solver + obj = femsolver.z88.solver.create(doc, name) return obj diff --git a/src/Mod/Fem/PyGui/_CommandFemSolverRun.py b/src/Mod/Fem/PyGui/_CommandFemSolverRun.py index 49e1171d2f..2c340d1006 100644 --- a/src/Mod/Fem/PyGui/_CommandFemSolverRun.py +++ b/src/Mod/Fem/PyGui/_CommandFemSolverRun.py @@ -52,7 +52,9 @@ class _CommandFemSolverRun(FemCommands): print ("CalculiX failed ccx finished with error {}".format(ret_code)) self.solver = FreeCADGui.Selection.getSelection()[0] # see 'with_solver' in FemCommands for selection check - if self.solver.SolverType == "FemSolverCalculix": + if FemUtils.isDerivedFrom(self.solver, "Fem::FemSolverObjectZ88"): + self._newActivated() + elif self.solver.SolverType == "FemSolverCalculix": import FemToolsCcx self.fea = FemToolsCcx.FemToolsCcx(None, self.solver) self.fea.reset_mesh_purge_results_checked() diff --git a/src/Mod/Fem/femsolver/settings.py b/src/Mod/Fem/femsolver/settings.py index 25f302bfe6..5996a66201 100644 --- a/src/Mod/Fem/femsolver/settings.py +++ b/src/Mod/Fem/femsolver/settings.py @@ -36,6 +36,7 @@ CUSTOM = "custom" _ELMER_PARAM = "User parameter:BaseApp/Preferences/Mod/Fem/Elmer" _GRID_PARAM = "User parameter:BaseApp/Preferences/Mod/Fem/Grid" +_Z88_PARAM = "User parameter:BaseApp/Preferences/Mod/Fem/Z88" class _BinaryDlg(object): @@ -65,6 +66,11 @@ _BINARIES = { param=_GRID_PARAM, useDefault="UseStandardGridLocation", customPath="gridBinaryPath"), + "Z88": _BinaryDlg( + default="z88r", + param=_Z88_PARAM, + useDefault="UseStandardZ88Location", + customPath="z88BinaryPath"), } diff --git a/src/Mod/Fem/femsolver/z88/__init__.py b/src/Mod/Fem/femsolver/z88/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/Mod/Fem/femsolver/z88/solver.py b/src/Mod/Fem/femsolver/z88/solver.py new file mode 100644 index 0000000000..e1cf021888 --- /dev/null +++ b/src/Mod/Fem/femsolver/z88/solver.py @@ -0,0 +1,90 @@ +# *************************************************************************** +# * * +# * Copyright (c) 2017 - 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__ = "Z88 SolverObject" +__author__ = "Bernd Hahnebach" +__url__ = "http://www.freecadweb.org" + +## @package SolverZ88 +# \ingroup FEM + +import os +import glob + +import FreeCAD +import FemUtils + +from .. import run +from .. import solverbase +from . import tasks + + +if FreeCAD.GuiUp: + import FemGui + +ANALYSIS_TYPES = ["static"] + + +def create(doc, name="SolverZ88"): + return FemUtils.createObject( + doc, name, Proxy, ViewProxy) + + +class Proxy(solverbase.Proxy): + """The Fem::FemSolver's Proxy python type, add solver specific properties + """ + + Type = "Fem::FemSolverObjectZ88" + + def __init__(self, obj): + super(Proxy, self).__init__(obj) + obj.Proxy = self + + # z88_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/Z88") + + obj.addProperty("App::PropertyEnumeration", "AnalysisType", "Fem", "Type of the analysis") + obj.AnalysisType = ANALYSIS_TYPES + obj.AnalysisType = ANALYSIS_TYPES[0] + + def createMachine(self, obj, directory): + return run.Machine( + solver=obj, directory=directory, + check=tasks.Check(), + prepare=tasks.Prepare(), + solve=tasks.Solve(), + results=tasks.Results()) + + def editSupported(self): + return True + + def edit(self, directory): + pattern = os.path.join(directory, "*.txt") + print(pattern) + f = glob.glob(pattern)[0] + FemGui.open(f) + + def execute(self, obj): + return + + +class ViewProxy(solverbase.ViewProxy): + pass diff --git a/src/Mod/Fem/femsolver/z88/tasks.py b/src/Mod/Fem/femsolver/z88/tasks.py new file mode 100644 index 0000000000..4d411b87ba --- /dev/null +++ b/src/Mod/Fem/femsolver/z88/tasks.py @@ -0,0 +1,261 @@ +# *************************************************************************** +# * * +# * Copyright (c) 2017 - 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__ = "Z88 Tasks" +__author__ = "Bernd Hahnebach" +__url__ = "http://www.freecadweb.org" + + +import os +import subprocess +import os.path + +import FreeCAD as App +import FemUtils +import importZ88O2Results + +from .. import run +from .. import settings +from . import writer + + +_inputFileName = None + + +class Check(run.Check): + + def run(self): + self.pushStatus("Checking analysis...\n") + self.checkMesh() + self.checkMaterial() + + +class Prepare(run.Prepare): + + def run(self): + global _inputFileName + self.pushStatus("Preparing input files...\n") + c = _Container(self.analysis) + w = writer.FemInputWriterZ88( + self.analysis, self.solver, c.mesh, c.materials_linear, + c.materials_nonlinear, c.fixed_constraints, + c.displacement_constraints, c.contact_constraints, + c.planerotation_constraints, c.transform_constraints, + c.selfweight_constraints, c.force_constraints, + c.pressure_constraints, c.temperature_constraints, + c.heatflux_constraints, c.initialtemperature_constraints, + c.beam_sections, c.shell_thicknesses, c.fluid_sections, + self.solver.AnalysisType, self.directory) + path = w.write_z88_input() + _inputFileName = os.path.splitext(os.path.basename(path))[0] # AFAIK empty for z88 + print(path) + print(_inputFileName) + + +class Solve(run.Solve): + + def run(self): + # AFAIK: z88r needs to be run twice, once in test mode ond once in real solve mode + # the subprocess was just copied, it seams to work :-) + # TODO: search out for "Vektor GS" and "Vektor KOI" and print values, may be compare with the used ones + self.pushStatus("Executing test solver...\n") + binary = settings.getBinary("Z88") + self._process = subprocess.Popen( + [binary, "-t", "-choly"], + cwd=self.directory, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + self.signalAbort.add(self._process.terminate) + output = self._observeSolver(self._process) + self._process.communicate() + self.signalAbort.remove(self._process.terminate) + + self.pushStatus("Executing real solver...\n") + binary = settings.getBinary("Z88") + self._process = subprocess.Popen( + [binary, "-c", "-choly"], + cwd=self.directory, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + self.signalAbort.add(self._process.terminate) + output = self._observeSolver(self._process) + self._process.communicate() + self.signalAbort.remove(self._process.terminate) + # if not self.aborted: + # self._updateOutput(output) + del output # get flake8 quiet + + def _observeSolver(self, process): + output = "" + line = process.stdout.readline() + self.pushStatus(line) + output += line + line = process.stdout.readline() + while line: + line = "\n%s" % line.rstrip() + self.pushStatus(line) + output += line + line = process.stdout.readline() + return output + + +class Results(run.Results): + + def run(self): + prefs = App.ParamGet( + "User parameter:BaseApp/Preferences/Mod/Fem/General") + if not prefs.GetBool("KeepResultsOnReRun", False): + self.purge_results() + self.load_results_z88o2() + + def purge_results(self): + for m in FemUtils.getMember(self.analysis, "Fem::FemResultObject"): + if FemUtils.isOfType(m.Mesh, "FemMeshResult"): + self.analysis.Document.removeObject(m.Mesh.Name) + self.analysis.Document.removeObject(m.Name) + App.ActiveDocument.recompute() + + def load_results_z88o2(self): + disp_result_file = os.path.join( + self.directory, 'z88o2.txt') + if os.path.isfile(disp_result_file): + result_name_prefix = 'Z88_' + self.solver.AnalysisType + '_' + importZ88O2Results.import_z88_disp( + disp_result_file, self.analysis, result_name_prefix) + else: + raise Exception( + 'FEM: No results found at {}!'.format(disp_result_file)) + + +class _Container(object): + + def __init__(self, analysis): + self.mesh = None + self.materials_linear = [] + self.materials_nonlinear = [] + self.fixed_constraints = [] + self.selfweight_constraints = [] + self.force_constraints = [] + self.pressure_constraints = [] + self.beam_sections = [] + self.fluid_sections = [] + self.shell_thicknesses = [] + self.displacement_constraints = [] + self.temperature_constraints = [] + self.heatflux_constraints = [] + self.initialtemperature_constraints = [] + self.planerotation_constraints = [] + self.contact_constraints = [] + self.transform_constraints = [] + + for m in analysis.Member: + if m.isDerivedFrom("Fem::FemMeshObject"): + if not self.mesh: + self.mesh = m + else: + raise Exception('FEM: Multiple mesh in analysis not yet supported!') + elif m.isDerivedFrom("App::MaterialObjectPython"): + material_linear_dict = {} + material_linear_dict['Object'] = m + self.materials_linear.append(material_linear_dict) + elif hasattr(m, "Proxy") and m.Proxy.Type == "FemMaterialMechanicalNonlinear": + material_nonlinear_dict = {} + material_nonlinear_dict['Object'] = m + self.materials_nonlinear.append(material_nonlinear_dict) + elif m.isDerivedFrom("Fem::ConstraintFixed"): + fixed_constraint_dict = {} + fixed_constraint_dict['Object'] = m + self.fixed_constraints.append(fixed_constraint_dict) + elif hasattr(m, "Proxy") and m.Proxy.Type == "FemConstraintSelfWeight": + selfweight_dict = {} + selfweight_dict['Object'] = m + self.selfweight_constraints.append(selfweight_dict) + elif m.isDerivedFrom("Fem::ConstraintForce"): + force_constraint_dict = {} + force_constraint_dict['Object'] = m + force_constraint_dict['RefShapeType'] = self.get_refshape_type(m) + self.force_constraints.append(force_constraint_dict) + elif m.isDerivedFrom("Fem::ConstraintPressure"): + PressureObjectDict = {} + PressureObjectDict['Object'] = m + self.pressure_constraints.append(PressureObjectDict) + elif m.isDerivedFrom("Fem::ConstraintDisplacement"): + displacement_constraint_dict = {} + displacement_constraint_dict['Object'] = m + self.displacement_constraints.append(displacement_constraint_dict) + elif m.isDerivedFrom("Fem::ConstraintTemperature"): + temperature_constraint_dict = {} + temperature_constraint_dict['Object'] = m + self.temperature_constraints.append(temperature_constraint_dict) + elif m.isDerivedFrom("Fem::ConstraintHeatflux"): + heatflux_constraint_dict = {} + heatflux_constraint_dict['Object'] = m + self.heatflux_constraints.append(heatflux_constraint_dict) + elif m.isDerivedFrom("Fem::ConstraintInitialTemperature"): + initialtemperature_constraint_dict = {} + initialtemperature_constraint_dict['Object'] = m + self.initialtemperature_constraints.append( + initialtemperature_constraint_dict) + elif m.isDerivedFrom("Fem::ConstraintPlaneRotation"): + planerotation_constraint_dict = {} + planerotation_constraint_dict['Object'] = m + self.planerotation_constraints.append(planerotation_constraint_dict) + elif m.isDerivedFrom("Fem::ConstraintContact"): + contact_constraint_dict = {} + contact_constraint_dict['Object'] = m + self.contact_constraints.append(contact_constraint_dict) + elif m.isDerivedFrom("Fem::ConstraintTransform"): + transform_constraint_dict = {} + transform_constraint_dict['Object'] = m + self.transform_constraints.append(transform_constraint_dict) + elif hasattr(m, "Proxy") and m.Proxy.Type == "FemElementGeometry1D": + beam_section_dict = {} + beam_section_dict['Object'] = m + self.beam_sections.append(beam_section_dict) + elif hasattr(m, "Proxy") and m.Proxy.Type == "FemElementFluid1D": + fluid_section_dict = {} + fluid_section_dict['Object'] = m + self.fluid_sections.append(fluid_section_dict) + elif hasattr(m, "Proxy") and m.Proxy.Type == "FemElementGeometry2D": + shell_thickness_dict = {} + shell_thickness_dict['Object'] = m + self.shell_thicknesses.append(shell_thickness_dict) + + def get_refshape_type(self, fem_doc_object): + # returns the reference shape type + # for force object: + # in GUI defined frc_obj all frc_obj have at leas one ref_shape and ref_shape have all the same shape type + # for material object: + # in GUI defined material_obj could have no RefShape and RefShapes could be different type + # we gone need the RefShapes to be the same type inside one fem_doc_object + # TODO here: check if all RefShapes inside the object really have the same type + import FemMeshTools + if hasattr(fem_doc_object, 'References') and fem_doc_object.References: + first_ref_obj = fem_doc_object.References[0] + first_ref_shape = FemMeshTools.get_element(first_ref_obj[0], first_ref_obj[1][0]) + st = first_ref_shape.ShapeType + print(fem_doc_object.Name + ' has ' + st + ' reference shapes.') + return st + else: + print(fem_doc_object.Name + ' has empty References.') + return '' diff --git a/src/Mod/Fem/femsolver/z88/writer.py b/src/Mod/Fem/femsolver/z88/writer.py new file mode 100644 index 0000000000..ca7e15910d --- /dev/null +++ b/src/Mod/Fem/femsolver/z88/writer.py @@ -0,0 +1,323 @@ +# *************************************************************************** +# * * +# * Copyright (c) 2017 - 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__ = "Z88 Writer" +__author__ = "Bernd Hahnebach" +__url__ = "http://www.freecadweb.org" + +## \addtogroup FEM +# @{ + +import FreeCAD +import FemMeshTools +import importZ88Mesh +import FemInputWriter + + +class FemInputWriterZ88(FemInputWriter.FemInputWriter): + def __init__(self, + analysis_obj, solver_obj, + mesh_obj, matlin_obj, matnonlin_obj, + fixed_obj, displacement_obj, + contact_obj, planerotation_obj, transform_obj, + selfweight_obj, force_obj, pressure_obj, + temperature_obj, heatflux_obj, initialtemperature_obj, + beamsection_obj, shellthickness_obj, fluidsection_obj, + analysis_type=None, dir_name=None + ): + + FemInputWriter.FemInputWriter.__init__( + self, + analysis_obj, solver_obj, + mesh_obj, matlin_obj, matnonlin_obj, + fixed_obj, displacement_obj, + contact_obj, planerotation_obj, transform_obj, + selfweight_obj, force_obj, pressure_obj, + temperature_obj, heatflux_obj, initialtemperature_obj, + beamsection_obj, shellthickness_obj, fluidsection_obj, + analysis_type, dir_name) + # self.dir_name does have a slash at the end + 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.RectWidth.getValueAs('mm') + height = beam_obj.RectHeight.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 +''' + +## @}