Fem: Add support for Elmer static current solver - fixes #11895
This commit is contained in:
committed by
Max Wilfinger
parent
3f9ad28acf
commit
3d79de4ab3
90
src/Mod/Fem/femsolver/elmer/equations/staticcurrent.py
Normal file
90
src/Mod/Fem/femsolver/elmer/equations/staticcurrent.py
Normal file
@@ -0,0 +1,90 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2025 Mario Passaglia <mpassaglia[at]cbc.uba.ar> *
|
||||
# * *
|
||||
# * 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 *
|
||||
# * <https://www.gnu.org/licenses/>. *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
__title__ = "FreeCAD FEM solver Elmer equation object StaticCurrent"
|
||||
__author__ = "Mario Passaglia"
|
||||
__url__ = "https://www.freecad.org"
|
||||
|
||||
## \addtogroup FEM
|
||||
# @{
|
||||
|
||||
from femtools import femutils
|
||||
from ... import equationbase
|
||||
from . import linear
|
||||
|
||||
|
||||
def create(doc, name="StaticCurrent"):
|
||||
return femutils.createObject(doc, name, Proxy, ViewProxy)
|
||||
|
||||
|
||||
class Proxy(linear.Proxy, equationbase.StaticCurrentProxy):
|
||||
|
||||
Type = "Fem::EquationElmerStaticCurrent"
|
||||
|
||||
def __init__(self, obj):
|
||||
super().__init__(obj)
|
||||
|
||||
obj.addProperty("App::PropertyBool", "CalculateVolumeCurrent", "StaticCurrent", "")
|
||||
obj.CalculateVolumeCurrent = True
|
||||
obj.addProperty("App::PropertyBool", "CalculateJouleHeating", "StaticCurrent", "")
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"ConstantWeights",
|
||||
"StaticCurrent",
|
||||
"Used to turn constant weighting on for the results",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CalculateNodalHeating",
|
||||
"StaticCurrent",
|
||||
"Calculate nodal heating that may be used to couple the heat equation optimally when using conforming finite element meshes",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"HeatSource",
|
||||
"StaticCurrent",
|
||||
"Use Joule heating as a heat source in combination with heat equation",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"PowerControl",
|
||||
"StaticCurrent",
|
||||
"Apply power control with the desired heating power",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool",
|
||||
"CurrentControl",
|
||||
"StaticCurrent",
|
||||
"Apply current control with the desired current",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyElectricCurrent", "Current", "StaticCurrent", "Current control value"
|
||||
)
|
||||
obj.addProperty("App::PropertyPower", "Power", "StaticCurrent", "Power control value")
|
||||
|
||||
|
||||
class ViewProxy(linear.ViewProxy, equationbase.StaticCurrentViewProxy):
|
||||
pass
|
||||
|
||||
|
||||
## @}
|
||||
111
src/Mod/Fem/femsolver/elmer/equations/staticcurrent_writer.py
Normal file
111
src/Mod/Fem/femsolver/elmer/equations/staticcurrent_writer.py
Normal file
@@ -0,0 +1,111 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2025 Mario Passaglia <mpassaglia[at]cbc.uba.ar> *
|
||||
# * *
|
||||
# * 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 *
|
||||
# * <https://www.gnu.org/licenses/>. *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
__title__ = "FreeCAD FEM StaticCurrent Elmer writer"
|
||||
__author__ = "Mario Passaglia"
|
||||
__url__ = "https://www.freecad.org"
|
||||
|
||||
## \addtogroup FEM
|
||||
# @{
|
||||
|
||||
from FreeCAD import Units
|
||||
from .. import sifio
|
||||
|
||||
|
||||
class SCwriter:
|
||||
|
||||
def __init__(self, writer, solver):
|
||||
self.write = writer
|
||||
self.solver = solver
|
||||
|
||||
def getStaticCurrentSolver(self, equation):
|
||||
# output the equation parameters
|
||||
s = self.write.createLinearSolver(equation)
|
||||
s["Equation"] = "Stat Current Solver"
|
||||
s["Procedure"] = sifio.FileAttr("StatCurrentSolve/StatCurrentSolver")
|
||||
s["Variable"] = self.write.getUniqueVarName("Potential")
|
||||
s["Variable DOFs"] = 1
|
||||
s["Calculate Volume Current"] = equation.CalculateVolumeCurrent
|
||||
s["Calculate Joule Heating"] = equation.CalculateJouleHeating
|
||||
s["Constant Weights"] = equation.ConstantWeights
|
||||
s["Calculate Nodal Heating"] = equation.CalculateNodalHeating
|
||||
if equation.PowerControl:
|
||||
s["Power Control"] = equation.Power.getValueAs("W").Value
|
||||
if equation.CurrentControl:
|
||||
s["Current Control"] = equation.Current.getValueAs("A").Value
|
||||
s["Exec Solver"] = "Always"
|
||||
s["Optimize Bandwidth"] = True
|
||||
s["Stabilize"] = equation.Stabilize
|
||||
|
||||
return s
|
||||
|
||||
def handleStaticCurrentConstants(self):
|
||||
pass
|
||||
|
||||
def handleStaticCurrentMaterial(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 "ElectricalConductivity" in m:
|
||||
self.write.material(
|
||||
name,
|
||||
"Electric Conductivity",
|
||||
Units.Quantity(m["ElectricalConductivity"]).getValueAs("S/m").Value,
|
||||
)
|
||||
|
||||
def handleStaticCurrentBndConditions(self):
|
||||
for obj in self.write.getMember("Fem::ConstraintElectrostaticPotential"):
|
||||
if obj.References:
|
||||
for name in obj.References[0][1]:
|
||||
# output the FreeCAD label as comment
|
||||
if obj.Label:
|
||||
self.write.boundary(name, "! FreeCAD Name", obj.Label)
|
||||
if obj.BoundaryCondition == "Dirichlet":
|
||||
if obj.PotentialEnabled:
|
||||
self.write.boundary(name, "Current Density BC", False)
|
||||
self.write.boundary(
|
||||
name, "Potential", obj.Potential.getValueAs("V").Value
|
||||
)
|
||||
self.write.handled(obj)
|
||||
|
||||
for obj in self.write.getMember("Fem::ConstraintCurrentDensity"):
|
||||
if obj.References:
|
||||
for name in obj.References[0][1]:
|
||||
# output the FreeCAD label as comment
|
||||
if obj.Label:
|
||||
self.write.boundary(name, "! FreeCAD Name", obj.Label)
|
||||
self.write.boundary(name, "Current Density BC", True)
|
||||
self.write.boundary(
|
||||
name, "Current Density", obj.NormalCurrentDensity.getValueAs("A/m^2").Value
|
||||
)
|
||||
|
||||
self.write.handled(obj)
|
||||
|
||||
def handleStaticCurrentBodyForces(self, bodies, equation):
|
||||
for name in bodies:
|
||||
self.write.bodyForce(name, "Joule Heat", equation.HeatSource)
|
||||
|
||||
|
||||
## @}
|
||||
@@ -57,6 +57,7 @@ from .equations import flux_writer
|
||||
from .equations import heat_writer
|
||||
from .equations import magnetodynamic_writer as MgDyn_writer
|
||||
from .equations import magnetodynamic2D_writer as MgDyn2D_writer
|
||||
from .equations import staticcurrent_writer as SC_writer
|
||||
|
||||
|
||||
_STARTINFO_NAME = "ELMERSOLVER_STARTINFO"
|
||||
@@ -109,6 +110,7 @@ class Writer:
|
||||
self._handleFlux()
|
||||
self._handleMagnetodynamic()
|
||||
self._handleMagnetodynamic2D()
|
||||
self._handleStaticCurrent()
|
||||
self._addOutputSolver()
|
||||
|
||||
self._writeSif()
|
||||
@@ -614,6 +616,28 @@ class Writer:
|
||||
MgDyn2D.handleMagnetodynamic2DBodyForces(activeIn, equation)
|
||||
MgDyn2D.handleMagnetodynamic2DMaterial(activeIn)
|
||||
|
||||
# -------------------------------------------------------------------------------------------
|
||||
# StaticCurrent
|
||||
|
||||
def _handleStaticCurrent(self):
|
||||
SCW = SC_writer.SCwriter(self, self.solver)
|
||||
activeIn = []
|
||||
for equation in self.solver.Group:
|
||||
if femutils.is_of_type(equation, "Fem::EquationElmerStaticCurrent"):
|
||||
if equation.References:
|
||||
activeIn = equation.References[0][1]
|
||||
else:
|
||||
activeIn = self.getAllBodies()
|
||||
solverSection = SCW.getStaticCurrentSolver(equation)
|
||||
for body in activeIn:
|
||||
self._addSolver(body, solverSection)
|
||||
SCW.handleStaticCurrentBodyForces(activeIn, equation)
|
||||
|
||||
if activeIn:
|
||||
SCW.handleStaticCurrentConstants()
|
||||
SCW.handleStaticCurrentBndConditions()
|
||||
SCW.handleStaticCurrentMaterial(activeIn)
|
||||
|
||||
# -------------------------------------------------------------------------------------------
|
||||
# Solver handling
|
||||
|
||||
|
||||
@@ -157,4 +157,14 @@ class Magnetodynamic2DViewProxy(BaseViewProxy):
|
||||
return ":/icons/FEM_EquationMagnetodynamic2D.svg"
|
||||
|
||||
|
||||
class StaticCurrentProxy(BaseProxy):
|
||||
pass
|
||||
|
||||
|
||||
class StaticCurrentViewProxy(BaseViewProxy):
|
||||
|
||||
def getIcon(self):
|
||||
return ":/icons/FEM_EquationStaticCurrent.svg"
|
||||
|
||||
|
||||
## @}
|
||||
|
||||
Reference in New Issue
Block a user