From 240e2aa8165f703fb7bacf6273415237b738633f Mon Sep 17 00:00:00 2001 From: Uwe Date: Tue, 7 Feb 2023 01:21:01 +0100 Subject: [PATCH] [FEM] Elmer writer: sort out heat equation - sort out heat equation - next step to refactor writer.py --- src/Mod/Fem/CMakeLists.txt | 1 + .../femsolver/elmer/equations/heat_writer.py | 199 ++++++++++++++ src/Mod/Fem/femsolver/elmer/writer.py | 246 ++++-------------- 3 files changed, 245 insertions(+), 201 deletions(-) create mode 100644 src/Mod/Fem/femsolver/elmer/equations/heat_writer.py diff --git a/src/Mod/Fem/CMakeLists.txt b/src/Mod/Fem/CMakeLists.txt index 0b014d069f..4c7c6e1b84 100755 --- a/src/Mod/Fem/CMakeLists.txt +++ b/src/Mod/Fem/CMakeLists.txt @@ -259,6 +259,7 @@ SET(FemSolverElmerEquations_SRCS femsolver/elmer/equations/flow.py femsolver/elmer/equations/flux.py femsolver/elmer/equations/heat.py + femsolver/elmer/equations/heat_writer.py femsolver/elmer/equations/linear.py femsolver/elmer/equations/nonlinear.py ) diff --git a/src/Mod/Fem/femsolver/elmer/equations/heat_writer.py b/src/Mod/Fem/femsolver/elmer/equations/heat_writer.py new file mode 100644 index 0000000000..3ff1e9094d --- /dev/null +++ b/src/Mod/Fem/femsolver/elmer/equations/heat_writer.py @@ -0,0 +1,199 @@ +# *************************************************************************** +# * Copyright (c) 2023 Uwe Stöhr * +# * * +# * 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 Heat Elmer writer" +__author__ = "Uwe Stöhr" +__url__ = "https://www.freecad.org" + +## \addtogroup FEM +# @{ + +from .. import sifio +from .. import writer as general_writer +from femtools import membertools +from femmesh import meshtools +from . import heat + +class Heatwriter: + + def __init__(self, writer, solver): + self.write = writer + self.solver = solver + + def getHeatSolver(self, equation): + # check if we need to update the equation + self._updateHeatSolver(equation) + # output the equation parameters + s = self.write.createNonlinearSolver(equation) + s["Equation"] = equation.Name + s["Procedure"] = sifio.FileAttr("HeatSolve/HeatSolver") + s["Bubbles"] = equation.Bubbles + s["Exec Solver"] = "Always" + s["Optimize Bandwidth"] = True + s["Stabilize"] = equation.Stabilize + s["Variable"] = self.write.getUniqueVarName("Temperature") + return s + + def handleHeatConstants(self): + self.write.constant( + "Stefan Boltzmann", + self.write.convert(self.write.constsdef["StefanBoltzmann"], "M/(O^4*T^3)") + ) + + def handleHeatEquation(self, bodies, equation): + for b in bodies: + if equation.Convection != "None": + self.write.equation(b, "Convection", equation.Convection) + if equation.PhaseChangeModel != "None": + self.write.equation(b, "Phase Change Model", equation.PhaseChangeModel) + + def _updateHeatSolver(self, equation): + # updates older Heat equations + if not hasattr(equation, "Convection"): + equation.addProperty( + "App::PropertyEnumeration", + "Convection", + "Equation", + "Type of convection to be used" + ) + equation.Convection = heat.CONVECTION_TYPE + equation.Convection = "None" + if not hasattr(equation, "PhaseChangeModel"): + equation.addProperty( + "App::PropertyEnumeration", + "PhaseChangeModel", + "Equation", + "Model for phase change" + ) + equation.PhaseChangeModel = heat.PHASE_CHANGE_MODEL + equation.PhaseChangeModel = "None" + + def handleHeatBndConditions(self): + i = -1 + for obj in self.write.getMember("Fem::ConstraintTemperature"): + i = i + 1 + femobjects = membertools.get_several_member(self.write.analysis, "Fem::ConstraintTemperature") + femobjects[i]["Nodes"] = meshtools.get_femnodes_by_femobj_with_references( + self.write.getSingleMember("Fem::FemMeshObject").FemMesh, + femobjects[i] + ) + NumberOfNodes = len(femobjects[i]["Nodes"]) + if obj.References: + for name in obj.References[0][1]: + if obj.ConstraintType == "Temperature": + temp = self.write.getFromUi(obj.Temperature, "K", "O") + self.write.boundary(name, "Temperature", temp) + elif obj.ConstraintType == "CFlux": + # the CFLUX property stores the value in µW + # but the unit system is not aware of µW, only of mW + flux = 0.001 * self.write.getFromUi(obj.CFlux, "mW", "M*L^2*T^-3") + # CFLUX is the flux per mesh node + flux = flux / NumberOfNodes + self.write.boundary(name, "Temperature Load", flux) + self.write.handled(obj) + for obj in self.write.getMember("Fem::ConstraintHeatflux"): + if obj.References: + for name in obj.References[0][1]: + if obj.ConstraintType == "Convection": + film = self.write.getFromUi(obj.FilmCoef, "W/(m^2*K)", "M/(T^3*O)") + temp = self.write.getFromUi(obj.AmbientTemp, "K", "O") + self.write.boundary(name, "Heat Transfer Coefficient", film) + self.write.boundary(name, "External Temperature", temp) + elif obj.ConstraintType == "DFlux": + flux = self.write.getFromUi(obj.DFlux, "W/m^2", "M*T^-3") + self.write.boundary(name, "Heat Flux BC", True) + self.write.boundary(name, "Heat Flux", flux) + self.write.handled(obj) + + def handleHeatInitial(self, bodies): + obj = self.write.getSingleMember("Fem::ConstraintInitialTemperature") + if obj is not None: + for name in bodies: + temp = self.write.getFromUi(obj.initialTemperature, "K", "O") + self.write.initial(name, "Temperature", temp) + self.write.handled(obj) + + def _outputHeatBodyForce(self, obj, name): + heatSource = self.write.getFromUi(obj.HeatSource, "W/kg", "L^2*T^-3") + if heatSource == 0.0: + # a zero heat would break Elmer (division by zero) + raise general_writer.WriteError("The body heat source must not be zero!") + self.write.bodyForce(name, "Heat Source", heatSource) + + def handleHeatBodyForces(self, bodies): + bodyHeats = self.write.getMember("Fem::ConstraintBodyHeatSource") + for obj in bodyHeats: + if obj.References: + for name in obj.References[0][1]: + self._outputHeatBodyForce(obj, name) + self.write.handled(obj) + else: + # if there is only one body heat without a reference + # add it to all bodies + if len(bodyHeats) == 1: + for name in bodies: + self._outputHeatBodyForce(obj, name) + else: + raise general_writer.WriteError( + "Several body heat constraints found without reference to a body.\n" + "Please set a body for each body heat constraint." + ) + self.write.handled(obj) + + def handleHeatMaterial(self, bodies): + tempObj = self.write.getSingleMember("Fem::ConstraintInitialTemperature") + if tempObj is not None: + refTemp = self.write.getFromUi(tempObj.initialTemperature, "K", "O") + for name in bodies: + self.write.material(name, "Reference Temperature", refTemp) + for obj in self.write.getMember("App::MaterialObject"): + m = obj.Material + refs = ( + obj.References[0][1] + if obj.References + else self.write.getAllBodies()) + for name in (n for n in refs if n in bodies): + if "Density" not in m: + raise general_writer.WriteError( + "Used material does not specify the necessary 'Density'." + ) + self.write.material(name, "Name", m["Name"]) + self.write.material( + name, "Density", + self.write.getDensity(m)) + if "ThermalConductivity" not in m: + raise general_writer.WriteError( + "Used material does not specify the necessary 'Thermal Conductivity'." + ) + self.write.material( + name, "Heat Conductivity", + self.write.convert(m["ThermalConductivity"], "M*L/(T^3*O)")) + if "SpecificHeat" not in m: + raise general_writer.WriteError( + "Used material does not specify the necessary 'Specific Heat'." + ) + self.write.material( + name, "Heat Capacity", + self.write.convert(m["SpecificHeat"], "L^2/(T^2*O)")) + +## @} diff --git a/src/Mod/Fem/femsolver/elmer/writer.py b/src/Mod/Fem/femsolver/elmer/writer.py index 65fb9a1c98..34f5d9b29c 100644 --- a/src/Mod/Fem/femsolver/elmer/writer.py +++ b/src/Mod/Fem/femsolver/elmer/writer.py @@ -45,7 +45,6 @@ from . import sifio from . import solver as solverClass from .. import settings from femmesh import gmshtools -from femmesh import meshtools from femtools import constants from femtools import femutils from femtools import membertools @@ -54,7 +53,7 @@ from .equations import electricforce from .equations import electrostatic_writer as ES_writer from .equations import flow from .equations import flux -from .equations import heat +from .equations import heat_writer _STARTINFO_NAME = "ELMERSOLVER_STARTINFO" @@ -181,7 +180,7 @@ class Writer(object): .format(Units.listSchemas(self.unit_schema)) ) - def _getFromUi(self, value, unit, outputDim): + def getFromUi(self, value, unit, outputDim): quantity = Units.Quantity(str(value) + str(unit)) return self.convert(quantity, outputDim) @@ -201,7 +200,7 @@ class Writer(object): } def _writeMesh(self): - mesh = self._getSingleMember("Fem::FemMeshObject") + mesh = self.getSingleMember("Fem::FemMeshObject") unvPath = os.path.join(self.directory, "mesh.unv") groups = [] groups.extend(self._builder.getBodyNames()) @@ -682,7 +681,7 @@ class Writer(object): for obj in self.getMember("Fem::ConstraintPressure"): if obj.References: for name in obj.References[0][1]: - pressure = self._getFromUi(obj.Pressure, "MPa", "M/(L*T^2)") + pressure = self.getFromUi(obj.Pressure, "MPa", "M/(L*T^2)") if not obj.Reversed: pressure *= -1 self.boundary(name, "Normal Force", pressure) @@ -697,7 +696,7 @@ class Writer(object): for obj in self.getMember("Fem::ConstraintForce"): if obj.References: for name in obj.References[0][1]: - force = self._getFromUi(obj.Force, "N", "M*L*T^-2") + force = self.getFromUi(obj.Force, "N", "M*L*T^-2") self.boundary(name, "Force 1", obj.DirectionVector.x * force) self.boundary(name, "Force 2", obj.DirectionVector.y * force) self.boundary(name, "Force 3", obj.DirectionVector.z * force) @@ -729,7 +728,7 @@ class Writer(object): pass def _handleElasticityBodyForces(self, bodies): - obj = self._getSingleMember("Fem::ConstraintSelfWeight") + obj = self.getSingleMember("Fem::ConstraintSelfWeight") if obj is not None: for name in bodies: gravity = self.convert(self.constsdef["Gravity"], "L/T^2") @@ -775,13 +774,13 @@ class Writer(object): if equation.EigenAnalysis is True: density_needed = True break # there could be a second equation without frequency - gravObj = self._getSingleMember("Fem::ConstraintSelfWeight") + gravObj = self.getSingleMember("Fem::ConstraintSelfWeight") if gravObj is not None: density_needed = True # temperature - tempObj = self._getSingleMember("Fem::ConstraintInitialTemperature") + tempObj = self.getSingleMember("Fem::ConstraintInitialTemperature") if tempObj is not None: - refTemp = self._getFromUi(tempObj.initialTemperature, "K", "O") + refTemp = self.getFromUi(tempObj.initialTemperature, "K", "O") for name in bodies: self.material(name, "Reference Temperature", refTemp) # get the material data for all bodies @@ -809,7 +808,7 @@ class Writer(object): if density_needed is True: self.material( name, "Density", - self._getDensity(m) + self.getDensity(m) ) self.material( name, "Youngs Modulus", @@ -825,12 +824,6 @@ class Writer(object): self.convert(m["ThermalExpansionCoefficient"], "O^-1") ) - def _getDensity(self, m): - density = self.convert(m["Density"], "M/L^3") - if self._getMeshDimension() == 2: - density *= 1e3 - return density - def _getYoungsModulus(self, m): youngsModulus = self.convert(m["YoungsModulus"], "M/(L*T^2)") if self._getMeshDimension() == 2: @@ -929,7 +922,7 @@ class Writer(object): # check if we need to update the equation self._updateFlowSolver(equation) # output the equation parameters - s = self._createNonlinearSolver(equation) + s = self.createNonlinearSolver(equation) s["Equation"] = "Navier-Stokes" s["Procedure"] = sifio.FileAttr("FlowSolve/FlowSolver") if equation.DivDiscretization is True: @@ -1009,9 +1002,9 @@ class Writer(object): equation.Variable = "Flow Solution[Velocity:3 Pressure:1]" def _handleFlowMaterial(self, bodies): - tempObj = self._getSingleMember("Fem::ConstraintInitialTemperature") + tempObj = self.getSingleMember("Fem::ConstraintInitialTemperature") if tempObj is not None: - refTemp = self._getFromUi(tempObj.initialTemperature, "K", "O") + refTemp = self.getFromUi(tempObj.initialTemperature, "K", "O") for name in bodies: self.material(name, "Reference Temperature", refTemp) for obj in self.getMember("App::MaterialObject"): @@ -1025,7 +1018,7 @@ class Writer(object): if "Density" in m: self.material( name, "Density", - self._getDensity(m) + self.getDensity(m) ) if "ThermalConductivity" in m: self.material( @@ -1033,7 +1026,7 @@ class Writer(object): self.convert(m["ThermalConductivity"], "M*L/(T^3*O)") ) if "KinematicViscosity" in m: - density = self._getDensity(m) + density = self.getDensity(m) kViscosity = self.convert(m["KinematicViscosity"], "L^2/T") self.material( name, "Viscosity", kViscosity * density) @@ -1059,7 +1052,7 @@ class Writer(object): # initial pressure only makes sense for fluid material if self._isBodyMaterialFluid(name): pressure = float(obj.Pressure.getValueAs("Pa")) - self._initial(name, "Pressure", pressure) + self.initial(name, "Pressure", pressure) def _handleFlowInitialPressure(self, bodies): initialPressures = self.getMember("Fem::ConstraintInitialPressure") @@ -1085,14 +1078,14 @@ class Writer(object): # flow only makes sense for fluid material if self._isBodyMaterialFluid(name): if obj.VelocityXEnabled: - velocity = self._getFromUi(obj.VelocityX, "m/s", "L/T") - self._initial(name, "Velocity 1", velocity) + velocity = self.getFromUi(obj.VelocityX, "m/s", "L/T") + self.initial(name, "Velocity 1", velocity) if obj.VelocityYEnabled: - velocity = self._getFromUi(obj.VelocityY, "m/s", "L/T") - self._initial(name, "Velocity 2", velocity) + velocity = self.getFromUi(obj.VelocityY, "m/s", "L/T") + self.initial(name, "Velocity 2", velocity) if obj.VelocityZEnabled: - velocity = self._getFromUi(obj.VelocityZ, "m/s", "L/T") - self._initial(name, "Velocity 3", velocity) + velocity = self.getFromUi(obj.VelocityZ, "m/s", "L/T") + self.initial(name, "Velocity 3", velocity) def _handleFlowInitialVelocity(self, bodies): initialVelocities = self.getMember("Fem::ConstraintInitialFlowVelocity") @@ -1119,13 +1112,13 @@ class Writer(object): if obj.References: for name in obj.References[0][1]: if obj.VelocityXEnabled: - velocity = self._getFromUi(obj.VelocityX, "m/s", "L/T") + velocity = self.getFromUi(obj.VelocityX, "m/s", "L/T") self.boundary(name, "Velocity 1", velocity) if obj.VelocityYEnabled: - velocity = self._getFromUi(obj.VelocityY, "m/s", "L/T") + velocity = self.getFromUi(obj.VelocityY, "m/s", "L/T") self.boundary(name, "Velocity 2", velocity) if obj.VelocityZEnabled: - velocity = self._getFromUi(obj.VelocityZ, "m/s", "L/T") + velocity = self.getFromUi(obj.VelocityZ, "m/s", "L/T") self.boundary(name, "Velocity 3", velocity) if obj.NormalToBoundary: self.boundary(name, "Normal-Tangential Velocity", True) @@ -1133,7 +1126,7 @@ class Writer(object): for obj in self.getMember("Fem::ConstraintPressure"): if obj.References: for name in obj.References[0][1]: - pressure = self._getFromUi(obj.Pressure, "MPa", "M/(L*T^2)") + pressure = self.getFromUi(obj.Pressure, "MPa", "M/(L*T^2)") if obj.Reversed: pressure *= -1 self.boundary(name, "External Pressure", pressure) @@ -1293,6 +1286,7 @@ class Writer(object): # Heat def _handleHeat(self): + HeatW = heat_writer.Heatwriter(self, self.solver) activeIn = [] for equation in self.solver.Group: if femutils.is_of_type(equation, "Fem::EquationElmerHeat"): @@ -1300,172 +1294,16 @@ class Writer(object): activeIn = equation.References[0][1] else: activeIn = self.getAllBodies() - solverSection = self._getHeatSolver(equation) + solverSection = HeatW.getHeatSolver(equation) for body in activeIn: self._addSolver(body, solverSection) - self._handleHeatEquation(activeIn, equation) + HeatW.handleHeatEquation(activeIn, equation) if activeIn: - self._handleHeatConstants() - self._handleHeatBndConditions() - self._handleHeatInitial(activeIn) - self._handleHeatBodyForces(activeIn) - self._handleHeatMaterial(activeIn) - - def _getHeatSolver(self, equation): - # check if we need to update the equation - self._updateHeatSolver(equation) - # output the equation parameters - s = self._createNonlinearSolver(equation) - s["Equation"] = equation.Name - s["Procedure"] = sifio.FileAttr("HeatSolve/HeatSolver") - s["Bubbles"] = equation.Bubbles - s["Exec Solver"] = "Always" - s["Optimize Bandwidth"] = True - s["Stabilize"] = equation.Stabilize - s["Variable"] = self.getUniqueVarName("Temperature") - return s - - def _handleHeatConstants(self): - self.constant( - "Stefan Boltzmann", - self.convert(self.constsdef["StefanBoltzmann"], "M/(O^4*T^3)") - ) - - def _handleHeatEquation(self, bodies, equation): - for b in bodies: - if equation.Convection != "None": - self._equation(b, "Convection", equation.Convection) - if equation.PhaseChangeModel != "None": - self._equation(b, "Phase Change Model", equation.PhaseChangeModel) - - def _updateHeatSolver(self, equation): - # updates older Heat equations - if not hasattr(equation, "Convection"): - equation.addProperty( - "App::PropertyEnumeration", - "Convection", - "Equation", - "Type of convection to be used" - ) - equation.Convection = heat.CONVECTION_TYPE - equation.Convection = "None" - if not hasattr(equation, "PhaseChangeModel"): - equation.addProperty( - "App::PropertyEnumeration", - "PhaseChangeModel", - "Equation", - "Model for phase change" - ) - equation.PhaseChangeModel = heat.PHASE_CHANGE_MODEL - equation.PhaseChangeModel = "None" - - def _handleHeatBndConditions(self): - i = -1 - for obj in self.getMember("Fem::ConstraintTemperature"): - i = i + 1 - femobjects = membertools.get_several_member(self.analysis, "Fem::ConstraintTemperature") - femobjects[i]["Nodes"] = meshtools.get_femnodes_by_femobj_with_references( - self._getSingleMember("Fem::FemMeshObject").FemMesh, - femobjects[i] - ) - NumberOfNodes = len(femobjects[i]["Nodes"]) - if obj.References: - for name in obj.References[0][1]: - if obj.ConstraintType == "Temperature": - temp = self._getFromUi(obj.Temperature, "K", "O") - self.boundary(name, "Temperature", temp) - elif obj.ConstraintType == "CFlux": - # the CFLUX property stores the value in µW - # but the unit system is not aware of µW, only of mW - flux = 0.001 * self._getFromUi(obj.CFlux, "mW", "M*L^2*T^-3") - # CFLUX is the flux per mesh node - flux = flux / NumberOfNodes - self.boundary(name, "Temperature Load", flux) - self.handled(obj) - for obj in self.getMember("Fem::ConstraintHeatflux"): - if obj.References: - for name in obj.References[0][1]: - if obj.ConstraintType == "Convection": - film = self._getFromUi(obj.FilmCoef, "W/(m^2*K)", "M/(T^3*O)") - temp = self._getFromUi(obj.AmbientTemp, "K", "O") - self.boundary(name, "Heat Transfer Coefficient", film) - self.boundary(name, "External Temperature", temp) - elif obj.ConstraintType == "DFlux": - flux = self._getFromUi(obj.DFlux, "W/m^2", "M*T^-3") - self.boundary(name, "Heat Flux BC", True) - self.boundary(name, "Heat Flux", flux) - self.handled(obj) - - def _handleHeatInitial(self, bodies): - obj = self._getSingleMember("Fem::ConstraintInitialTemperature") - if obj is not None: - for name in bodies: - temp = self._getFromUi(obj.initialTemperature, "K", "O") - self._initial(name, "Temperature", temp) - self.handled(obj) - - def _outputHeatBodyForce(self, obj, name): - heatSource = self._getFromUi(obj.HeatSource, "W/kg", "L^2*T^-3") - if heatSource == 0.0: - # a zero heat would break Elmer (division by zero) - raise WriteError("The body heat source must not be zero!") - self._bodyForce(name, "Heat Source", heatSource) - - def _handleHeatBodyForces(self, bodies): - bodyHeats = self.getMember("Fem::ConstraintBodyHeatSource") - for obj in bodyHeats: - if obj.References: - for name in obj.References[0][1]: - self._outputHeatBodyForce(obj, name) - self.handled(obj) - else: - # if there is only one body heat without a reference - # add it to all bodies - if len(bodyHeats) == 1: - for name in bodies: - self._outputHeatBodyForce(obj, name) - else: - raise WriteError( - "Several body heat constraints found without reference to a body.\n" - "Please set a body for each body heat constraint." - ) - self.handled(obj) - - def _handleHeatMaterial(self, bodies): - tempObj = self._getSingleMember("Fem::ConstraintInitialTemperature") - if tempObj is not None: - refTemp = self._getFromUi(tempObj.initialTemperature, "K", "O") - for name in bodies: - self.material(name, "Reference Temperature", refTemp) - for obj in self.getMember("App::MaterialObject"): - m = obj.Material - refs = ( - obj.References[0][1] - if obj.References - else self.getAllBodies()) - for name in (n for n in refs if n in bodies): - if "Density" not in m: - raise WriteError( - "Used material does not specify the necessary 'Density'." - ) - self.material(name, "Name", m["Name"]) - self.material( - name, "Density", - self._getDensity(m)) - if "ThermalConductivity" not in m: - raise WriteError( - "Used material does not specify the necessary 'Thermal Conductivity'." - ) - self.material( - name, "Heat Conductivity", - self.convert(m["ThermalConductivity"], "M*L/(T^3*O)")) - if "SpecificHeat" not in m: - raise WriteError( - "Used material does not specify the necessary 'Specific Heat'." - ) - self.material( - name, "Heat Capacity", - self.convert(m["SpecificHeat"], "L^2/(T^2*O)")) + HeatW.handleHeatConstants() + HeatW.handleHeatBndConditions() + HeatW.handleHeatInitial(activeIn) + HeatW.handleHeatBodyForces(activeIn) + HeatW.handleHeatMaterial(activeIn) #------------------------------------------------------------------------------------------- # Solver handling @@ -1544,7 +1382,7 @@ class Writer(object): str(equation.NonlinearNewtonAfterTolerance) ) - def _createNonlinearSolver(self, equation): + def createNonlinearSolver(self, equation): # first check if we have to update self._updateNonlinearSolver(equation) # write the linear solver @@ -1589,6 +1427,12 @@ class Writer(object): return "KinematicViscosity" in m return False + def getDensity(self, m): + density = self.convert(m["Density"], "M/L^3") + if self._getMeshDimension() == 2: + density *= 1e3 + return density + def _hasExpression(self, equation): for (obj, exp) in equation.ExpressionEngine: if obj == equation: @@ -1606,7 +1450,7 @@ class Writer(object): return varName def getAllBodies(self): - obj = self._getSingleMember("Fem::FemMeshObject") + obj = self.getSingleMember("Fem::FemMeshObject") bodyCount = 0 prefix = "" if obj.Part.Shape.Solids: @@ -1621,7 +1465,7 @@ class Writer(object): return [prefix + str(i + 1) for i in range(bodyCount)] def _getMeshDimension(self): - obj = self._getSingleMember("Fem::FemMeshObject") + obj = self.getSingleMember("Fem::FemMeshObject") if obj.Part.Shape.Solids: return 3 if obj.Part.Shape.Faces: @@ -1665,7 +1509,7 @@ class Writer(object): def constant(self, key, attr): self._builder.constant(key, attr) - def _initial(self, body, key, attr): + def initial(self, body, key, attr): self._builder.initial(body, key, attr) def material(self, body, key, attr): @@ -1689,7 +1533,7 @@ class Writer(object): def getMember(self, t): return membertools.get_member(self.analysis, t) - def _getSingleMember(self, t): + def getSingleMember(self, t): return membertools.get_single_member(self.analysis, t)