From 4ac2f8fe1a3b76a6ab5e9b7bd6205573b975eaed Mon Sep 17 00:00:00 2001 From: Uwe Date: Sun, 5 Feb 2023 18:58:58 +0100 Subject: [PATCH] [FEM] Elmer: refactor writer for electrostatics - the writer.py is to large to keep the overview, thus sort out the handling of the different equations (also since more equations will be added) - This PR sorts out the electrostatic equation handling as first step (more equations will follow once this is merged) --- src/Mod/Fem/CMakeLists.txt | 1 + .../elmer/equations/electrostatic_writer.py | 155 +++++++ src/Mod/Fem/femsolver/elmer/writer.py | 378 ++++++------------ 3 files changed, 287 insertions(+), 247 deletions(-) create mode 100644 src/Mod/Fem/femsolver/elmer/equations/electrostatic_writer.py diff --git a/src/Mod/Fem/CMakeLists.txt b/src/Mod/Fem/CMakeLists.txt index c0e51cea9e..0b014d069f 100755 --- a/src/Mod/Fem/CMakeLists.txt +++ b/src/Mod/Fem/CMakeLists.txt @@ -254,6 +254,7 @@ SET(FemSolverElmerEquations_SRCS femsolver/elmer/equations/elasticity.py femsolver/elmer/equations/electricforce.py femsolver/elmer/equations/electrostatic.py + femsolver/elmer/equations/electrostatic_writer.py femsolver/elmer/equations/equation.py femsolver/elmer/equations/flow.py femsolver/elmer/equations/flux.py diff --git a/src/Mod/Fem/femsolver/elmer/equations/electrostatic_writer.py b/src/Mod/Fem/femsolver/elmer/equations/electrostatic_writer.py new file mode 100644 index 0000000000..916f77c41d --- /dev/null +++ b/src/Mod/Fem/femsolver/elmer/equations/electrostatic_writer.py @@ -0,0 +1,155 @@ +# *************************************************************************** +# * 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 Electrostatics Elmer writer" +__author__ = "Uwe Stöhr" +__url__ = "https://www.freecad.org" + +## \addtogroup FEM +# @{ + +from .. import sifio + +class ESwriter: + + def __init__(self, writer, solver): + self.write = writer + self.solver = solver + + def getElectrostaticSolver(self, equation): + # check if we need to update the equation + self._updateElectrostaticSolver(equation) + # output the equation parameters + s = self.write.createLinearSolver(equation) + s["Equation"] = "Stat Elec Solver" # equation.Name + s["Procedure"] = sifio.FileAttr("StatElecSolve/StatElecSolver") + s["Variable"] = self.write.getUniqueVarName("Potential") + s["Variable DOFs"] = 1 + if equation.CalculateCapacitanceMatrix is True: + s["Calculate Capacitance Matrix"] = equation.CalculateCapacitanceMatrix + s["Capacitance Matrix Filename"] = equation.CapacitanceMatrixFilename + if equation.CalculateElectricEnergy is True: + s["Calculate Electric Energy"] = equation.CalculateElectricEnergy + if equation.CalculateElectricField is True: + s["Calculate Electric Field"] = equation.CalculateElectricField + if equation.CalculateElectricFlux is True: + s["Calculate Electric Flux"] = equation.CalculateElectricFlux + if equation.CalculateSurfaceCharge is True: + s["Calculate Surface Charge"] = equation.CalculateSurfaceCharge + if equation.ConstantWeights is True: + s["Constant Weights"] = equation.ConstantWeights + s["Exec Solver"] = "Always" + s["Optimize Bandwidth"] = True + if ( + equation.CalculateCapacitanceMatrix is False + and (equation.PotentialDifference != 0.0) + ): + s["Potential Difference"] = equation.PotentialDifference + s["Stabilize"] = equation.Stabilize + return s + + def _updateElectrostaticSolver(self, equation): + # updates older Electrostatic equations + if not hasattr(equation, "CapacitanceMatrixFilename"): + equation.addProperty( + "App::PropertyFile", + "CapacitanceMatrixFilename", + "Electrostatic", + ( + "File where capacitance matrix is being saved\n" + "Only used if 'CalculateCapacitanceMatrix' is true" + ) + ) + equation.CapacitanceMatrixFilename = "cmatrix.dat" + if not hasattr(equation, "ConstantWeights"): + equation.addProperty( + "App::PropertyBool", + "ConstantWeights", + "Electrostatic", + "Use constant weighting for results" + ) + if not hasattr(equation, "PotentialDifference"): + equation.addProperty( + "App::PropertyFloat", + "PotentialDifference", + "Electrostatic", + ( + "Potential difference in Volt for which capacitance is\n" + "calculated if 'CalculateCapacitanceMatrix' is false" + ) + ) + equation.PotentialDifference = 0.0 + + def handleElectrostaticConstants(self): + self.write.constant( + "Permittivity Of Vacuum", + self.write.convert(self.write.constsdef["PermittivityOfVacuum"], "T^4*I^2/(L^3*M)") + ) + + def handleElectrostaticMaterial(self, bodies): + 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): + self.write.material(name, "Name", m["Name"]) + if "RelativePermittivity" in m: + self.write.material( + name, "Relative Permittivity", + float(m["RelativePermittivity"]) + ) + + def handleElectrostaticBndConditions(self): + for obj in self.write.getMember("Fem::ConstraintElectrostaticPotential"): + if obj.References: + for name in obj.References[0][1]: + if obj.PotentialEnabled: + if hasattr(obj, "Potential"): + # Potential was once a float and scaled not fitting SI units + if isinstance(obj.Potential, float): + savePotential = obj.Potential + obj.removeProperty("Potential") + obj.addProperty( + "App::PropertyElectricPotential", + "Potential", + "Parameter", + "Electric Potential" + ) + # scale to match SI units + obj.Potential = savePotential * 1e6 + potential = float(obj.Potential.getValueAs("V")) + self.write.boundary(name, "Potential", potential) + if obj.PotentialConstant: + self.write.boundary(name, "Potential Constant", True) + if obj.ElectricInfinity: + self.write.boundary(name, "Electric Infinity BC", True) + if obj.ElectricForcecalculation: + self.write.boundary(name, "Calculate Electric Force", True) + if obj.CapacitanceBodyEnabled: + if hasattr(obj, "CapacitanceBody"): + self.write.boundary(name, "Capacitance Body", obj.CapacitanceBody) + self.write.handled(obj) + +## @} diff --git a/src/Mod/Fem/femsolver/elmer/writer.py b/src/Mod/Fem/femsolver/elmer/writer.py index b3ec351777..65fb9a1c98 100644 --- a/src/Mod/Fem/femsolver/elmer/writer.py +++ b/src/Mod/Fem/femsolver/elmer/writer.py @@ -51,6 +51,7 @@ from femtools import femutils from femtools import membertools from .equations import elasticity from .equations import electricforce +from .equations import electrostatic_writer as ES_writer from .equations import flow from .equations import flux from .equations import heat @@ -182,9 +183,9 @@ class Writer(object): def _getFromUi(self, value, unit, outputDim): quantity = Units.Quantity(str(value) + str(unit)) - return self._convert(quantity, outputDim) + return self.convert(quantity, outputDim) - def _convert(self, quantityStr, unit): + def convert(self, quantityStr, unit): quantity = Units.Quantity(quantityStr) for key, setting in self.unit_system.items(): unit = unit.replace(key, setting) @@ -294,14 +295,14 @@ class Writer(object): """ redefine constants in self.constsdef according constant redefine objects """ - objs = self._getMember("Fem::ConstantVacuumPermittivity") + objs = self.getMember("Fem::ConstantVacuumPermittivity") if len(objs) == 1: permittivity = float(objs[0].VacuumPermittivity.getValueAs("F/m")) # since the base unit of FC is in mm, we must scale it to get plain SI permittivity = permittivity * 1e-9 Console.PrintLog("Overwriting vacuum permittivity with: {}\n".format(permittivity)) self.constsdef["PermittivityOfVacuum"] = "{} {}".format(permittivity, "F/m") - self._handled(objs[0]) + self.handled(objs[0]) elif len(objs) > 1: Console.PrintError( "More than one permittivity constant overwriting objects ({} objs). " @@ -413,7 +414,7 @@ class Writer(object): if equation.References: activeIn = equation.References[0][1] else: - activeIn = self._getAllBodies() + activeIn = self.getAllBodies() solverSection = self._getElasticitySolver(equation) for body in activeIn: if not self._isBodyMaterialFluid(body): @@ -427,7 +428,7 @@ class Writer(object): self._handleElasticityMaterial(activeIn) def _getElasticitySolver(self, equation): - s = self._createLinearSolver(equation) + s = self.createLinearSolver(equation) # check if we need to update the equation self._updateElasticitySolver(equation) # output the equation parameters @@ -678,51 +679,51 @@ class Writer(object): pass def _handleElasticityBndConditions(self): - for obj in self._getMember("Fem::ConstraintPressure"): + 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)") if not obj.Reversed: pressure *= -1 - self._boundary(name, "Normal Force", pressure) - self._handled(obj) - for obj in self._getMember("Fem::ConstraintFixed"): + self.boundary(name, "Normal Force", pressure) + self.handled(obj) + for obj in self.getMember("Fem::ConstraintFixed"): if obj.References: for name in obj.References[0][1]: - self._boundary(name, "Displacement 1", 0.0) - self._boundary(name, "Displacement 2", 0.0) - self._boundary(name, "Displacement 3", 0.0) - self._handled(obj) - for obj in self._getMember("Fem::ConstraintForce"): + self.boundary(name, "Displacement 1", 0.0) + self.boundary(name, "Displacement 2", 0.0) + self.boundary(name, "Displacement 3", 0.0) + self.handled(obj) + 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") - 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) - self._boundary(name, "Force 1 Normalize by Area", True) - self._boundary(name, "Force 2 Normalize by Area", True) - self._boundary(name, "Force 3 Normalize by Area", True) - self._handled(obj) - for obj in self._getMember("Fem::ConstraintDisplacement"): + 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) + self.boundary(name, "Force 1 Normalize by Area", True) + self.boundary(name, "Force 2 Normalize by Area", True) + self.boundary(name, "Force 3 Normalize by Area", True) + self.handled(obj) + for obj in self.getMember("Fem::ConstraintDisplacement"): if obj.References: for name in obj.References[0][1]: if not obj.xFree: - self._boundary( + self.boundary( name, "Displacement 1", obj.xDisplacement * 0.001) elif obj.xFix: - self._boundary(name, "Displacement 1", 0.0) + self.boundary(name, "Displacement 1", 0.0) if not obj.yFree: - self._boundary( + self.boundary( name, "Displacement 2", obj.yDisplacement * 0.001) elif obj.yFix: - self._boundary(name, "Displacement 2", 0.0) + self.boundary(name, "Displacement 2", 0.0) if not obj.zFree: - self._boundary( + self.boundary( name, "Displacement 3", obj.zDisplacement * 0.001) elif obj.zFix: - self._boundary(name, "Displacement 3", 0.0) - self._handled(obj) + self.boundary(name, "Displacement 3", 0.0) + self.handled(obj) def _handleElasticityInitial(self, bodies): pass @@ -731,8 +732,8 @@ class Writer(object): obj = self._getSingleMember("Fem::ConstraintSelfWeight") if obj is not None: for name in bodies: - gravity = self._convert(self.constsdef["Gravity"], "L/T^2") - if self._getBodyMaterial(name) == None: + gravity = self.convert(self.constsdef["Gravity"], "L/T^2") + if self._getBodyMaterial(name) is None: raise WriteError( "The body {} is not referenced in any material.\n\n".format(name) ) @@ -745,7 +746,7 @@ class Writer(object): # TODO: test densityQuantity.Unit = Units.Unit(-2, 1) dimension = "M/L^2" - density = self._convert(densityQuantity, dimension) + density = self.convert(densityQuantity, dimension) force1 = gravity * obj.Gravity_x * density force2 = gravity * obj.Gravity_y * density @@ -753,10 +754,10 @@ class Writer(object): self._bodyForce(name, "Stress Bodyforce 1", force1) self._bodyForce(name, "Stress Bodyforce 2", force2) self._bodyForce(name, "Stress Bodyforce 3", force3) - self._handled(obj) + self.handled(obj) def _getBodyMaterial(self, name): - for obj in self._getMember("App::MaterialObject"): + for obj in self.getMember("App::MaterialObject"): # we can have e.g. the case there are 2 bodies and 2 materials # body 2 has material 2 as reference while material 1 has no reference # therefore we must not return a material when it is not referenced @@ -782,14 +783,14 @@ class Writer(object): if tempObj is not None: refTemp = self._getFromUi(tempObj.initialTemperature, "K", "O") for name in bodies: - self._material(name, "Reference Temperature", refTemp) + self.material(name, "Reference Temperature", refTemp) # get the material data for all bodies - for obj in self._getMember("App::MaterialObject"): + for obj in self.getMember("App::MaterialObject"): m = obj.Material refs = ( obj.References[0][1] if obj.References - else self._getAllBodies() + else self.getAllBodies() ) for name in (n for n in refs if n in bodies): # don't evaluate fluid material @@ -804,34 +805,34 @@ class Writer(object): "There are two or more materials with empty references.\n\n" "Set for the materials to what solid they belong to.\n" ) - self._material(name, "Name", m["Name"]) + self.material(name, "Name", m["Name"]) if density_needed is True: - self._material( + self.material( name, "Density", self._getDensity(m) ) - self._material( + self.material( name, "Youngs Modulus", self._getYoungsModulus(m) ) - self._material( + self.material( name, "Poisson ratio", float(m["PoissonRatio"]) ) if tempObj: - self._material( + self.material( name, "Heat expansion Coefficient", - self._convert(m["ThermalExpansionCoefficient"], "O^-1") + self.convert(m["ThermalExpansionCoefficient"], "O^-1") ) def _getDensity(self, m): - density = self._convert(m["Density"], "M/L^3") + 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)") + youngsModulus = self.convert(m["YoungsModulus"], "M/(L*T^2)") if self._getMeshDimension() == 2: youngsModulus *= 1e3 return youngsModulus @@ -840,138 +841,21 @@ class Writer(object): # Electrostatic def _handleElectrostatic(self): + ESW = ES_writer.ESwriter(self, self.solver) activeIn = [] for equation in self.solver.Group: if femutils.is_of_type(equation, "Fem::EquationElmerElectrostatic"): if equation.References: activeIn = equation.References[0][1] else: - activeIn = self._getAllBodies() - solverSection = self._getElectrostaticSolver(equation) + activeIn = self.getAllBodies() + solverSection = ESW.getElectrostaticSolver(equation) for body in activeIn: self._addSolver(body, solverSection) if activeIn: - self._handleElectrostaticConstants() - self._handleElectrostaticBndConditions() - self._handleElectrostaticMaterial(activeIn) - - def _getElectrostaticSolver(self, equation): - # check if we need to update the equation - self._updateElectrostaticSolver(equation) - # output the equation parameters - s = self._createLinearSolver(equation) - s["Equation"] = "Stat Elec Solver" # equation.Name - s["Procedure"] = sifio.FileAttr("StatElecSolve/StatElecSolver") - s["Variable"] = self._getUniqueVarName("Potential") - s["Variable DOFs"] = 1 - if equation.CalculateCapacitanceMatrix is True: - s["Calculate Capacitance Matrix"] = equation.CalculateCapacitanceMatrix - s["Capacitance Matrix Filename"] = equation.CapacitanceMatrixFilename - if equation.CalculateElectricEnergy is True: - s["Calculate Electric Energy"] = equation.CalculateElectricEnergy - if equation.CalculateElectricField is True: - s["Calculate Electric Field"] = equation.CalculateElectricField - if equation.CalculateElectricFlux is True: - s["Calculate Electric Flux"] = equation.CalculateElectricFlux - if equation.CalculateSurfaceCharge is True: - s["Calculate Surface Charge"] = equation.CalculateSurfaceCharge - if equation.ConstantWeights is True: - s["Constant Weights"] = equation.ConstantWeights - s["Exec Solver"] = "Always" - s["Optimize Bandwidth"] = True - if ( - equation.CalculateCapacitanceMatrix is False - and (equation.PotentialDifference != 0.0) - ): - s["Potential Difference"] = equation.PotentialDifference - s["Stabilize"] = equation.Stabilize - return s - - def _updateElectrostaticSolver(self, equation): - # updates older Electrostatic equations - if not hasattr(equation, "CapacitanceMatrixFilename"): - equation.addProperty( - "App::PropertyFile", - "CapacitanceMatrixFilename", - "Electrostatic", - ( - "File where capacitance matrix is being saved\n" - "Only used if 'CalculateCapacitanceMatrix' is true" - ) - ) - equation.CapacitanceMatrixFilename = "cmatrix.dat" - if not hasattr(equation, "ConstantWeights"): - equation.addProperty( - "App::PropertyBool", - "ConstantWeights", - "Electrostatic", - "Use constant weighting for results" - ) - if not hasattr(equation, "PotentialDifference"): - equation.addProperty( - "App::PropertyFloat", - "PotentialDifference", - "Electrostatic", - ( - "Potential difference in Volt for which capacitance is\n" - "calculated if 'CalculateCapacitanceMatrix' is false" - ) - ) - equation.PotentialDifference = 0.0 - - def _handleElectrostaticConstants(self): - permittivity = self._convert(self.constsdef["PermittivityOfVacuum"], "T^4*I^2/(L^3*M)") - permittivity = round(permittivity, 20) # to get rid of numerical artifacts - self._constant( - "Permittivity Of Vacuum", - permittivity - ) - - def _handleElectrostaticMaterial(self, bodies): - 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): - self._material(name, "Name", m["Name"]) - if "RelativePermittivity" in m: - self._material( - name, "Relative Permittivity", - float(m["RelativePermittivity"]) - ) - - def _handleElectrostaticBndConditions(self): - for obj in self._getMember("Fem::ConstraintElectrostaticPotential"): - if obj.References: - for name in obj.References[0][1]: - if obj.PotentialEnabled: - if hasattr(obj, "Potential"): - # Potential was once a float and scaled not fitting SI units - if isinstance(obj.Potential, float): - savePotential = obj.Potential - obj.removeProperty("Potential") - obj.addProperty( - "App::PropertyElectricPotential", - "Potential", - "Parameter", - "Electric Potential" - ) - # scale to match SI units - obj.Potential = savePotential * 1e6 - potential = float(obj.Potential.getValueAs("V")) - self._boundary(name, "Potential", potential) - if obj.PotentialConstant: - self._boundary(name, "Potential Constant", True) - if obj.ElectricInfinity: - self._boundary(name, "Electric Infinity BC", True) - if obj.ElectricForcecalculation: - self._boundary(name, "Calculate Electric Force", True) - if obj.CapacitanceBodyEnabled: - if hasattr(obj, "CapacitanceBody"): - self._boundary(name, "Capacitance Body", obj.CapacitanceBody) - self._handled(obj) + ESW.handleElectrostaticConstants() + ESW.handleElectrostaticBndConditions() + ESW.handleElectrostaticMaterial(activeIn) #------------------------------------------------------------------------------------------- # Electricforce @@ -983,7 +867,7 @@ class Writer(object): if equation.References: activeIn = equation.References[0][1] else: - activeIn = self._getAllBodies() + activeIn = self.getAllBodies() solverSection = self._getElectricforceSolver(equation) for body in activeIn: self._addSolver(body, solverSection) @@ -1028,7 +912,7 @@ class Writer(object): if equation.References: activeIn = equation.References[0][1] else: - activeIn = self._getAllBodies() + activeIn = self.getAllBodies() solverSection = self._getFlowSolver(equation) for body in activeIn: if self._isBodyMaterialFluid(body): @@ -1062,8 +946,8 @@ class Writer(object): return s def _handleFlowConstants(self): - gravity = self._convert(self.constsdef["Gravity"], "L/T^2") - self._constant("Gravity", (0.0, -1.0, 0.0, gravity)) + gravity = self.convert(self.constsdef["Gravity"], "L/T^2") + self.constant("Gravity", (0.0, -1.0, 0.0, gravity)) def _updateFlowSolver(self, equation): # updates older Flow equations @@ -1129,45 +1013,45 @@ class Writer(object): 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"): + 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()) + else self.getAllBodies()) for name in (n for n in refs if n in bodies): - self._material(name, "Name", m["Name"]) + self.material(name, "Name", m["Name"]) if "Density" in m: - self._material( + self.material( name, "Density", self._getDensity(m) ) if "ThermalConductivity" in m: - self._material( + self.material( name, "Heat Conductivity", - self._convert(m["ThermalConductivity"], "M*L/(T^3*O)") + self.convert(m["ThermalConductivity"], "M*L/(T^3*O)") ) if "KinematicViscosity" in m: density = self._getDensity(m) - kViscosity = self._convert(m["KinematicViscosity"], "L^2/T") - self._material( + kViscosity = self.convert(m["KinematicViscosity"], "L^2/T") + self.material( name, "Viscosity", kViscosity * density) if "ThermalExpansionCoefficient" in m: - value = self._convert(m["ThermalExpansionCoefficient"], "O^-1") + value = self.convert(m["ThermalExpansionCoefficient"], "O^-1") if value > 0: - self._material( + self.material( name, "Heat expansion Coefficient", value) if "ReferencePressure" in m: - pressure = self._convert(m["ReferencePressure"], "M/(L*T^2)") - self._material(name, "Reference Pressure", pressure) + pressure = self.convert(m["ReferencePressure"], "M/(L*T^2)") + self.material(name, "Reference Pressure", pressure) if "SpecificHeatRatio" in m: - self._material( + self.material( name, "Specific Heat Ratio", float(m["SpecificHeatRatio"]) ) if "CompressibilityModel" in m: - self._material( + self.material( name, "Compressibility Model", m["CompressibilityModel"]) @@ -1178,12 +1062,12 @@ class Writer(object): self._initial(name, "Pressure", pressure) def _handleFlowInitialPressure(self, bodies): - initialPressures = self._getMember("Fem::ConstraintInitialPressure") + initialPressures = self.getMember("Fem::ConstraintInitialPressure") for obj in initialPressures: if obj.References: for name in obj.References[0][1]: self._outputInitialPressure(obj, name) - self._handled(obj) + self.handled(obj) else: # if there is only one initial pressure without a reference # add it to all fluid bodies @@ -1195,7 +1079,7 @@ class Writer(object): "Several initial pressures found without reference to a body.\n" "Please set a body for each initial pressure." ) - self._handled(obj) + self.handled(obj) def _outputInitialVelocity(self, obj, name): # flow only makes sense for fluid material @@ -1211,12 +1095,12 @@ class Writer(object): self._initial(name, "Velocity 3", velocity) def _handleFlowInitialVelocity(self, bodies): - initialVelocities = self._getMember("Fem::ConstraintInitialFlowVelocity") + initialVelocities = self.getMember("Fem::ConstraintInitialFlowVelocity") for obj in initialVelocities: if obj.References: for name in obj.References[0][1]: self._outputInitialVelocity(obj, name) - self._handled(obj) + self.handled(obj) else: # if there is only one initial velocity without a reference # add it to all fluid bodies @@ -1228,32 +1112,32 @@ class Writer(object): "Several initial velocities found without reference to a body.\n" "Please set a body for each initial velocity." ) - self._handled(obj) + self.handled(obj) def _handleFlowBndConditions(self): - for obj in self._getMember("Fem::ConstraintFlowVelocity"): + for obj in self.getMember("Fem::ConstraintFlowVelocity"): if obj.References: for name in obj.References[0][1]: if obj.VelocityXEnabled: velocity = self._getFromUi(obj.VelocityX, "m/s", "L/T") - self._boundary(name, "Velocity 1", velocity) + self.boundary(name, "Velocity 1", velocity) if obj.VelocityYEnabled: velocity = self._getFromUi(obj.VelocityY, "m/s", "L/T") - self._boundary(name, "Velocity 2", velocity) + self.boundary(name, "Velocity 2", velocity) if obj.VelocityZEnabled: velocity = self._getFromUi(obj.VelocityZ, "m/s", "L/T") - self._boundary(name, "Velocity 3", velocity) + self.boundary(name, "Velocity 3", velocity) if obj.NormalToBoundary: - self._boundary(name, "Normal-Tangential Velocity", True) - self._handled(obj) - for obj in self._getMember("Fem::ConstraintPressure"): + self.boundary(name, "Normal-Tangential Velocity", True) + self.handled(obj) + 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)") if obj.Reversed: pressure *= -1 - self._boundary(name, "External Pressure", pressure) - self._handled(obj) + self.boundary(name, "External Pressure", pressure) + self.handled(obj) def _handleFlowEquation(self, bodies, equation): for b in bodies: @@ -1274,13 +1158,13 @@ class Writer(object): if equation.References: activeIn = equation.References[0][1] else: - activeIn = self._getAllBodies() + activeIn = self.getAllBodies() solverSection = self._getFluxSolver(equation) for body in activeIn: self._addSolver(body, solverSection) def _getFluxSolver(self, equation): - s = self._createLinearSolver(equation) + s = self.createLinearSolver(equation) # check if we need to update the equation self._updateFluxSolver(equation) # output the equation parameters @@ -1415,7 +1299,7 @@ class Writer(object): if equation.References: activeIn = equation.References[0][1] else: - activeIn = self._getAllBodies() + activeIn = self.getAllBodies() solverSection = self._getHeatSolver(equation) for body in activeIn: self._addSolver(body, solverSection) @@ -1438,13 +1322,13 @@ class Writer(object): s["Exec Solver"] = "Always" s["Optimize Bandwidth"] = True s["Stabilize"] = equation.Stabilize - s["Variable"] = self._getUniqueVarName("Temperature") + s["Variable"] = self.getUniqueVarName("Temperature") return s def _handleHeatConstants(self): - self._constant( + self.constant( "Stefan Boltzmann", - self._convert(self.constsdef["StefanBoltzmann"], "M/(O^4*T^3)") + self.convert(self.constsdef["StefanBoltzmann"], "M/(O^4*T^3)") ) def _handleHeatEquation(self, bodies, equation): @@ -1477,7 +1361,7 @@ class Writer(object): def _handleHeatBndConditions(self): i = -1 - for obj in self._getMember("Fem::ConstraintTemperature"): + 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( @@ -1489,28 +1373,28 @@ class Writer(object): for name in obj.References[0][1]: if obj.ConstraintType == "Temperature": temp = self._getFromUi(obj.Temperature, "K", "O") - self._boundary(name, "Temperature", temp) + 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"): + 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) + 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) + 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") @@ -1518,7 +1402,7 @@ class Writer(object): for name in bodies: temp = self._getFromUi(obj.initialTemperature, "K", "O") self._initial(name, "Temperature", temp) - self._handled(obj) + self.handled(obj) def _outputHeatBodyForce(self, obj, name): heatSource = self._getFromUi(obj.HeatSource, "W/kg", "L^2*T^-3") @@ -1528,12 +1412,12 @@ class Writer(object): self._bodyForce(name, "Heat Source", heatSource) def _handleHeatBodyForces(self, bodies): - bodyHeats = self._getMember("Fem::ConstraintBodyHeatSource") + 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) + self.handled(obj) else: # if there is only one body heat without a reference # add it to all bodies @@ -1545,43 +1429,43 @@ class Writer(object): "Several body heat constraints found without reference to a body.\n" "Please set a body for each body heat constraint." ) - self._handled(obj) + 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"): + 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()) + 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( + 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( + self.material( name, "Heat Conductivity", - self._convert(m["ThermalConductivity"], "M*L/(T^3*O)")) + 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( + self.material( name, "Heat Capacity", - self._convert(m["SpecificHeat"], "L^2/(T^2*O)")) + self.convert(m["SpecificHeat"], "L^2/(T^2*O)")) #------------------------------------------------------------------------------------------- # Solver handling @@ -1617,7 +1501,7 @@ class Writer(object): ) equation.IdrsParameter = (2, 1, 10, 1) - def _createLinearSolver(self, equation): + def createLinearSolver(self, equation): # first check if we have to update self._updateLinearSolver(equation) # write the solver @@ -1664,7 +1548,7 @@ class Writer(object): # first check if we have to update self._updateNonlinearSolver(equation) # write the linear solver - s = self._createLinearSolver(equation) + s = self.createLinearSolver(equation) # write the nonlinear solver s["Nonlinear System Max Iterations"] = \ equation.NonlinearIterations @@ -1682,15 +1566,15 @@ class Writer(object): # Helper functions def _haveMaterialSolid(self): - for obj in self._getMember("App::MaterialObject"): + for obj in self.getMember("App::MaterialObject"): m = obj.Material # fluid material always has KinematicViscosity defined - if not ("KinematicViscosity" in m): + if not "KinematicViscosity" in m: return True return False def _haveMaterialFluid(self): - for obj in self._getMember("App::MaterialObject"): + for obj in self.getMember("App::MaterialObject"): m = obj.Material # fluid material always has KinematicViscosity defined if "KinematicViscosity" in m: @@ -1711,7 +1595,7 @@ class Writer(object): return exp return None - def _getUniqueVarName(self, varName): + def getUniqueVarName(self, varName): postfix = 1 if varName in self._usedVarNames: varName += "%2d" % postfix @@ -1721,7 +1605,7 @@ class Writer(object): self._usedVarNames.add(varName) return varName - def _getAllBodies(self): + def getAllBodies(self): obj = self._getSingleMember("Fem::FemMeshObject") bodyCount = 0 prefix = "" @@ -1740,9 +1624,9 @@ class Writer(object): obj = self._getSingleMember("Fem::FemMeshObject") if obj.Part.Shape.Solids: return 3 - elif obj.Part.Shape.Faces: + if obj.Part.Shape.Faces: return 2 - elif obj.Part.Shape.Edges: + if obj.Part.Shape.Edges: return 1 return None @@ -1763,7 +1647,7 @@ class Writer(object): "'Coordinate Scaling Revert = Logical True' was " "inserted into the solver input file.\n" ) - for name in self._getAllBodies(): + for name in self.getAllBodies(): self._addSolver(name, s) def _writeSif(self): @@ -1772,19 +1656,19 @@ class Writer(object): sif = sifio.Sif(self._builder) sif.write(fstream) - def _handled(self, obj): + def handled(self, obj): self._handledObjects.add(obj) def _simulation(self, key, attr): self._builder.simulation(key, attr) - def _constant(self, key, attr): + def constant(self, key, attr): self._builder.constant(key, attr) def _initial(self, body, key, attr): self._builder.initial(body, key, attr) - def _material(self, body, key, attr): + def material(self, body, key, attr): self._builder.material(body, key, attr) def _equation(self, body, key, attr): @@ -1796,13 +1680,13 @@ class Writer(object): def _addSolver(self, body, solverSection): self._builder.addSolver(body, solverSection) - def _boundary(self, boundary, key, attr): + def boundary(self, boundary, key, attr): self._builder.boundary(boundary, key, attr) def _addSection(self, section): self._builder.addSection(section) - def _getMember(self, t): + def getMember(self, t): return membertools.get_member(self.analysis, t) def _getSingleMember(self, t):