diff --git a/src/Mod/Fem/CMakeLists.txt b/src/Mod/Fem/CMakeLists.txt index 97d78f4c44..f597274816 100755 --- a/src/Mod/Fem/CMakeLists.txt +++ b/src/Mod/Fem/CMakeLists.txt @@ -202,6 +202,9 @@ SET(FemSolverCalculix_SRCS femsolver/calculix/write_constraint_temperature.py femsolver/calculix/write_constraint_tie.py femsolver/calculix/write_constraint_transform.py + femsolver/calculix/write_femelement_geometry.py + femsolver/calculix/write_femelement_material.py + femsolver/calculix/write_femelement_matgeosets.py femsolver/calculix/write_footer.py femsolver/calculix/write_mesh.py femsolver/calculix/write_step_equation.py diff --git a/src/Mod/Fem/femsolver/calculix/write_femelement_geometry.py b/src/Mod/Fem/femsolver/calculix/write_femelement_geometry.py new file mode 100644 index 0000000000..64c0d6a925 --- /dev/null +++ b/src/Mod/Fem/femsolver/calculix/write_femelement_geometry.py @@ -0,0 +1,185 @@ +# *************************************************************************** +# * Copyright (c) 2021 Bernd Hahnebach * +# * * +# * This file is part of the FreeCAD CAx development system. * +# * * +# * 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__ = "FreeCAD FEM calculix write inpfile femelement geometry" +__author__ = "Bernd Hahnebach" +__url__ = "https://www.freecadweb.org" + + +def write_femelement_geometry(f, ccxwriter): + f.write("\n{}\n".format(59 * "*")) + f.write("** Sections\n") + for ccx_elset in ccxwriter.ccx_elsets: + if ccx_elset["ccx_elset"]: + if "beamsection_obj"in ccx_elset: # beam mesh + beamsec_obj = ccx_elset["beamsection_obj"] + elsetdef = "ELSET=" + ccx_elset["ccx_elset_name"] + ", " + material = "MATERIAL=" + ccx_elset["mat_obj_name"] + normal = ccx_elset["beam_normal"] + if beamsec_obj.SectionType == "Rectangular": + height = beamsec_obj.RectHeight.getValueAs("mm") + width = beamsec_obj.RectWidth.getValueAs("mm") + section_type = ", SECTION=RECT" + section_geo = str(height) + ", " + str(width) + "\n" + section_def = "*BEAM SECTION, {}{}{}\n".format( + elsetdef, + material, + section_type + ) + elif beamsec_obj.SectionType == "Circular": + radius = 0.5 * beamsec_obj.CircDiameter.getValueAs("mm") + section_type = ", SECTION=CIRC" + section_geo = str(radius) + "\n" + section_def = "*BEAM SECTION, {}{}{}\n".format( + elsetdef, + material, + section_type + ) + elif beamsec_obj.SectionType == "Pipe": + radius = 0.5 * beamsec_obj.PipeDiameter.getValueAs("mm") + thickness = beamsec_obj.PipeThickness.getValueAs("mm") + section_type = ", SECTION=PIPE" + section_geo = str(radius) + ", " + str(thickness) + "\n" + section_def = "*BEAM GENERAL SECTION, {}{}{}\n".format( + elsetdef, + material, + section_type + ) + # see forum topic for output formatting of rotation + # https://forum.freecadweb.org/viewtopic.php?f=18&t=46133&p=405142#p405142 + section_nor = "{:f}, {:f}, {:f}\n".format( + normal[0], + normal[1], + normal[2] + ) + f.write(section_def) + f.write(section_geo) + f.write(section_nor) + elif "fluidsection_obj"in ccx_elset: # fluid mesh + fluidsec_obj = ccx_elset["fluidsection_obj"] + elsetdef = "ELSET=" + ccx_elset["ccx_elset_name"] + ", " + material = "MATERIAL=" + ccx_elset["mat_obj_name"] + if fluidsec_obj.SectionType == "Liquid": + section_type = fluidsec_obj.LiquidSectionType + if (section_type == "PIPE INLET") or (section_type == "PIPE OUTLET"): + section_type = "PIPE INOUT" + section_def = "*FLUID SECTION, {}TYPE={}, {}\n".format( + elsetdef, + section_type, + material + ) + section_geo = liquid_section_def(fluidsec_obj, section_type) + """ + # deactivate as it would result in section_def and section_geo not defined + # deactivated in the App and Gui object and thus in the task panel as well + elif fluidsec_obj.SectionType == "Gas": + section_type = fluidsec_obj.GasSectionType + elif fluidsec_obj.SectionType == "Open Channel": + section_type = fluidsec_obj.ChannelSectionType + """ + f.write(section_def) + f.write(section_geo) + elif "shellthickness_obj"in ccx_elset: # shell mesh + shellth_obj = ccx_elset["shellthickness_obj"] + elsetdef = "ELSET=" + ccx_elset["ccx_elset_name"] + ", " + material = "MATERIAL=" + ccx_elset["mat_obj_name"] + section_def = "*SHELL SECTION, " + elsetdef + material + "\n" + section_geo = str(shellth_obj.Thickness.getValueAs("mm")) + "\n" + f.write(section_def) + f.write(section_geo) + else: # solid mesh + elsetdef = "ELSET=" + ccx_elset["ccx_elset_name"] + ", " + material = "MATERIAL=" + ccx_elset["mat_obj_name"] + section_def = "*SOLID SECTION, " + elsetdef + material + "\n" + f.write(section_def) + + +# ************************************************************************************************ +# Helpers +def liquid_section_def(obj, section_type): + if section_type == "PIPE MANNING": + manning_area = str(obj.ManningArea.getValueAs("mm^2").Value) + manning_radius = str(obj.ManningRadius.getValueAs("mm")) + manning_coefficient = str(obj.ManningCoefficient) + section_geo = manning_area + "," + manning_radius + "," + manning_coefficient + "\n" + return section_geo + elif section_type == "PIPE ENLARGEMENT": + enlarge_area1 = str(obj.EnlargeArea1.getValueAs("mm^2").Value) + enlarge_area2 = str(obj.EnlargeArea2.getValueAs("mm^2").Value) + section_geo = enlarge_area1 + "," + enlarge_area2 + "\n" + return section_geo + elif section_type == "PIPE CONTRACTION": + contract_area1 = str(obj.ContractArea1.getValueAs("mm^2").Value) + contract_area2 = str(obj.ContractArea2.getValueAs("mm^2").Value) + section_geo = contract_area1 + "," + contract_area2 + "\n" + return section_geo + elif section_type == "PIPE ENTRANCE": + entrance_pipe_area = str(obj.EntrancePipeArea.getValueAs("mm^2").Value) + entrance_area = str(obj.EntranceArea.getValueAs("mm^2").Value) + section_geo = entrance_pipe_area + "," + entrance_area + "\n" + return section_geo + elif section_type == "PIPE DIAPHRAGM": + diaphragm_pipe_area = str(obj.DiaphragmPipeArea.getValueAs("mm^2").Value) + diaphragm_area = str(obj.DiaphragmArea.getValueAs("mm^2").Value) + section_geo = diaphragm_pipe_area + "," + diaphragm_area + "\n" + return section_geo + elif section_type == "PIPE BEND": + bend_pipe_area = str(obj.BendPipeArea.getValueAs("mm^2").Value) + bend_radius_diameter = str(obj.BendRadiusDiameter) + bend_angle = str(obj.BendAngle) + bend_loss_coefficient = str(obj.BendLossCoefficient) + section_geo = ("{},{},{},{}\n".format( + bend_pipe_area, + bend_radius_diameter, + bend_angle, + bend_loss_coefficient + )) + return section_geo + elif section_type == "PIPE GATE VALVE": + gatevalve_pipe_area = str(obj.GateValvePipeArea.getValueAs("mm^2").Value) + gatevalve_closing_coeff = str(obj.GateValveClosingCoeff) + section_geo = gatevalve_pipe_area + "," + gatevalve_closing_coeff + "\n" + return section_geo + elif section_type == "PIPE WHITE-COLEBROOK": + colebrooke_area = str(obj.ColebrookeArea.getValueAs("mm^2").Value) + colebrooke_diameter = str(2 * obj.ColebrookeRadius.getValueAs("mm")) + colebrooke_grain_diameter = str(obj.ColebrookeGrainDiameter.getValueAs("mm")) + colebrooke_form_factor = str(obj.ColebrookeFormFactor) + section_geo = ("{},{},{},{},{}\n".format( + colebrooke_area, + colebrooke_diameter, + "-1", + colebrooke_grain_diameter, + colebrooke_form_factor + )) + return section_geo + elif section_type == "LIQUID PUMP": + section_geo = "" + for i in range(len(obj.PumpFlowRate)): + flow_rate = str(obj.PumpFlowRate[i]) + top = str(obj.PumpHeadLoss[i]) + section_geo = section_geo + flow_rate + "," + top + "," + section_geo = section_geo + "\n" + return section_geo + else: + return "" diff --git a/src/Mod/Fem/femsolver/calculix/write_femelement_material.py b/src/Mod/Fem/femsolver/calculix/write_femelement_material.py new file mode 100644 index 0000000000..9fce13920c --- /dev/null +++ b/src/Mod/Fem/femsolver/calculix/write_femelement_material.py @@ -0,0 +1,194 @@ +# *************************************************************************** +# * Copyright (c) 2021 Bernd Hahnebach * +# * * +# * This file is part of the FreeCAD CAx development system. * +# * * +# * 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__ = "FreeCAD FEM calculix write inpfile materials" +__author__ = "Bernd Hahnebach" +__url__ = "https://www.freecadweb.org" + + +import FreeCAD + + +def write_femelement_material(f, ccxwriter): + + # helper inside class method + def is_density_needed(): + if ccxwriter.analysis_type == "frequency": + return True + if ( + ccxwriter.analysis_type == "thermomech" + and not ccxwriter.solver_obj.ThermoMechSteadyState + ): + return True + if ccxwriter.centrif_objects: + return True + if ccxwriter.selfweight_objects: + return True + return False + + f.write("\n{}\n".format(59 * "*")) + f.write("** Materials\n") + f.write("** Young\'s modulus unit is MPa = N/mm2\n") + if is_density_needed() is True: + f.write("** Density\'s unit is t/mm^3\n") + if ccxwriter.analysis_type == "thermomech": + f.write("** Thermal conductivity unit is kW/mm/K = t*mm/K*s^3\n") + f.write("** Specific Heat unit is kJ/t/K = mm^2/s^2/K\n") + for femobj in ccxwriter.material_objects: + # femobj --> dict, FreeCAD document object is femobj["Object"] + mat_obj = femobj["Object"] + mat_info_name = mat_obj.Material["Name"] + mat_name = mat_obj.Name + mat_label = mat_obj.Label + # get material properties of solid material, Currently in SI units: M/kg/s/Kelvin + if mat_obj.Category == "Solid": + YM = FreeCAD.Units.Quantity(mat_obj.Material["YoungsModulus"]) + YM_in_MPa = float(YM.getValueAs("MPa")) + PR = float(mat_obj.Material["PoissonRatio"]) + if is_density_needed() is True: + density = FreeCAD.Units.Quantity(mat_obj.Material["Density"]) + density_in_tonne_per_mm3 = float(density.getValueAs("t/mm^3")) + if ccxwriter.analysis_type == "thermomech": + TC = FreeCAD.Units.Quantity(mat_obj.Material["ThermalConductivity"]) + # SvdW: Add factor to force units to results base units + # of t/mm/s/K - W/m/K results in no factor needed + TC_in_WmK = float(TC.getValueAs("W/m/K")) + SH = FreeCAD.Units.Quantity(mat_obj.Material["SpecificHeat"]) + # SvdW: Add factor to force units to results base units of t/mm/s/K + SH_in_JkgK = float(SH.getValueAs("J/kg/K")) * 1e+06 + if mat_obj.Category == "Solid": + TEC = FreeCAD.Units.Quantity(mat_obj.Material["ThermalExpansionCoefficient"]) + TEC_in_mmK = float(TEC.getValueAs("mm/mm/K")) + elif mat_obj.Category == "Fluid": + DV = FreeCAD.Units.Quantity(mat_obj.Material["DynamicViscosity"]) + DV_in_tmms = float(DV.getValueAs("t/mm/s")) + # write material properties + f.write("** FreeCAD material name: " + mat_info_name + "\n") + f.write("** " + mat_label + "\n") + f.write("*MATERIAL, NAME=" + mat_name + "\n") + if mat_obj.Category == "Solid": + f.write("*ELASTIC\n") + f.write("{0:.0f}, {1:.3f}\n".format(YM_in_MPa, PR)) + + if is_density_needed() is True: + f.write("*DENSITY\n") + f.write("{0:.3e}\n".format(density_in_tonne_per_mm3)) + if ccxwriter.analysis_type == "thermomech": + if mat_obj.Category == "Solid": + f.write("*CONDUCTIVITY\n") + f.write("{0:.3f}\n".format(TC_in_WmK)) + f.write("*EXPANSION\n") + f.write("{0:.3e}\n".format(TEC_in_mmK)) + f.write("*SPECIFIC HEAT\n") + f.write("{0:.3e}\n".format(SH_in_JkgK)) + elif mat_obj.Category == "Fluid": + f.write("*FLUID CONSTANTS\n") + f.write("{0:.3e}, {1:.3e}\n".format(SH_in_JkgK, DV_in_tmms)) + + # nonlinear material properties + if ccxwriter.solver_obj.MaterialNonlinearity == "nonlinear": + + for nlfemobj in ccxwriter.material_nonlinear_objects: + # femobj --> dict, FreeCAD document object is nlfemobj["Object"] + nl_mat_obj = nlfemobj["Object"] + if nl_mat_obj.LinearBaseMaterial == mat_obj: + if nl_mat_obj.MaterialModelNonlinearity == "simple hardening": + f.write("*PLASTIC\n") + if nl_mat_obj.YieldPoint1: + f.write(nl_mat_obj.YieldPoint1 + "\n") + if nl_mat_obj.YieldPoint2: + f.write(nl_mat_obj.YieldPoint2 + "\n") + if nl_mat_obj.YieldPoint3: + f.write(nl_mat_obj.YieldPoint3 + "\n") + f.write("\n") + + +# ************************************************************************************************ +# Helpers +def liquid_section_def(obj, section_type): + if section_type == "PIPE MANNING": + manning_area = str(obj.ManningArea.getValueAs("mm^2").Value) + manning_radius = str(obj.ManningRadius.getValueAs("mm")) + manning_coefficient = str(obj.ManningCoefficient) + section_geo = manning_area + "," + manning_radius + "," + manning_coefficient + "\n" + return section_geo + elif section_type == "PIPE ENLARGEMENT": + enlarge_area1 = str(obj.EnlargeArea1.getValueAs("mm^2").Value) + enlarge_area2 = str(obj.EnlargeArea2.getValueAs("mm^2").Value) + section_geo = enlarge_area1 + "," + enlarge_area2 + "\n" + return section_geo + elif section_type == "PIPE CONTRACTION": + contract_area1 = str(obj.ContractArea1.getValueAs("mm^2").Value) + contract_area2 = str(obj.ContractArea2.getValueAs("mm^2").Value) + section_geo = contract_area1 + "," + contract_area2 + "\n" + return section_geo + elif section_type == "PIPE ENTRANCE": + entrance_pipe_area = str(obj.EntrancePipeArea.getValueAs("mm^2").Value) + entrance_area = str(obj.EntranceArea.getValueAs("mm^2").Value) + section_geo = entrance_pipe_area + "," + entrance_area + "\n" + return section_geo + elif section_type == "PIPE DIAPHRAGM": + diaphragm_pipe_area = str(obj.DiaphragmPipeArea.getValueAs("mm^2").Value) + diaphragm_area = str(obj.DiaphragmArea.getValueAs("mm^2").Value) + section_geo = diaphragm_pipe_area + "," + diaphragm_area + "\n" + return section_geo + elif section_type == "PIPE BEND": + bend_pipe_area = str(obj.BendPipeArea.getValueAs("mm^2").Value) + bend_radius_diameter = str(obj.BendRadiusDiameter) + bend_angle = str(obj.BendAngle) + bend_loss_coefficient = str(obj.BendLossCoefficient) + section_geo = ("{},{},{},{}\n".format( + bend_pipe_area, + bend_radius_diameter, + bend_angle, + bend_loss_coefficient + )) + return section_geo + elif section_type == "PIPE GATE VALVE": + gatevalve_pipe_area = str(obj.GateValvePipeArea.getValueAs("mm^2").Value) + gatevalve_closing_coeff = str(obj.GateValveClosingCoeff) + section_geo = gatevalve_pipe_area + "," + gatevalve_closing_coeff + "\n" + return section_geo + elif section_type == "PIPE WHITE-COLEBROOK": + colebrooke_area = str(obj.ColebrookeArea.getValueAs("mm^2").Value) + colebrooke_diameter = str(2 * obj.ColebrookeRadius.getValueAs("mm")) + colebrooke_grain_diameter = str(obj.ColebrookeGrainDiameter.getValueAs("mm")) + colebrooke_form_factor = str(obj.ColebrookeFormFactor) + section_geo = ("{},{},{},{},{}\n".format( + colebrooke_area, + colebrooke_diameter, + "-1", + colebrooke_grain_diameter, + colebrooke_form_factor + )) + return section_geo + elif section_type == "LIQUID PUMP": + section_geo = "" + for i in range(len(obj.PumpFlowRate)): + flow_rate = str(obj.PumpFlowRate[i]) + top = str(obj.PumpHeadLoss[i]) + section_geo = section_geo + flow_rate + "," + top + "," + section_geo = section_geo + "\n" + return section_geo + else: + return "" diff --git a/src/Mod/Fem/femsolver/calculix/write_femelement_matgeosets.py b/src/Mod/Fem/femsolver/calculix/write_femelement_matgeosets.py new file mode 100644 index 0000000000..c485af58e4 --- /dev/null +++ b/src/Mod/Fem/femsolver/calculix/write_femelement_matgeosets.py @@ -0,0 +1,44 @@ +# *************************************************************************** +# * Copyright (c) 2021 Bernd Hahnebach * +# * * +# * This file is part of the FreeCAD CAx development system. * +# * * +# * 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__ = "FreeCAD FEM calculix write inpfile material and geometry sets" +__author__ = "Bernd Hahnebach" +__url__ = "https://www.freecadweb.org" + + +import six + + +def write_femelement_matgeosets(f, ccxwriter): + + # write ccx_elsets to file + f.write("\n{}\n".format(59 * "*")) + f.write("** Element sets for materials and FEM element type (solid, shell, beam, fluid)\n") + for ccx_elset in ccxwriter.ccx_elsets: + f.write("*ELSET,ELSET=" + ccx_elset["ccx_elset_name"] + "\n") + # use six to be sure to be Python 2.7 and 3.x compatible + if isinstance(ccx_elset["ccx_elset"], six.string_types): + f.write(ccx_elset["ccx_elset"] + "\n") + else: + for elid in ccx_elset["ccx_elset"]: + f.write(str(elid) + ",\n") diff --git a/src/Mod/Fem/femsolver/calculix/writer.py b/src/Mod/Fem/femsolver/calculix/writer.py index e0e32f31b3..c9dd6c9ae0 100644 --- a/src/Mod/Fem/femsolver/calculix/writer.py +++ b/src/Mod/Fem/femsolver/calculix/writer.py @@ -29,7 +29,6 @@ __url__ = "https://www.freecadweb.org" ## \addtogroup FEM # @{ -import six import time from os.path import join @@ -51,6 +50,9 @@ from . import write_constraint_selfweight as con_selfweight from . import write_constraint_temperature as con_temperature from . import write_constraint_tie as con_tie from . import write_constraint_transform as con_transform +from . import write_femelement_geometry +from . import write_femelement_material +from . import write_femelement_matgeosets from . import write_footer from . import write_mesh from . import write_step_equation @@ -161,8 +163,7 @@ class FemInputWriterCcx(writerbase.FemInputWriter): inpfile = write_mesh.write_mesh(self) # element sets for materials and element geometry - # self.write_element_sets_material_and_femelement_geometry(inpfile) - self.write_element_sets_material_and_femelement_type(inpfile) + write_femelement_matgeosets.write_femelement_matgeosets(inpfile, self) if self.fluidsection_objects: # some fluidsection objs need special treatment, ccx_elsets are needed for this @@ -184,10 +185,9 @@ class FemInputWriterCcx(writerbase.FemInputWriter): self.write_constraints_sets(inpfile, self.sectionprint_objects, con_sectionprint) # materials and fem element types - self.write_materials(inpfile) + write_femelement_material.write_femelement_material(inpfile, self) self.write_constraints_data(inpfile, self.initialtemperature_objects, con_initialtemp) - # self.write_femelement_geometry(inpfile) - self.write_femelementsets(inpfile) + write_femelement_geometry.write_femelement_geometry(inpfile, self) # constraints independent from steps self.write_constraints_data(inpfile, self.planerotation_objects, con_planerotation) @@ -294,267 +294,4 @@ class FemInputWriterCcx(writerbase.FemInputWriter): if write_after != "": f.write(write_after) - # ******************************************************************************************** - # material and fem element geometry - # def write_element_sets_material_and_femelement_geometry(self, f): - def write_element_sets_material_and_femelement_type(self, f): - - # write ccx_elsets to file - f.write("\n***********************************************************\n") - f.write("** Element sets for materials and FEM element type (solid, shell, beam, fluid)\n") - for ccx_elset in self.ccx_elsets: - f.write("*ELSET,ELSET=" + ccx_elset["ccx_elset_name"] + "\n") - # use six to be sure to be Python 2.7 and 3.x compatible - if isinstance(ccx_elset["ccx_elset"], six.string_types): - f.write(ccx_elset["ccx_elset"] + "\n") - else: - for elid in ccx_elset["ccx_elset"]: - f.write(str(elid) + ",\n") - - def is_density_needed(self): - if self.analysis_type == "frequency": - return True - if self.analysis_type == "thermomech" and not self.solver_obj.ThermoMechSteadyState: - return True - if self.centrif_objects: - return True - if self.selfweight_objects: - return True - return False - - def write_materials(self, f): - f.write("\n***********************************************************\n") - f.write("** Materials\n") - f.write("** Young\'s modulus unit is MPa = N/mm2\n") - if self.is_density_needed() is True: - f.write("** Density\'s unit is t/mm^3\n") - if self.analysis_type == "thermomech": - f.write("** Thermal conductivity unit is kW/mm/K = t*mm/K*s^3\n") - f.write("** Specific Heat unit is kJ/t/K = mm^2/s^2/K\n") - for femobj in self.material_objects: - # femobj --> dict, FreeCAD document object is femobj["Object"] - mat_obj = femobj["Object"] - mat_info_name = mat_obj.Material["Name"] - mat_name = mat_obj.Name - mat_label = mat_obj.Label - # get material properties of solid material, Currently in SI units: M/kg/s/Kelvin - if mat_obj.Category == "Solid": - YM = FreeCAD.Units.Quantity(mat_obj.Material["YoungsModulus"]) - YM_in_MPa = float(YM.getValueAs("MPa")) - PR = float(mat_obj.Material["PoissonRatio"]) - if self.is_density_needed() is True: - density = FreeCAD.Units.Quantity(mat_obj.Material["Density"]) - density_in_tonne_per_mm3 = float(density.getValueAs("t/mm^3")) - if self.analysis_type == "thermomech": - TC = FreeCAD.Units.Quantity(mat_obj.Material["ThermalConductivity"]) - # SvdW: Add factor to force units to results base units - # of t/mm/s/K - W/m/K results in no factor needed - TC_in_WmK = float(TC.getValueAs("W/m/K")) - SH = FreeCAD.Units.Quantity(mat_obj.Material["SpecificHeat"]) - # SvdW: Add factor to force units to results base units of t/mm/s/K - SH_in_JkgK = float(SH.getValueAs("J/kg/K")) * 1e+06 - if mat_obj.Category == "Solid": - TEC = FreeCAD.Units.Quantity(mat_obj.Material["ThermalExpansionCoefficient"]) - TEC_in_mmK = float(TEC.getValueAs("mm/mm/K")) - elif mat_obj.Category == "Fluid": - DV = FreeCAD.Units.Quantity(mat_obj.Material["DynamicViscosity"]) - DV_in_tmms = float(DV.getValueAs("t/mm/s")) - # write material properties - f.write("** FreeCAD material name: " + mat_info_name + "\n") - f.write("** " + mat_label + "\n") - f.write("*MATERIAL, NAME=" + mat_name + "\n") - if mat_obj.Category == "Solid": - f.write("*ELASTIC\n") - f.write("{0:.0f}, {1:.3f}\n".format(YM_in_MPa, PR)) - - if self.is_density_needed() is True: - f.write("*DENSITY\n") - f.write("{0:.3e}\n".format(density_in_tonne_per_mm3)) - if self.analysis_type == "thermomech": - if mat_obj.Category == "Solid": - f.write("*CONDUCTIVITY\n") - f.write("{0:.3f}\n".format(TC_in_WmK)) - f.write("*EXPANSION\n") - f.write("{0:.3e}\n".format(TEC_in_mmK)) - f.write("*SPECIFIC HEAT\n") - f.write("{0:.3e}\n".format(SH_in_JkgK)) - elif mat_obj.Category == "Fluid": - f.write("*FLUID CONSTANTS\n") - f.write("{0:.3e}, {1:.3e}\n".format(SH_in_JkgK, DV_in_tmms)) - - # nonlinear material properties - if self.solver_obj.MaterialNonlinearity == "nonlinear": - - for nlfemobj in self.material_nonlinear_objects: - # femobj --> dict, FreeCAD document object is nlfemobj["Object"] - nl_mat_obj = nlfemobj["Object"] - if nl_mat_obj.LinearBaseMaterial == mat_obj: - if nl_mat_obj.MaterialModelNonlinearity == "simple hardening": - f.write("*PLASTIC\n") - if nl_mat_obj.YieldPoint1: - f.write(nl_mat_obj.YieldPoint1 + "\n") - if nl_mat_obj.YieldPoint2: - f.write(nl_mat_obj.YieldPoint2 + "\n") - if nl_mat_obj.YieldPoint3: - f.write(nl_mat_obj.YieldPoint3 + "\n") - f.write("\n") - - # def write_femelement_geometry(self, f): - def write_femelementsets(self, f): - f.write("\n***********************************************************\n") - f.write("** Sections\n") - for ccx_elset in self.ccx_elsets: - if ccx_elset["ccx_elset"]: - if "beamsection_obj"in ccx_elset: # beam mesh - beamsec_obj = ccx_elset["beamsection_obj"] - elsetdef = "ELSET=" + ccx_elset["ccx_elset_name"] + ", " - material = "MATERIAL=" + ccx_elset["mat_obj_name"] - normal = ccx_elset["beam_normal"] - if beamsec_obj.SectionType == "Rectangular": - height = beamsec_obj.RectHeight.getValueAs("mm") - width = beamsec_obj.RectWidth.getValueAs("mm") - section_type = ", SECTION=RECT" - section_geo = str(height) + ", " + str(width) + "\n" - section_def = "*BEAM SECTION, {}{}{}\n".format( - elsetdef, - material, - section_type - ) - elif beamsec_obj.SectionType == "Circular": - radius = 0.5 * beamsec_obj.CircDiameter.getValueAs("mm") - section_type = ", SECTION=CIRC" - section_geo = str(radius) + "\n" - section_def = "*BEAM SECTION, {}{}{}\n".format( - elsetdef, - material, - section_type - ) - elif beamsec_obj.SectionType == "Pipe": - radius = 0.5 * beamsec_obj.PipeDiameter.getValueAs("mm") - thickness = beamsec_obj.PipeThickness.getValueAs("mm") - section_type = ", SECTION=PIPE" - section_geo = str(radius) + ", " + str(thickness) + "\n" - section_def = "*BEAM GENERAL SECTION, {}{}{}\n".format( - elsetdef, - material, - section_type - ) - # see forum topic for output formatting of rotation - # https://forum.freecadweb.org/viewtopic.php?f=18&t=46133&p=405142#p405142 - section_nor = "{:f}, {:f}, {:f}\n".format( - normal[0], - normal[1], - normal[2] - ) - f.write(section_def) - f.write(section_geo) - f.write(section_nor) - elif "fluidsection_obj"in ccx_elset: # fluid mesh - fluidsec_obj = ccx_elset["fluidsection_obj"] - elsetdef = "ELSET=" + ccx_elset["ccx_elset_name"] + ", " - material = "MATERIAL=" + ccx_elset["mat_obj_name"] - if fluidsec_obj.SectionType == "Liquid": - section_type = fluidsec_obj.LiquidSectionType - if (section_type == "PIPE INLET") or (section_type == "PIPE OUTLET"): - section_type = "PIPE INOUT" - section_def = "*FLUID SECTION, {}TYPE={}, {}\n".format( - elsetdef, - section_type, - material - ) - section_geo = liquid_section_def(fluidsec_obj, section_type) - """ - # deactivate as it would result in section_def and section_geo not defined - # deactivated in the App and Gui object and thus in the task panel as well - elif fluidsec_obj.SectionType == "Gas": - section_type = fluidsec_obj.GasSectionType - elif fluidsec_obj.SectionType == "Open Channel": - section_type = fluidsec_obj.ChannelSectionType - """ - f.write(section_def) - f.write(section_geo) - elif "shellthickness_obj"in ccx_elset: # shell mesh - shellth_obj = ccx_elset["shellthickness_obj"] - elsetdef = "ELSET=" + ccx_elset["ccx_elset_name"] + ", " - material = "MATERIAL=" + ccx_elset["mat_obj_name"] - section_def = "*SHELL SECTION, " + elsetdef + material + "\n" - section_geo = str(shellth_obj.Thickness.getValueAs("mm")) + "\n" - f.write(section_def) - f.write(section_geo) - else: # solid mesh - elsetdef = "ELSET=" + ccx_elset["ccx_elset_name"] + ", " - material = "MATERIAL=" + ccx_elset["mat_obj_name"] - section_def = "*SOLID SECTION, " + elsetdef + material + "\n" - f.write(section_def) - - -# ************************************************************************************************ -# Helpers -def liquid_section_def(obj, section_type): - if section_type == "PIPE MANNING": - manning_area = str(obj.ManningArea.getValueAs("mm^2").Value) - manning_radius = str(obj.ManningRadius.getValueAs("mm")) - manning_coefficient = str(obj.ManningCoefficient) - section_geo = manning_area + "," + manning_radius + "," + manning_coefficient + "\n" - return section_geo - elif section_type == "PIPE ENLARGEMENT": - enlarge_area1 = str(obj.EnlargeArea1.getValueAs("mm^2").Value) - enlarge_area2 = str(obj.EnlargeArea2.getValueAs("mm^2").Value) - section_geo = enlarge_area1 + "," + enlarge_area2 + "\n" - return section_geo - elif section_type == "PIPE CONTRACTION": - contract_area1 = str(obj.ContractArea1.getValueAs("mm^2").Value) - contract_area2 = str(obj.ContractArea2.getValueAs("mm^2").Value) - section_geo = contract_area1 + "," + contract_area2 + "\n" - return section_geo - elif section_type == "PIPE ENTRANCE": - entrance_pipe_area = str(obj.EntrancePipeArea.getValueAs("mm^2").Value) - entrance_area = str(obj.EntranceArea.getValueAs("mm^2").Value) - section_geo = entrance_pipe_area + "," + entrance_area + "\n" - return section_geo - elif section_type == "PIPE DIAPHRAGM": - diaphragm_pipe_area = str(obj.DiaphragmPipeArea.getValueAs("mm^2").Value) - diaphragm_area = str(obj.DiaphragmArea.getValueAs("mm^2").Value) - section_geo = diaphragm_pipe_area + "," + diaphragm_area + "\n" - return section_geo - elif section_type == "PIPE BEND": - bend_pipe_area = str(obj.BendPipeArea.getValueAs("mm^2").Value) - bend_radius_diameter = str(obj.BendRadiusDiameter) - bend_angle = str(obj.BendAngle) - bend_loss_coefficient = str(obj.BendLossCoefficient) - section_geo = ("{},{},{},{}\n".format( - bend_pipe_area, - bend_radius_diameter, - bend_angle, - bend_loss_coefficient - )) - return section_geo - elif section_type == "PIPE GATE VALVE": - gatevalve_pipe_area = str(obj.GateValvePipeArea.getValueAs("mm^2").Value) - gatevalve_closing_coeff = str(obj.GateValveClosingCoeff) - section_geo = gatevalve_pipe_area + "," + gatevalve_closing_coeff + "\n" - return section_geo - elif section_type == "PIPE WHITE-COLEBROOK": - colebrooke_area = str(obj.ColebrookeArea.getValueAs("mm^2").Value) - colebrooke_diameter = str(2 * obj.ColebrookeRadius.getValueAs("mm")) - colebrooke_grain_diameter = str(obj.ColebrookeGrainDiameter.getValueAs("mm")) - colebrooke_form_factor = str(obj.ColebrookeFormFactor) - section_geo = ("{},{},{},{},{}\n".format( - colebrooke_area, - colebrooke_diameter, - "-1", - colebrooke_grain_diameter, - colebrooke_form_factor - )) - return section_geo - elif section_type == "LIQUID PUMP": - section_geo = "" - for i in range(len(obj.PumpFlowRate)): - flow_rate = str(obj.PumpFlowRate[i]) - top = str(obj.PumpHeadLoss[i]) - section_geo = section_geo + flow_rate + "," + top + "," - section_geo = section_geo + "\n" - return section_geo - else: - return "" ## @}