From 38734fe0df6d23f3e3c678d67498cbbcb7201c56 Mon Sep 17 00:00:00 2001 From: FEA-eng <59876896+FEA-eng@users.noreply.github.com> Date: Wed, 5 Mar 2025 18:53:02 +0100 Subject: [PATCH 1/3] FEM: add example file --- .../equation_staticcurrent_elmer.py | 172 ++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 src/Mod/Fem/femexamples/equation_staticcurrent_elmer.py diff --git a/src/Mod/Fem/femexamples/equation_staticcurrent_elmer.py b/src/Mod/Fem/femexamples/equation_staticcurrent_elmer.py new file mode 100644 index 0000000000..5b030c249d --- /dev/null +++ b/src/Mod/Fem/femexamples/equation_staticcurrent_elmer.py @@ -0,0 +1,172 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +# *************************************************************************** +# * Copyright (c) 2025 Jakub Michalski * +# * * +# * This file is part of FreeCAD. * +# * * +# * FreeCAD is free software: you can redistribute it and/or modify it * +# * under the terms of the GNU Lesser General Public License as * +# * published by the Free Software Foundation, either version 2.1 of the * +# * License, or (at your option) any later version. * +# * * +# * FreeCAD 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 * +# * Lesser General Public License for more details. * +# * * +# * You should have received a copy of the GNU Lesser General Public * +# * License along with FreeCAD. If not, see * +# * . * +# * * +# *************************************************************************** +# to run the example use: +""" +from femexamples.equation_staticcurrent_elmer import setup +setup() + +""" + + +import sys +import FreeCAD + +import Fem +import ObjectsFem + +from BasicShapes import Shapes +from . import manager +from .manager import get_meshname +from .manager import init_doc + + +def get_information(): + return { + "name": "Joule heating", + "meshtype": "solid", + "meshelement": "Tet10", + "constraints": ["electrostatic potential", "current density"], + "solvers": ["elmer"], + "material": "solid", + "equations": ["static current"], + } + + +def get_explanation(header=""): + return ( + header + + """ + +To run the example from Python console use: +from femexamples.equation_staticcurrent_elmer import setup +setup() + +Static current equation - Elmer solver + +analytical solution - temperature 351.09 K at 50 s + +""" + ) + + +def setup(doc=None, solvertype="elmer"): + + # init FreeCAD document + if doc is None: + doc = init_doc() + + # explanation object + # just keep the following line and change text string in get_explanation method + manager.add_explanation_obj(doc, get_explanation(manager.get_header(get_information()))) + + # geometric objects + + # wire + Wire = doc.addObject("Part::Cylinder", "Wire") + Wire.Radius = "2 mm" + Wire.Height = "60 mm" + Wire.ViewObject.Visibility = True + + if FreeCAD.GuiUp: + Wire.ViewObject.Document.activeView().viewAxonometric() + Wire.ViewObject.Document.activeView().fitAll() + + # analysis + analysis = ObjectsFem.makeAnalysis(doc, "Analysis") + if FreeCAD.GuiUp: + import FemGui + + FemGui.setActiveAnalysis(analysis) + + # solver + if solvertype == "elmer": + solver_obj = ObjectsFem.makeSolverElmer(doc, "SolverElmer") + solver_obj.SimulationType = u"Transient" + solver_obj.TimestepSizes = [50] + solver_obj.TimestepIntervals = [1] + eq_staticcurrent = ObjectsFem.makeEquationStaticCurrent(doc, solver_obj) + eq_staticcurrent.References = [(Wire, "Solid1")] + eq_staticcurrent.CalculateJouleHeating = True + eq_staticcurrent.HeatSource = True + eq_staticcurrent.Priority = 2 + eq_heat = ObjectsFem.makeEquationHeat(doc, solver_obj) + eq_heat.References = [(Wire, "Solid1")] + eq_heat.Priority = 1 + else: + FreeCAD.Console.PrintWarning( + "Unknown or unsupported solver type: {}. " + "No solver object was created.\n".format(solvertype) + ) + analysis.addObject(solver_obj) + + # material + + # metal wire + material_obj = ObjectsFem.makeMaterialSolid(doc, "Metal for Joule heating") + mat = material_obj.Material + mat["Name"] = "Metal for Joule heating" + mat["Density"] = "7850 kg/m^3" + mat["ThermalConductivity"] = "16.0 W/m/K" + mat["SpecificHeat"] = "490.0 J/kg/K" + mat["ElectricalConductivity"] = "1450000 S/m" + material_obj.Material = mat + material_obj.References = [(Wire, "Solid1")] + analysis.addObject(material_obj) + + # voltage on one end + Voltage = ObjectsFem.makeConstraintElectrostaticPotential(doc, "Voltage") + Voltage.References = [(Wire, "Face2")] + Voltage.Potential = "0 V" + analysis.addObject(Voltage) + + # current on other end + Current = ObjectsFem.makeConstraintCurrentDensity(doc, "Current") + Current.References = [(Wire, "Face3")] + Current.Mode = "Normal" + Current.NormalCurrentDensity_re = "2387324 A/m^2" + analysis.addObject(Current) + + # constraint initial temperature + con_inittemp = ObjectsFem.makeConstraintInitialTemperature(doc, "ConstraintInitialTemperature") + con_inittemp.initialTemperature = 300.0 + analysis.addObject(con_inittemp) + + # mesh + femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0] + femmesh_obj.Shape = Wire + femmesh_obj.ElementOrder = "2nd" + femmesh_obj.CharacteristicLengthMax = "0.7 mm" + femmesh_obj.ViewObject.Visibility = False + + # generate the mesh + from femmesh import gmshtools + + gmsh_mesh = gmshtools.GmshTools(femmesh_obj, analysis) + try: + error = gmsh_mesh.create_mesh() + except Exception: + error = sys.exc_info()[1] + FreeCAD.Console.PrintError(f"Unexpected error when creating mesh: {error}\n") + + doc.recompute() + return doc From ccf66e50ce00a5ccfdc7bf9c85b2b56190b158b8 Mon Sep 17 00:00:00 2001 From: FEA-eng <59876896+FEA-eng@users.noreply.github.com> Date: Wed, 5 Mar 2025 18:54:29 +0100 Subject: [PATCH 2/3] FEM: Update CMakeLists.txt --- src/Mod/Fem/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Mod/Fem/CMakeLists.txt b/src/Mod/Fem/CMakeLists.txt index a8b9f378fe..1560c2b672 100755 --- a/src/Mod/Fem/CMakeLists.txt +++ b/src/Mod/Fem/CMakeLists.txt @@ -86,6 +86,7 @@ SET(FemExamples_SRCS femexamples/equation_magnetodynamics_elmer.py femexamples/equation_magnetodynamics_2D_elmer.py femexamples/equation_magnetostatics_2D_elmer.py + femexamples/equation_staticcurrent_elmer.py femexamples/frequency_beamsimple.py femexamples/manager.py femexamples/material_multiple_bendingbeam_fiveboxes.py From 1c8603bde97a5f7b2b6f1dca696845d31204c36b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 5 Mar 2025 17:58:18 +0000 Subject: [PATCH 3/3] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/Mod/Fem/femexamples/equation_staticcurrent_elmer.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Mod/Fem/femexamples/equation_staticcurrent_elmer.py b/src/Mod/Fem/femexamples/equation_staticcurrent_elmer.py index 5b030c249d..44e686ee08 100644 --- a/src/Mod/Fem/femexamples/equation_staticcurrent_elmer.py +++ b/src/Mod/Fem/femexamples/equation_staticcurrent_elmer.py @@ -86,7 +86,7 @@ def setup(doc=None, solvertype="elmer"): Wire.Radius = "2 mm" Wire.Height = "60 mm" Wire.ViewObject.Visibility = True - + if FreeCAD.GuiUp: Wire.ViewObject.Document.activeView().viewAxonometric() Wire.ViewObject.Document.activeView().fitAll() @@ -101,7 +101,7 @@ def setup(doc=None, solvertype="elmer"): # solver if solvertype == "elmer": solver_obj = ObjectsFem.makeSolverElmer(doc, "SolverElmer") - solver_obj.SimulationType = u"Transient" + solver_obj.SimulationType = "Transient" solver_obj.TimestepSizes = [50] solver_obj.TimestepIntervals = [1] eq_staticcurrent = ObjectsFem.makeEquationStaticCurrent(doc, solver_obj) @@ -111,7 +111,7 @@ def setup(doc=None, solvertype="elmer"): eq_staticcurrent.Priority = 2 eq_heat = ObjectsFem.makeEquationHeat(doc, solver_obj) eq_heat.References = [(Wire, "Solid1")] - eq_heat.Priority = 1 + eq_heat.Priority = 1 else: FreeCAD.Console.PrintWarning( "Unknown or unsupported solver type: {}. " @@ -145,7 +145,7 @@ def setup(doc=None, solvertype="elmer"): Current.Mode = "Normal" Current.NormalCurrentDensity_re = "2387324 A/m^2" analysis.addObject(Current) - + # constraint initial temperature con_inittemp = ObjectsFem.makeConstraintInitialTemperature(doc, "ConstraintInitialTemperature") con_inittemp.initialTemperature = 300.0