| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| __title__ = "FreeCAD FEM Elasticity Elmer writer" |
| __author__ = "Uwe Stöhr" |
| __url__ = "https://www.freecad.org" |
|
|
| |
| |
|
|
| from FreeCAD import Console |
| from FreeCAD import Units |
|
|
| from .. import sifio |
| from .. import writer as general_writer |
| from femtools import femutils |
|
|
|
|
| class DeformationWriter: |
|
|
| def __init__(self, writer, solver): |
| self.write = writer |
| self.solver = solver |
|
|
| def getDeformationSolver(self, equation): |
| s = self.write.createLinearSolver(equation) |
| |
| s = self.write.createNonlinearSolver(equation) |
| s["Equation"] = "Nonlinear elasticity solver" |
| s["Procedure"] = sifio.FileAttr("ElasticSolve/ElasticSolver") |
| if equation.CalculateStrains is True: |
| s["Calculate Strains"] = equation.CalculateStrains |
| if equation.CalculateStresses is True: |
| s["Calculate Stresses"] = equation.CalculateStresses |
| if equation.CalculatePrincipal is True: |
| s["Calculate Principal"] = equation.CalculatePrincipal |
| if equation.CalculatePangle is True: |
| s["Calculate Pangle"] = equation.CalculatePangle |
| if equation.InitializeStateVariables is True: |
| s["Initialize State Variables"] = equation.InitializeStateVariables |
| if equation.MixedFormulation is True: |
| s["Mixed Formulation"] = equation.MixedFormulation |
| if equation.NeoHookeanMaterial is True: |
| s["Neo-Hookean Material"] = equation.NeoHookeanMaterial |
| s["Exec Solver"] = "Always" |
| s["Optimize Bandwidth"] = True |
| s["Stabilize"] = equation.Stabilize |
| s["Variable"] = equation.Variable |
| return s |
|
|
| def handleDeformationEquation(self, bodies, equation): |
| for b in bodies: |
| |
| if not self.write.isBodyMaterialFluid(b): |
| if equation.PlaneStress: |
| self.write.equation(b, "Plane Stress", equation.PlaneStress) |
|
|
| def handleDeformationConstants(self): |
| pass |
|
|
| def handleDeformationBndConditions(self): |
| for obj in self.write.getMember("Fem::ConstraintPressure"): |
| if obj.References: |
| for name in obj.References[0][1]: |
| pressure = float(obj.Pressure.getValueAs("Pa")) |
| if not obj.Reversed: |
| pressure *= -1 |
| self.write.boundary(name, "Normal Force", pressure) |
| self.write.handled(obj) |
| for obj in self.write.getMember("Fem::ConstraintFixed"): |
| if obj.References: |
| for name in obj.References[0][1]: |
| self.write.boundary(name, "Displacement 1", 0.0) |
| self.write.boundary(name, "Displacement 2", 0.0) |
| self.write.boundary(name, "Displacement 3", 0.0) |
| self.write.handled(obj) |
| for obj in self.write.getMember("Fem::ConstraintForce"): |
| if obj.References: |
| for name in obj.References[0][1]: |
| force = float(obj.Force.getValueAs("N")) |
| self.write.boundary(name, "Force 1", obj.DirectionVector.x * force) |
| self.write.boundary(name, "Force 2", obj.DirectionVector.y * force) |
| self.write.boundary(name, "Force 3", obj.DirectionVector.z * force) |
| self.write.boundary(name, "Force 1 Normalize by Area", True) |
| self.write.boundary(name, "Force 2 Normalize by Area", True) |
| self.write.boundary(name, "Force 3 Normalize by Area", True) |
| self.write.handled(obj) |
| for obj in self.write.getMember("Fem::ConstraintDisplacement"): |
| if obj.References: |
| for name in obj.References[0][1]: |
| if obj.useFlowSurfaceForce: |
| self.write.boundary(name, "FSI BC", obj.useFlowSurfaceForce) |
| |
| continue |
| if not obj.xFree: |
| if not obj.hasXFormula: |
| displacement = float(obj.xDisplacement.getValueAs("m")) |
| else: |
| displacement = obj.xDisplacementFormula |
| self.write.boundary(name, "Displacement 1", displacement) |
| if not obj.yFree: |
| if not obj.hasYFormula: |
| displacement = float(obj.yDisplacement.getValueAs("m")) |
| else: |
| displacement = obj.yDisplacementFormula |
| self.write.boundary(name, "Displacement 2", displacement) |
| if not obj.zFree: |
| if not obj.hasZFormula: |
| displacement = float(obj.zDisplacement.getValueAs("m")) |
| else: |
| displacement = obj.zDisplacementFormula |
| self.write.boundary(name, "Displacement 3", displacement) |
| self.write.handled(obj) |
| for obj in self.write.getMember("Fem::ConstraintSpring"): |
| if obj.References: |
| for name in obj.References[0][1]: |
| if obj.ElmerStiffness == "Normal Stiffness": |
| spring = float(obj.NormalStiffness.getValueAs("N/m")) |
| else: |
| spring = float(obj.TangentialStiffness.getValueAs("N/m")) |
| self.write.boundary(name, "Spring", spring) |
| self.write.handled(obj) |
|
|
| def handleDeformationInitial(self, bodies): |
| pass |
|
|
| def handleDeformationBodyForces(self, bodies): |
| obj = self.write.getSingleMember("Fem::ConstraintSelfWeight") |
| if obj is not None: |
| for name in bodies: |
| gravity = self.write.convert(obj.GravityAcceleration.toStr(), "L/T^2") |
| if self.write.getBodyMaterial(name) is None: |
| raise general_writer.WriteError( |
| f"The body {name} is not referenced in any material.\n\n" |
| ) |
| m = self.write.getBodyMaterial(name).Material |
|
|
| densityQuantity = Units.Quantity(m["Density"]) |
| dimension = "M/L^3" |
| if name.startswith("Edge"): |
| |
| |
| densityQuantity.Unit = Units.Unit(-2, 1) |
| dimension = "M/L^2" |
| density = self.write.convert(densityQuantity, dimension) |
|
|
| force1 = gravity * obj.GravityDirection.x * density |
| force2 = gravity * obj.GravityDirection.y * density |
| force3 = gravity * obj.GravityDirection.z * density |
| self.write.bodyForce(name, "Stress Bodyforce 1", force1) |
| self.write.bodyForce(name, "Stress Bodyforce 2", force2) |
| self.write.bodyForce(name, "Stress Bodyforce 3", force3) |
| self.write.handled(obj) |
|
|
| def handleDeformationMaterial(self, bodies): |
| |
| |
| density_needed = False |
| for equation in self.solver.Group: |
| if femutils.is_of_type(equation, "Fem::EquationElmerElasticity"): |
| if equation.EigenAnalysis is True: |
| density_needed = True |
| break |
| gravObj = self.write.getSingleMember("Fem::ConstraintSelfWeight") |
| if gravObj is not None: |
| density_needed = True |
| |
| tempObj = self.write.getSingleMember("Fem::ConstraintInitialTemperature") |
| if tempObj is not None: |
| refTemp = float(tempObj.initialTemperature.getValueAs("K")) |
| 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 self.write.isBodyMaterialFluid(name): |
| break |
| if "YoungsModulus" not in m: |
| Console.PrintMessage(f"m: {m}\n") |
| |
| |
| |
| raise general_writer.WriteError( |
| "There are two or more materials with empty references.\n\n" |
| "Set for the materials to what solid they belong to.\n" |
| ) |
| self.write.material(name, "Name", m["Name"]) |
| if density_needed is True: |
| self.write.material(name, "Density", self.write.getDensity(m)) |
| self.write.material(name, "Youngs Modulus", self._getYoungsModulus(m)) |
| self.write.material(name, "Poisson ratio", float(m["PoissonRatio"])) |
| if tempObj: |
| self.write.material( |
| name, |
| "Heat expansion Coefficient", |
| self.write.convert(m["ThermalExpansionCoefficient"], "O^-1"), |
| ) |
|
|
| def _getYoungsModulus(self, m): |
| youngsModulus = self.write.convert(m["YoungsModulus"], "M/(L*T^2)") |
| if self.write.getMeshDimension() == 2: |
| youngsModulus *= 1e3 |
| return youngsModulus |
|
|
|
|
| |
|
|