Merge pull request #19011 from marioalexis84/fem-electromagnetic_boundary_condtion

This commit is contained in:
Chris Hennes
2025-01-27 15:15:59 -06:00
committed by GitHub
13 changed files with 1054 additions and 1043 deletions

View File

@@ -2061,6 +2061,7 @@ void Application::initTypes()
App::PropertyElectricalInductance ::init();
App::PropertyElectricalResistance ::init();
App::PropertyElectricCharge ::init();
App::PropertySurfaceChargeDensity ::init();
App::PropertyElectricCurrent ::init();
App::PropertyElectricPotential ::init();
App::PropertyElectromagneticPotential ::init();

View File

@@ -392,6 +392,17 @@ PropertyElectricCharge::PropertyElectricCharge()
setUnit(Base::Unit::ElectricCharge);
}
//**************************************************************************
// PropertySurfaceChargeDensity
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertySurfaceChargeDensity, App::PropertyQuantity)
PropertySurfaceChargeDensity::PropertySurfaceChargeDensity()
{
setUnit(Base::Unit::SurfaceChargeDensity);
}
//**************************************************************************
// PropertyElectricCurrent
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

View File

@@ -361,6 +361,19 @@ public:
~PropertyElectricCharge() override = default;
};
/** SurfaceChargeDensity property
* This is a property for representing surface charge density. It is basically a float
* property. On the Gui it has a quantity like C/m^2.
*/
class AppExport PropertySurfaceChargeDensity: public PropertyQuantity
{
TYPESYSTEM_HEADER_WITH_OVERRIDE();
public:
PropertySurfaceChargeDensity();
~PropertySurfaceChargeDensity() override = default;
};
/** ElectricCurrent property
* This is a property for representing electric currents. It is basically a
* float property. On the Gui it has a quantity like A.

View File

@@ -587,7 +587,7 @@ std::string Unit::getString() const
std::string Unit::getTypeString() const
{
static std::array<std::pair<Unit, std::string>, 55> unitSpecs {{
static std::array<std::pair<Unit, std::string>, 56> unitSpecs {{
{ Unit::Acceleration, "Acceleration" },
{ Unit::AmountOfSubstance, "AmountOfSubstance" },
{ Unit::Angle, "Angle" },
@@ -603,6 +603,7 @@ std::string Unit::getTypeString() const
{ Unit::ElectricalInductance, "ElectricalInductance" },
{ Unit::ElectricalResistance, "ElectricalResistance" },
{ Unit::ElectricCharge, "ElectricCharge" },
{ Unit::SurfaceChargeDensity, "SurfaceChargeDensity" },
{ Unit::ElectricCurrent, "ElectricCurrent" },
{ Unit::ElectricPotential, "ElectricPotential" },
{ Unit::ElectromagneticPotential, "ElectromagneticPotential" },
@@ -681,6 +682,7 @@ const Unit Unit::ElectricalConductivity (-3, -1, 3, 2);
const Unit Unit::ElectricalInductance (2, 1, -2, -2);
const Unit Unit::ElectricalResistance (2, 1, -3, -2);
const Unit Unit::ElectricCharge (0, 0, 1, 1);
const Unit Unit::SurfaceChargeDensity (-2, 0, 1, 1);
const Unit Unit::ElectricPotential (2, 1, -3, -1);
const Unit Unit::ElectromagneticPotential (1, 1, -2, -1);
const Unit Unit::Force (1, 1, -2);

View File

@@ -110,6 +110,7 @@ public:
static const Unit ElectricCurrent;
static const Unit ElectricPotential;
static const Unit ElectricCharge;
static const Unit SurfaceChargeDensity;
static const Unit MagneticFieldStrength;
static const Unit MagneticFlux;
static const Unit MagneticFluxDensity;

View File

@@ -364,6 +364,10 @@ UnitsSchemaInternal::schemaTranslate(const Quantity& quant, double& factor, std:
unitString = "C";
factor = 1.0;
}
else if (unit == Unit::SurfaceChargeDensity) {
unitString = "C/m^2";
factor = 1e-6;
}
else if (unit == Unit::CurrentDensity) {
if (UnitValue <= 1e3) {
unitString = "A/m^2";

View File

@@ -312,6 +312,10 @@ UnitsSchemaMKS::schemaTranslate(const Quantity& quant, double& factor, std::stri
unitString = "C";
factor = 1.0;
}
else if (unit == Unit::SurfaceChargeDensity) {
unitString = "C/m^2";
factor = 1e-6;
}
else if (unit == Unit::CurrentDensity) {
if (UnitValue <= 1e3) {
unitString = "A/m^2";

File diff suppressed because it is too large Load Diff

View File

@@ -164,30 +164,28 @@ def setup(doc=None, solvertype="elmer"):
(BooleanFragments, "Face6"),
]
AxialField.PotentialEnabled = False
AxialField.AV_im_1_Disabled = False
AxialField.AV_im_2_Disabled = False
AxialField.AV_re_1_Disabled = False
AxialField.AV_re_2_Disabled = False
AxialField.EnableAV_1 = True
AxialField.EnableAV_2 = True
analysis.addObject(AxialField)
# voltage on one end
Voltage = ObjectsFem.makeConstraintElectrostaticPotential(doc, "Voltage")
Voltage.References = [(BooleanFragments, "Face3")]
Voltage.Potential = "10.000 mV"
Voltage.AV_im_1_Disabled = False
Voltage.AV_im_2_Disabled = False
Voltage.AV_re_1_Disabled = False
Voltage.AV_re_2_Disabled = False
Voltage.AV_re = "10.000 mV"
Voltage.AV_im = "0 V"
Voltage.EnableAV = True
Voltage.EnableAV_1 = True
Voltage.EnableAV_2 = True
analysis.addObject(Voltage)
# ground on other end
Ground = ObjectsFem.makeConstraintElectrostaticPotential(doc, "Ground")
Ground.References = [(BooleanFragments, "Face2")]
Ground.Potential = "0 V"
Ground.AV_im_1_Disabled = False
Ground.AV_im_2_Disabled = False
Ground.AV_re_1_Disabled = False
Ground.AV_re_2_Disabled = False
Ground.AV_re = "0 V"
Ground.AV_im = "0 V"
Ground.EnableAV = True
Ground.EnableAV_1 = True
Ground.EnableAV_2 = True
analysis.addObject(Ground)
# magnetization

View File

@@ -2,6 +2,7 @@
# * Copyright (c) 2017 Markus Hovorka <m.hovorka@live.de> *
# * Copyright (c) 2020 Bernd Hahnebach <bernd@bimstatik.org> *
# * Copyright (c) 2023 Uwe Stöhr <uwestoehr@lyx.org> *
# * Copyright (c) 2024 Mario Passaglia <mpassaglia[at]cbc.uba.ar> *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
@@ -24,15 +25,19 @@
# ***************************************************************************
__title__ = "FreeCAD FEM constraint electrostatic potential document object"
__author__ = "Markus Hovorka, Bernd Hahnebach, Uwe Stöhr"
__author__ = "Markus Hovorka, Bernd Hahnebach, Uwe Stöhr, Mario Passaglia"
__url__ = "https://www.freecad.org"
## @package constraint_electrostaticpotential
# \ingroup FEM
# \brief constraint electrostatic potential object
from FreeCAD import Base
from . import base_fempythonobject
_PropHelper = base_fempythonobject._PropHelper
class ConstraintElectrostaticPotential(base_fempythonobject.BaseFemPythonObject):
@@ -40,158 +45,257 @@ class ConstraintElectrostaticPotential(base_fempythonobject.BaseFemPythonObject)
def __init__(self, obj):
super().__init__(obj)
self.add_properties(obj)
for prop in self._get_properties():
prop.add_to_object(obj)
def _get_properties(self):
prop = []
prop.append(
_PropHelper(
type="App::PropertyElectricPotential",
name="Potential",
group="Parameter",
doc="Electric Potential",
value="1 V",
)
)
prop.append(
_PropHelper(
type="App::PropertyBool",
name="PotentialEnabled",
group="Parameter",
doc="Enable electric potential",
value=True,
)
)
prop.append(
_PropHelper(
type="App::PropertyElectricPotential",
name="AV_re",
group="Electromagnetic Potential",
doc="Real part of scalar potential",
value="0 V",
)
)
prop.append(
_PropHelper(
type="App::PropertyElectricPotential",
name="AV_im",
group="Electromagnetic Potential",
doc="Imaginary part of scalar potential",
value="0 V",
)
)
prop.append(
_PropHelper(
type="App::PropertyElectromagneticPotential",
name="AV_re_1",
group="Electromagnetic Potential",
doc="Real part of vector potential x-component",
value="0 Wb/m",
)
)
prop.append(
_PropHelper(
type="App::PropertyElectromagneticPotential",
name="AV_re_2",
group="Electromagnetic Potential",
doc="Real part of vector potential y-component",
value="0 Wb/m",
)
)
prop.append(
_PropHelper(
type="App::PropertyElectromagneticPotential",
name="AV_re_3",
group="Electromagnetic Potential",
doc="Real part of vector potential z-component",
value="0 Wb/m",
)
)
prop.append(
_PropHelper(
type="App::PropertyElectromagneticPotential",
name="AV_im_1",
group="Electromagnetic Potential",
doc="Imaginary part of vector potential x-component",
value="0 Wb/m",
)
)
prop.append(
_PropHelper(
type="App::PropertyElectromagneticPotential",
name="AV_im_2",
group="Electromagnetic Potential",
doc="Imaginary part of vector potential y-component",
value="0 Wb/m",
)
)
prop.append(
_PropHelper(
type="App::PropertyElectromagneticPotential",
name="AV_im_3",
group="Electromagnetic Potential",
doc="Imaginary part of vector potential z-component",
value="0 Wb/m",
)
)
prop.append(
_PropHelper(
type="App::PropertySurfaceChargeDensity",
name="SurfaceChargeDensity",
group="Parameter",
doc="Free surface charge density",
value="0 C/m^2",
)
)
prop.append(
_PropHelper(
type="App::PropertyEnumeration",
name="BoundaryCondition",
group="Parameter",
doc="Set boundary condition type",
value=["Dirichlet", "Neumann"],
)
)
prop.append(
_PropHelper(
type="App::PropertyBool",
name="EnableAV",
group="Electromagnetic Potential",
doc="Enable scalar potential boundary condition",
value=False,
)
)
prop.append(
_PropHelper(
type="App::PropertyBool",
name="EnableAV_1",
group="Electromagnetic Potential",
doc="Enable vector potential x-component boundary condition",
value=False,
)
)
prop.append(
_PropHelper(
type="App::PropertyBool",
name="EnableAV_2",
group="Electromagnetic Potential",
doc="Enable vector potential y-component boundary condition",
value=False,
)
)
prop.append(
_PropHelper(
type="App::PropertyBool",
name="EnableAV_3",
group="Electromagnetic Potential",
doc="Enable vector potential z-component boundary condition",
value=False,
)
)
prop.append(
_PropHelper(
type="App::PropertyBool",
name="PotentialConstant",
group="Parameter",
doc="",
value=False,
)
)
prop.append(
_PropHelper(
type="App::PropertyBool",
name="ElectricInfinity",
group="Parameter",
doc="Electric Infinity",
value=False,
)
)
prop.append(
_PropHelper(
type="App::PropertyBool",
name="ElectricForcecalculation",
group="Parameter",
doc="Electric force calculation",
value=False,
)
)
prop.append(
_PropHelper(
type="App::PropertyInteger",
name="CapacitanceBody",
group="Parameter",
doc="Capacitance body",
value=0,
)
)
prop.append(
_PropHelper(
type="App::PropertyBool",
name="CapacitanceBodyEnabled",
group="Parameter",
doc="Capacitance body enabled",
value=False,
)
)
return prop
def onDocumentRestored(self, obj):
self.add_properties(obj)
# update old project with new properties
for prop in self._get_properties():
try:
obj.getPropertyByName(prop.name)
except Base.PropertyError:
prop.add_to_object(obj)
def add_properties(self, obj):
if not hasattr(obj, "Potential"):
obj.addProperty(
"App::PropertyElectricPotential", "Potential", "Parameter", "Electric Potential"
)
obj.setPropertyStatus("Potential", "LockDynamic")
# setting 1 V assures that the unit does not switch to mV
# and the constraint holds usually Volts
obj.Potential = "1 V"
# convert old potential float to Volt
if prop.name == "Potential":
prop.handle_change_type(
obj,
old_type="App::PropertyFloat",
convert_old_value=lambda x: "{} V".format(1e6 * x),
)
# fix unit for magnetic vector potential properties
if prop.name in ("AV_re_1", "AV_re_2", "AV_re_3", "AV_im_1", "AV_im_2", "AV_im_3"):
prop.handle_change_type(
obj,
old_type="App::PropertyElectricPotential",
convert_old_value=lambda x: "{} Wb/m".format(x.getValueAs("V").Value),
)
if not hasattr(obj, "AV_re_1"):
obj.addProperty(
"App::PropertyElectricPotential",
"AV_re_1",
"Vector Potential",
"Real part of potential x-component",
)
obj.setPropertyStatus("AV_re_1", "LockDynamic")
obj.AV_re_1 = "0 V"
if not hasattr(obj, "AV_re_2"):
obj.addProperty(
"App::PropertyElectricPotential",
"AV_re_2",
"Vector Potential",
"Real part of potential y-component",
)
obj.setPropertyStatus("AV_re_2", "LockDynamic")
obj.AV_re_2 = "0 V"
if not hasattr(obj, "AV_re_3"):
obj.addProperty(
"App::PropertyElectricPotential",
"AV_re_3",
"Vector Potential",
"Real part of potential z-component",
)
obj.setPropertyStatus("AV_re_3", "LockDynamic")
obj.AV_re_3 = "0 V"
if not hasattr(obj, "AV_im"):
obj.addProperty(
"App::PropertyElectricPotential",
"AV_im",
"Vector Potential",
"Imaginary part of scalar potential",
)
obj.setPropertyStatus("AV_im", "LockDynamic")
obj.AV_im = "0 V"
if not hasattr(obj, "AV_im_1"):
obj.addProperty(
"App::PropertyElectricPotential",
"AV_im_1",
"Vector Potential",
"Imaginary part of potential x-component",
)
obj.setPropertyStatus("AV_im_1", "LockDynamic")
obj.AV_im_1 = "0 V"
if not hasattr(obj, "AV_im_2"):
obj.addProperty(
"App::PropertyElectricPotential",
"AV_im_2",
"Vector Potential",
"Imaginary part of potential y-component",
)
obj.setPropertyStatus("AV_im_2", "LockDynamic")
obj.AV_im_2 = "0 V"
if not hasattr(obj, "AV_im_3"):
obj.addProperty(
"App::PropertyElectricPotential",
"AV_im_3",
"Vector Potential",
"Imaginary part of potential z-component",
)
obj.setPropertyStatus("AV_im_3", "LockDynamic")
obj.AV_im_3 = "0 V"
# enable electromagnetic properties from old properties
try:
obj.EnableAV_1 = not obj.getPropertyByName(
"AV_re_1_Disabled"
) or not obj.getPropertyByName("AV_im_1_Disabled")
obj.EnableAV_2 = not obj.getPropertyByName(
"AV_re_2_Disabled"
) or not obj.getPropertyByName("AV_im_2_Disabled")
obj.EnableAV_3 = not obj.getPropertyByName(
"AV_re_3_Disabled"
) or not obj.getPropertyByName("AV_im_3_Disabled")
obj.EnableAV = not obj.getPropertyByName("AV_im_Disabled")
# now the enable bools
if not hasattr(obj, "PotentialEnabled"):
obj.addProperty(
"App::PropertyBool", "PotentialEnabled", "Parameter", "Potential Enabled"
)
obj.setPropertyStatus("PotentialEnabled", "LockDynamic")
obj.PotentialEnabled = True
if not hasattr(obj, "AV_re_1_Disabled"):
obj.addProperty("App::PropertyBool", "AV_re_1_Disabled", "Vector Potential", "")
obj.setPropertyStatus("AV_re_1_Disabled", "LockDynamic")
obj.AV_re_1_Disabled = True
if not hasattr(obj, "AV_re_2_Disabled"):
obj.addProperty("App::PropertyBool", "AV_re_2_Disabled", "Vector Potential", "")
obj.setPropertyStatus("AV_re_2_Disabled", "LockDynamic")
obj.AV_re_2_Disabled = True
if not hasattr(obj, "AV_re_3_Disabled"):
obj.addProperty("App::PropertyBool", "AV_re_3_Disabled", "Vector Potential", "")
obj.setPropertyStatus("AV_re_3_Disabled", "LockDynamic")
obj.AV_re_3_Disabled = True
if not hasattr(obj, "AV_im_Disabled"):
obj.addProperty("App::PropertyBool", "AV_im_Disabled", "Vector Potential", "")
obj.setPropertyStatus("AV_im_Disabled", "LockDynamic")
obj.AV_im_Disabled = True
if not hasattr(obj, "AV_im_1_Disabled"):
obj.addProperty("App::PropertyBool", "AV_im_1_Disabled", "Vector Potential", "")
obj.setPropertyStatus("AV_im_1_Disabled", "LockDynamic")
obj.AV_im_1_Disabled = True
if not hasattr(obj, "AV_im_2_Disabled"):
obj.addProperty("App::PropertyBool", "AV_im_2_Disabled", "Vector Potential", "")
obj.setPropertyStatus("AV_im_2_Disabled", "LockDynamic")
obj.AV_im_2_Disabled = True
if not hasattr(obj, "AV_im_3_Disabled"):
obj.addProperty("App::PropertyBool", "AV_im_3_Disabled", "Vector Potential", "")
obj.setPropertyStatus("AV_im_3_Disabled", "LockDynamic")
obj.AV_im_3_Disabled = True
# remove old properties
obj.setPropertyStatus("AV_re_1_Disabled", "-LockDynamic")
obj.removeProperty("AV_re_1_Disabled")
obj.setPropertyStatus("AV_re_2_Disabled", "-LockDynamic")
obj.removeProperty("AV_re_2_Disabled")
obj.setPropertyStatus("AV_re_3_Disabled", "-LockDynamic")
obj.removeProperty("AV_re_3_Disabled")
obj.setPropertyStatus("AV_im_1_Disabled", "-LockDynamic")
obj.removeProperty("AV_im_1_Disabled")
obj.setPropertyStatus("AV_im_2_Disabled", "-LockDynamic")
obj.removeProperty("AV_im_2_Disabled")
obj.setPropertyStatus("AV_im_3_Disabled", "-LockDynamic")
obj.removeProperty("AV_im_3_Disabled")
obj.setPropertyStatus("AV_im_Disabled", "-LockDynamic")
obj.removeProperty("AV_im_Disabled")
if not hasattr(obj, "PotentialConstant"):
obj.addProperty(
"App::PropertyBool", "PotentialConstant", "Parameter", "Potential Constant"
)
obj.setPropertyStatus("PotentialConstant", "LockDynamic")
obj.PotentialConstant = False
if not hasattr(obj, "ElectricInfinity"):
obj.addProperty(
"App::PropertyBool", "ElectricInfinity", "Parameter", "Electric Infinity"
)
obj.setPropertyStatus("ElectricInfinity", "LockDynamic")
obj.ElectricInfinity = False
if not hasattr(obj, "ElectricForcecalculation"):
obj.addProperty(
"App::PropertyBool",
"ElectricForcecalculation",
"Parameter",
"Electric Force Calculation",
)
obj.setPropertyStatus("ElectricForcecalculation", "LockDynamic")
obj.ElectricForcecalculation = False
if not hasattr(obj, "CapacitanceBody"):
obj.addProperty(
"App::PropertyInteger", "CapacitanceBody", "Parameter", "Capacitance Body"
)
obj.setPropertyStatus("CapacitanceBody", "LockDynamic")
obj.CapacitanceBody = 0
if not hasattr(obj, "CapacitanceBodyEnabled"):
obj.addProperty(
"App::PropertyBool",
"CapacitanceBodyEnabled",
"Parameter",
"Capacitance Body Enabled",
)
obj.setPropertyStatus("CapacitanceBodyEnabled", "LockDynamic")
obj.CapacitanceBodyEnabled = False
except Base.PropertyError:
pass

View File

@@ -125,22 +125,17 @@ class ESwriter:
# output the FreeCAD label as comment
if obj.Label:
self.write.boundary(name, "! FreeCAD Name", obj.Label)
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.BoundaryCondition == "Dirichlet":
if obj.PotentialEnabled:
self.write.boundary(
name, "Potential", obj.Potential.getValueAs("V").Value
)
elif obj.BoundaryCondition == "Neumann":
self.write.boundary(
name,
"Surface Charge Density",
obj.SurfaceChargeDensity.getValueAs("C/m^2").Value,
)
if obj.PotentialConstant:
self.write.boundary(name, "Potential Constant", True)
if obj.ElectricInfinity:
@@ -148,8 +143,7 @@ class ESwriter:
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.boundary(name, "Capacitance Body", obj.CapacitanceBody)
self.write.handled(obj)

View File

@@ -31,6 +31,7 @@ __url__ = "https://www.freecad.org"
from FreeCAD import Console
from FreeCAD import Units
from femtools import femutils
from .. import sifio
from .. import writer as general_writer
@@ -207,16 +208,13 @@ class MgDynwriter:
magnetization = float(obj.Magnetization_im_3.getValueAs("A/m"))
self.write.bodyForce(name, "Magnetization Im 3", magnetization)
if hasattr(obj, "PotentialEnabled"):
# check for PotentialEnabled not Potential since PotentialEnabled was
# added later and only with this the imaginary property is available
if femutils.is_derived_from(obj, "Fem::ConstraintElectrostaticPotential"):
if obj.PotentialEnabled:
# output only if potential is enabled and needed
potential = float(obj.Potential.getValueAs("V"))
self.write.bodyForce(name, "Electric Potential", round(potential, 6))
# imaginary is only needed for harmonic equation
if equation.IsHarmonic:
if not obj.AV_im_Disabled:
# imaginary is only needed for harmonic equation
if equation.IsHarmonic:
potential = float(obj.AV_im.getValueAs("V"))
self.write.bodyForce(name, "Electric Potential Im", round(potential, 6))
@@ -289,47 +287,39 @@ class MgDynwriter:
currentDensity = float(obj.CurrentDensity_im_1.getValueAs("A/m^2"))
self.write.boundary(name, "Current Density Im 1", round(currentDensity, 6))
if hasattr(obj, "PotentialEnabled"):
# check for PotentialEnabled not Potential since PotentialEnabled was
# added later and only with this the vectorial properties are available
if obj.PotentialEnabled:
potential = float(obj.Potential.getValueAs("V"))
if femutils.is_derived_from(obj, "Fem::ConstraintElectrostaticPotential"):
if obj.EnableAV:
potential = obj.AV_re.getValueAs("V").Value
if equation.IsHarmonic:
self.write.boundary(name, "AV re", round(potential, 6))
potential = obj.AV_im.getValueAs("V").Value
self.write.boundary(name, "AV im", round(potential, 6))
else:
self.write.boundary(name, "AV", round(potential, 6))
if not obj.AV_re_1_Disabled:
potential = float(obj.AV_re_1.getValueAs("V"))
if obj.EnableAV_1:
potential = obj.AV_re_1.getValueAs("Wb/m").Value
if equation.IsHarmonic:
self.write.boundary(name, "AV re {e} 1", round(potential, 6))
potential = obj.AV_im_1.getValueAs("Wb/m").Value
self.write.boundary(name, "AV im {e} 1", round(potential, 6))
else:
self.write.boundary(name, "AV {e} 1", round(potential, 6))
if not obj.AV_re_2_Disabled:
potential = float(obj.AV_re_2.getValueAs("V"))
if obj.EnableAV_2:
potential = obj.AV_re_2.getValueAs("Wb/m").Value
if equation.IsHarmonic:
self.write.boundary(name, "AV re {e} 2", round(potential, 6))
potential = obj.AV_im_2.getValueAs("Wb/m").Value
self.write.boundary(name, "AV im {e} 2", round(potential, 6))
else:
self.write.boundary(name, "AV {e} 2", round(potential, 6))
if not obj.AV_re_3_Disabled:
potential = float(obj.AV_re_3.getValueAs("V"))
if obj.EnableAV_3:
potential = obj.AV_re_3.getValueAs("Wb/m").Value
if equation.IsHarmonic:
self.write.boundary(name, "AV re {e} 3", round(potential, 6))
potential = obj.AV_im_3.getValueAs("Wb/m").Value
self.write.boundary(name, "AV im {e} 3", round(potential, 6))
else:
self.write.boundary(name, "AV {e} 3", round(potential, 6))
# imaginaries are only needed for harmonic equation
if equation.IsHarmonic:
if not obj.AV_im_Disabled:
potential = float(obj.AV_im.getValueAs("V"))
self.write.boundary(name, "AV im", round(potential, 6))
if not obj.AV_im_1_Disabled:
potential = float(obj.AV_im_1.getValueAs("V"))
self.write.boundary(name, "AV im {e} 1", round(potential, 6))
if not obj.AV_im_2_Disabled:
potential = float(obj.AV_im_2.getValueAs("V"))
self.write.boundary(name, "AV im {e} 2", round(potential, 6))
if not obj.AV_im_3_Disabled:
potential = float(obj.AV_im_3.getValueAs("V"))
self.write.boundary(name, "AV im {e} 3", round(potential, 6))
def handleMagnetodynamicBndConditions(self, equation):
# the current density can either be a body force or a boundary constraint

View File

@@ -2,6 +2,7 @@
# * Copyright (c) 2017 Markus Hovorka <m.hovorka@live.de> *
# * Copyright (c) 2020 Bernd Hahnebach <bernd@bimstatik.org> *
# * Copyright (c) 2023 Uwe Stöhr <uwestoehr@lyx.org> *
# * Copyright (c) 2024 Mario Passaglia <mpassaglia[at]cbc.uba.ar> *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
@@ -24,7 +25,7 @@
# ***************************************************************************
__title__ = "FreeCAD FEM constraint electrostatic potential task panel for the document object"
__author__ = "Markus Hovorka, Bernd Hahnebach, Uwe Stöhr"
__author__ = "Markus Hovorka, Bernd Hahnebach, Uwe Stöhr, André Kapelrud, Mario Passaglia"
__url__ = "https://www.freecad.org"
## @package task_constraint_electrostaticpotential
@@ -46,10 +47,9 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
def __init__(self, obj):
super().__init__(obj)
self._paramWidget = FreeCADGui.PySideUic.loadUi(
self.parameter_widget = FreeCADGui.PySideUic.loadUi(
FreeCAD.getHomePath() + "Mod/Fem/Resources/ui/ElectrostaticPotential.ui"
)
self._initParamWidget()
# geometry selection widget
# start with Solid in list!
@@ -58,7 +58,7 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
)
# form made from param and selection widget
self.form = [self._paramWidget, self._selectionWidget]
self.form = [self.parameter_widget, self._selectionWidget]
analysis = obj.getParentGroup()
self._mesh = None
@@ -70,26 +70,113 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
self._partVisible = None
self._meshVisible = None
# start with vector inputs hidden if no vector is set
if (
self.obj.AV_re_1_Disabled
and self.obj.AV_re_2_Disabled
and self.obj.AV_re_3_Disabled
and self.obj.AV_im_Disabled
and self.obj.AV_im_1_Disabled
and self.obj.AV_im_2_Disabled
and self.obj.AV_im_3_Disabled
):
self._vectorField_visibility(False)
self._paramWidget.vectorFieldBox.setChecked(False)
QtCore.QObject.connect(
self._paramWidget.vectorFieldBox,
self.parameter_widget.ckb_electromagnetic,
QtCore.SIGNAL("toggled(bool)"),
self._vectorField_visibility,
self.electromagnetic_enabled_changed,
)
QtCore.QObject.connect(
self.parameter_widget.cb_boundary_condition,
QtCore.SIGNAL("currentIndexChanged(int)"),
self.boundary_condition_changed,
)
QtCore.QObject.connect(
self.parameter_widget.ckb_potential,
QtCore.SIGNAL("toggled(bool)"),
self.potential_enabled_changed,
)
QtCore.QObject.connect(
self.parameter_widget.qsb_potential,
QtCore.SIGNAL("valueChanged(Base::Quantity)"),
self.potential_changed,
)
QtCore.QObject.connect(
self.parameter_widget.ckb_av,
QtCore.SIGNAL("toggled(bool)"),
self.av_enabled_changed,
)
QtCore.QObject.connect(
self.parameter_widget.qsb_av_re,
QtCore.SIGNAL("valueChanged(Base::Quantity)"),
self.av_re_changed,
)
QtCore.QObject.connect(
self.parameter_widget.ckb_av_1,
QtCore.SIGNAL("toggled(bool)"),
self.av_1_enabled_changed,
)
QtCore.QObject.connect(
self.parameter_widget.qsb_av_re_1,
QtCore.SIGNAL("valueChanged(Base::Quantity)"),
self.av_re_1_changed,
)
QtCore.QObject.connect(
self.parameter_widget.ckb_av_2,
QtCore.SIGNAL("toggled(bool)"),
self.av_2_enabled_changed,
)
QtCore.QObject.connect(
self.parameter_widget.qsb_av_re_2,
QtCore.SIGNAL("valueChanged(Base::Quantity)"),
self.av_re_2_changed,
)
QtCore.QObject.connect(
self.parameter_widget.ckb_av_3,
QtCore.SIGNAL("toggled(bool)"),
self.av_3_enabled_changed,
)
QtCore.QObject.connect(
self.parameter_widget.qsb_av_re_3,
QtCore.SIGNAL("valueChanged(Base::Quantity)"),
self.av_re_3_changed,
)
QtCore.QObject.connect(
self.parameter_widget.qsb_av_im,
QtCore.SIGNAL("valueChanged(Base::Quantity)"),
self.av_im_changed,
)
QtCore.QObject.connect(
self.parameter_widget.qsb_av_im_1,
QtCore.SIGNAL("valueChanged(Base::Quantity)"),
self.av_im_1_changed,
)
QtCore.QObject.connect(
self.parameter_widget.qsb_av_im_2,
QtCore.SIGNAL("valueChanged(Base::Quantity)"),
self.av_im_2_changed,
)
QtCore.QObject.connect(
self.parameter_widget.qsb_av_im_3,
QtCore.SIGNAL("valueChanged(Base::Quantity)"),
self.av_im_3_changed,
)
QtCore.QObject.connect(
self.parameter_widget.ckb_capacitance_body,
QtCore.SIGNAL("toggled(bool)"),
self.capacitance_body_enabled_changed,
)
QtCore.QObject.connect(
self.parameter_widget.spb_capacitance_body,
QtCore.SIGNAL("valueChanged(int)"),
self.capacitance_body_changed,
)
QtCore.QObject.connect(
self.parameter_widget.ckb_potential_constant,
QtCore.SIGNAL("toggled(bool)"),
self.potential_constant_changed,
)
QtCore.QObject.connect(
self.parameter_widget.ckb_electric_infinity,
QtCore.SIGNAL("toggled(bool)"),
self.electric_infinity_changed,
)
QtCore.QObject.connect(
self.parameter_widget.qsb_surface_charge_density,
QtCore.SIGNAL("valueChanged(Base::Quantity)"),
self.surface_charge_density_changed,
)
def _vectorField_visibility(self, visible):
self._paramWidget.vectorFieldGB.setVisible(visible)
self.init_parameter_widget()
def open(self):
if self._mesh is not None and self._part is not None:
@@ -106,7 +193,7 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
def accept(self):
if self.obj.References != self._selectionWidget.references:
self.obj.References = self._selectionWidget.references
self._applyWidgetChanges()
self._set_params()
self._selectionWidget.finish_selection()
self._restoreVisibility()
return super().accept()
@@ -122,100 +209,202 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
else:
self._part.ViewObject.hide()
def _initParamWidget(self):
self._paramWidget.potentialQSB.setProperty("value", self.obj.Potential)
FreeCADGui.ExpressionBinding(self._paramWidget.potentialQSB).bind(self.obj, "Potential")
self._paramWidget.potentialBox.setChecked(not self.obj.PotentialEnabled)
def _get_params(self):
self.potential = self.obj.Potential
self.potential_enabled = self.obj.PotentialEnabled
# the vector potentials
# realScalarQSB always the same value as potentialQSB
self._paramWidget.realScalarQSB.setProperty("value", self.obj.Potential)
FreeCADGui.ExpressionBinding(self._paramWidget.realScalarQSB).bind(self.obj, "Potential")
self._paramWidget.realXQSB.setProperty("value", self.obj.AV_re_1)
FreeCADGui.ExpressionBinding(self._paramWidget.realXQSB).bind(self.obj, "AV_re_1")
self._paramWidget.realYQSB.setProperty("value", self.obj.AV_re_2)
FreeCADGui.ExpressionBinding(self._paramWidget.realYQSB).bind(self.obj, "AV_re_2")
self._paramWidget.realZQSB.setProperty("value", self.obj.AV_re_3)
FreeCADGui.ExpressionBinding(self._paramWidget.realZQSB).bind(self.obj, "AV_re_3")
self._paramWidget.imagScalarQSB.setProperty("value", self.obj.AV_im)
FreeCADGui.ExpressionBinding(self._paramWidget.imagScalarQSB).bind(self.obj, "AV_im")
self._paramWidget.imagXQSB.setProperty("value", self.obj.AV_im_1)
FreeCADGui.ExpressionBinding(self._paramWidget.imagXQSB).bind(self.obj, "AV_im_1")
self._paramWidget.imagYQSB.setProperty("value", self.obj.AV_im_2)
FreeCADGui.ExpressionBinding(self._paramWidget.imagYQSB).bind(self.obj, "AV_im_2")
self._paramWidget.imagZQSB.setProperty("value", self.obj.AV_im_3)
FreeCADGui.ExpressionBinding(self._paramWidget.imagZQSB).bind(self.obj, "AV_im_3")
self.av_re = self.obj.AV_re
self.av_re_1 = self.obj.AV_re_1
self.av_re_2 = self.obj.AV_re_2
self.av_re_3 = self.obj.AV_re_3
self.av_im = self.obj.AV_im
self.av_im_1 = self.obj.AV_im_1
self.av_im_2 = self.obj.AV_im_2
self.av_im_3 = self.obj.AV_im_3
self._paramWidget.reXunspecBox.setChecked(self.obj.AV_re_1_Disabled)
self._paramWidget.reYunspecBox.setChecked(self.obj.AV_re_2_Disabled)
self._paramWidget.reZunspecBox.setChecked(self.obj.AV_re_3_Disabled)
self._paramWidget.imScalarunspecBox.setChecked(self.obj.AV_im_Disabled)
self._paramWidget.imXunspecBox.setChecked(self.obj.AV_im_1_Disabled)
self._paramWidget.imYunspecBox.setChecked(self.obj.AV_im_2_Disabled)
self._paramWidget.imZunspecBox.setChecked(self.obj.AV_im_3_Disabled)
self.av_enabled = self.obj.EnableAV
self.av_1_enabled = self.obj.EnableAV_1
self.av_2_enabled = self.obj.EnableAV_2
self.av_3_enabled = self.obj.EnableAV_3
self._paramWidget.potentialConstantBox.setChecked(self.obj.PotentialConstant)
self.boundary_condition = self.obj.BoundaryCondition
self.potential_constant = self.obj.PotentialConstant
self.electric_infinity = self.obj.ElectricInfinity
self.capacitance_body_enabled = self.obj.CapacitanceBodyEnabled
self.capacitance_body = self.obj.CapacitanceBody
self.surface_charge_density = self.obj.SurfaceChargeDensity
self._paramWidget.electricInfinityBox.setChecked(self.obj.ElectricInfinity)
def _set_params(self):
self.obj.Potential = self.potential
self.obj.PotentialEnabled = self.potential_enabled
self._paramWidget.electricForcecalculationBox.setChecked(self.obj.ElectricForcecalculation)
self.obj.AV_re = self.av_re
self.obj.AV_re_1 = self.av_re_1
self.obj.AV_re_2 = self.av_re_2
self.obj.AV_re_3 = self.av_re_3
self.obj.AV_im = self.av_im
self.obj.AV_im_1 = self.av_im_1
self.obj.AV_im_2 = self.av_im_2
self.obj.AV_im_3 = self.av_im_3
self._paramWidget.capacitanceBodyBox.setChecked(not self.obj.CapacitanceBodyEnabled)
self._paramWidget.capacitanceBody_spinBox.setValue(self.obj.CapacitanceBody)
self._paramWidget.capacitanceBody_spinBox.setEnabled(
not self._paramWidget.capacitanceBodyBox.isChecked()
self.obj.EnableAV = self.av_enabled
self.obj.EnableAV_1 = self.av_1_enabled
self.obj.EnableAV_2 = self.av_2_enabled
self.obj.EnableAV_3 = self.av_3_enabled
self.obj.BoundaryCondition = self.boundary_condition
self.obj.PotentialConstant = self.potential_constant
self.obj.ElectricInfinity = self.electric_infinity
self.obj.CapacitanceBodyEnabled = self.capacitance_body_enabled
self.obj.CapacitanceBody = self.capacitance_body
self.obj.SurfaceChargeDensity = self.surface_charge_density
def init_parameter_widget(self):
self._get_params()
self.parameter_widget.qsb_potential.setProperty("value", self.potential)
FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_potential).bind(
self.obj, "Potential"
)
self.parameter_widget.ckb_potential.setChecked(self.potential_enabled)
# scalar potential
self.parameter_widget.qsb_av_re.setProperty("value", self.av_re)
self.parameter_widget.qsb_av_re.setEnabled(self.av_enabled)
FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_av_re).bind(self.obj, "AV_re")
self.parameter_widget.qsb_av_im.setProperty("value", self.av_im)
self.parameter_widget.qsb_av_im.setEnabled(self.av_enabled)
FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_av_im).bind(self.obj, "AV_im")
# vector potential
self.parameter_widget.qsb_av_re_1.setProperty("value", self.av_re_1)
self.parameter_widget.qsb_av_re_1.setEnabled(self.av_1_enabled)
FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_av_re_1).bind(self.obj, "AV_re_1")
self.parameter_widget.qsb_av_re_2.setProperty("value", self.av_re_2)
self.parameter_widget.qsb_av_re_2.setEnabled(self.av_2_enabled)
FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_av_re_2).bind(self.obj, "AV_re_2")
self.parameter_widget.qsb_av_re_3.setProperty("value", self.av_re_3)
self.parameter_widget.qsb_av_re_3.setEnabled(self.av_3_enabled)
FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_av_re_3).bind(self.obj, "AV_re_3")
self.parameter_widget.qsb_av_im_1.setProperty("value", self.av_im_1)
self.parameter_widget.qsb_av_im_1.setEnabled(self.av_1_enabled)
FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_av_im_1).bind(self.obj, "AV_im_1")
self.parameter_widget.qsb_av_im_2.setProperty("value", self.av_im_2)
self.parameter_widget.qsb_av_im_2.setEnabled(self.av_2_enabled)
FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_av_im_2).bind(self.obj, "AV_im_2")
self.parameter_widget.qsb_av_im_3.setProperty("value", self.av_im_3)
self.parameter_widget.qsb_av_im_3.setEnabled(self.av_3_enabled)
FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_av_im_3).bind(self.obj, "AV_im_3")
self.parameter_widget.ckb_av.setChecked(self.av_enabled)
self.parameter_widget.ckb_av_1.setChecked(self.av_1_enabled)
self.parameter_widget.ckb_av_2.setChecked(self.av_2_enabled)
self.parameter_widget.ckb_av_3.setChecked(self.av_3_enabled)
self.parameter_widget.ckb_potential_constant.setChecked(self.potential_constant)
self.parameter_widget.ckb_electric_infinity.setChecked(self.electric_infinity)
self.parameter_widget.ckb_capacitance_body.setChecked(self.capacitance_body_enabled)
self.parameter_widget.spb_capacitance_body.setProperty("value", self.capacitance_body)
FreeCADGui.ExpressionBinding(self.parameter_widget.spb_capacitance_body).bind(
self.obj, "CapacitanceBody"
)
def _applyPotentialChanges(self, enabledBox, potentialQSB):
enabled = enabledBox.isChecked()
potential = None
try:
potential = potentialQSB.property("value")
except ValueError:
FreeCAD.Console.PrintMessage(
"Wrong input. Not recognised input: '{}' "
"Potential has not been set.\n".format(potentialQSB.text())
)
potential = "0.0 mm^2*kg/(s^3*A)"
return enabled, potential
self.parameter_widget.qsb_surface_charge_density.setProperty(
"value", self.surface_charge_density
)
FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_surface_charge_density).bind(
self.obj, "SurfaceChargeDensity"
)
def _applyWidgetChanges(self):
# apply the voltages and their enabled state
self.obj.PotentialEnabled, self.obj.Potential = self._applyPotentialChanges(
self._paramWidget.potentialBox, self._paramWidget.potentialQSB
)
self.obj.AV_re_1_Disabled, self.obj.AV_re_1 = self._applyPotentialChanges(
self._paramWidget.reXunspecBox, self._paramWidget.realXQSB
)
self.obj.AV_re_2_Disabled, self.obj.AV_re_2 = self._applyPotentialChanges(
self._paramWidget.reYunspecBox, self._paramWidget.realYQSB
)
self.obj.AV_re_3_Disabled, self.obj.AV_re_3 = self._applyPotentialChanges(
self._paramWidget.reZunspecBox, self._paramWidget.realZQSB
)
self.obj.AV_im_Disabled, self.obj.AV_im = self._applyPotentialChanges(
self._paramWidget.imScalarunspecBox, self._paramWidget.imagScalarQSB
)
self.obj.AV_im_1_Disabled, self.obj.AV_im_1 = self._applyPotentialChanges(
self._paramWidget.imXunspecBox, self._paramWidget.imagXQSB
)
self.obj.AV_im_2_Disabled, self.obj.AV_im_2 = self._applyPotentialChanges(
self._paramWidget.imYunspecBox, self._paramWidget.imagYQSB
)
self.obj.AV_im_3_Disabled, self.obj.AV_im_3 = self._applyPotentialChanges(
self._paramWidget.imZunspecBox, self._paramWidget.imagZQSB
)
# because this is an enable the others are disabled, reverse
self.obj.PotentialEnabled = not self.obj.PotentialEnabled
self.bc_enum = self.obj.getEnumerationsOfProperty("BoundaryCondition")
index = self.bc_enum.index(self.boundary_condition)
self.parameter_widget.cb_boundary_condition.addItems(self.bc_enum)
self.parameter_widget.cb_boundary_condition.setCurrentIndex(index)
self.obj.PotentialConstant = self._paramWidget.potentialConstantBox.isChecked()
# start with electromagnetic inputs hidden if no field is set
if not (self.av_enabled or self.av_1_enabled or self.av_2_enabled or self.av_3_enabled):
self.parameter_widget.ckb_electromagnetic.setChecked(False)
self.obj.ElectricInfinity = self._paramWidget.electricInfinityBox.isChecked()
def potential_changed(self, value):
self.potential = value
calc_is_checked = self._paramWidget.electricForcecalculationBox.isChecked()
self.obj.ElectricForcecalculation = calc_is_checked # two lines because max line length
def potential_enabled_changed(self, value):
self.potential_enabled = value
self.parameter_widget.qsb_potential.setEnabled(value)
self.obj.CapacitanceBodyEnabled = not self._paramWidget.capacitanceBodyBox.isChecked()
if self.obj.CapacitanceBodyEnabled:
self._paramWidget.capacitanceBody_spinBox.setEnabled(True)
self.obj.CapacitanceBody = self._paramWidget.capacitanceBody_spinBox.value()
def electromagnetic_enabled_changed(self, value):
self.parameter_widget.gb_electromagnetic.setVisible(value)
def av_enabled_changed(self, value):
self.av_enabled = value
self.parameter_widget.qsb_av_re.setEnabled(value)
self.parameter_widget.qsb_av_im.setEnabled(value)
def av_1_enabled_changed(self, value):
self.av_1_enabled = value
self.parameter_widget.qsb_av_re_1.setEnabled(value)
self.parameter_widget.qsb_av_im_1.setEnabled(value)
def av_2_enabled_changed(self, value):
self.av_2_enabled = value
self.parameter_widget.qsb_av_re_2.setEnabled(value)
self.parameter_widget.qsb_av_im_2.setEnabled(value)
def av_3_enabled_changed(self, value):
self.av_3_enabled = value
self.parameter_widget.qsb_av_re_3.setEnabled(value)
self.parameter_widget.qsb_av_im_3.setEnabled(value)
def av_re_changed(self, value):
self.av_re = value
def av_re_1_changed(self, value):
self.av_re_1 = value
def av_re_2_changed(self, value):
self.av_re_2 = value
def av_re_3_changed(self, value):
self.av_re_3 = value
def av_im_changed(self, value):
self.av_im = value
def av_im_1_changed(self, value):
self.av_im_1 = value
def av_im_2_changed(self, value):
self.av_im_2 = value
def av_im_3_changed(self, value):
self.av_im_3 = value
def potential_constant_changed(self, value):
self.potential_constant = value
def electric_infinity_changed(self, value):
self.electric_infinity = value
def capacitance_body_enabled_changed(self, value):
self.capacitance_body_enabled = value
self.parameter_widget.spb_capacitance_body.setEnabled(value)
def capacitance_body_changed(self, value):
self.capacitance_body = value
self.parameter_widget.spb_capacitance_body.setValue(value)
def surface_charge_density_changed(self, value):
self.surface_charge_density = value
def boundary_condition_changed(self, index):
self.boundary_condition = self.bc_enum[index]
if self.boundary_condition == "Dirichlet":
self.parameter_widget.gb_neumann.setEnabled(False)
self.parameter_widget.gb_dirichlet.setEnabled(True)
elif self.boundary_condition == "Neumann":
self.parameter_widget.gb_neumann.setEnabled(True)
self.parameter_widget.gb_dirichlet.setEnabled(False)