From aaa976953d13a8ee26e28b930d901e5c94bcb06b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Kapelrud?= Date: Mon, 6 Jan 2025 13:02:10 -0300 Subject: [PATCH 1/5] Base: Add surface charge density unit --- src/App/Application.cpp | 1 + src/App/PropertyUnits.cpp | 11 +++++++++++ src/App/PropertyUnits.h | 13 +++++++++++++ src/Base/Unit.cpp | 4 +++- src/Base/Unit.h | 1 + src/Base/UnitsSchemaInternal.cpp | 4 ++++ src/Base/UnitsSchemaMKS.cpp | 4 ++++ 7 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/App/Application.cpp b/src/App/Application.cpp index 967bf5bcb2..ee28b528eb 100644 --- a/src/App/Application.cpp +++ b/src/App/Application.cpp @@ -2060,6 +2060,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(); diff --git a/src/App/PropertyUnits.cpp b/src/App/PropertyUnits.cpp index b18ea6b65f..b4ed219cd9 100644 --- a/src/App/PropertyUnits.cpp +++ b/src/App/PropertyUnits.cpp @@ -392,6 +392,17 @@ PropertyElectricCharge::PropertyElectricCharge() setUnit(Base::Unit::ElectricCharge); } +//************************************************************************** +// PropertySurfaceChargeDensity +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +TYPESYSTEM_SOURCE(App::PropertySurfaceChargeDensity, App::PropertyQuantity) + +PropertySurfaceChargeDensity::PropertySurfaceChargeDensity() +{ + setUnit(Base::Unit::SurfaceChargeDensity); +} + //************************************************************************** // PropertyElectricCurrent //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/src/App/PropertyUnits.h b/src/App/PropertyUnits.h index 8a19ead0ce..e81a8fd9c3 100644 --- a/src/App/PropertyUnits.h +++ b/src/App/PropertyUnits.h @@ -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. diff --git a/src/Base/Unit.cpp b/src/Base/Unit.cpp index a3c2a12c87..6aaa117af1 100644 --- a/src/Base/Unit.cpp +++ b/src/Base/Unit.cpp @@ -587,7 +587,7 @@ std::string Unit::getString() const std::string Unit::getTypeString() const { - static std::array, 55> unitSpecs {{ + static std::array, 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); diff --git a/src/Base/Unit.h b/src/Base/Unit.h index 670cf67526..b47d5c26ae 100644 --- a/src/Base/Unit.h +++ b/src/Base/Unit.h @@ -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; diff --git a/src/Base/UnitsSchemaInternal.cpp b/src/Base/UnitsSchemaInternal.cpp index 63e543d205..1d67455bab 100644 --- a/src/Base/UnitsSchemaInternal.cpp +++ b/src/Base/UnitsSchemaInternal.cpp @@ -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"; diff --git a/src/Base/UnitsSchemaMKS.cpp b/src/Base/UnitsSchemaMKS.cpp index 98ef0545eb..241e3eba9b 100644 --- a/src/Base/UnitsSchemaMKS.cpp +++ b/src/Base/UnitsSchemaMKS.cpp @@ -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"; From 9ad7bd37e3bdfff58aa21618b85de131989eac53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Kapelrud?= Date: Mon, 6 Jan 2025 16:57:18 -0300 Subject: [PATCH 2/5] Fem: Add Neumann boundary condition for electrostatic potential --- .../Resources/ui/ElectrostaticPotential.ui | 1187 +++++++++-------- .../constraint_electrostaticpotential.py | 20 + .../elmer/equations/electrostatic_writer.py | 36 +- .../task_constraint_electrostaticpotential.py | 38 +- 4 files changed, 716 insertions(+), 565 deletions(-) diff --git a/src/Mod/Fem/Gui/Resources/ui/ElectrostaticPotential.ui b/src/Mod/Fem/Gui/Resources/ui/ElectrostaticPotential.ui index 0e0338008c..fd83f7d508 100644 --- a/src/Mod/Fem/Gui/Resources/ui/ElectrostaticPotential.ui +++ b/src/Mod/Fem/Gui/Resources/ui/ElectrostaticPotential.ui @@ -6,8 +6,8 @@ 0 0 - 317 - 303 + 357 + 593 @@ -15,602 +15,690 @@ - - - - - Potential: - - - - - - - Qt::Horizontal - - - - 20 - 20 - - - - - - - - false - - - - 100 - 20 - - - - Electric potential - - - true - - - V - - - -1000000000000000000000.000000000000000 - - - 1000000000000000000000.000000000000000 - - - 1.000000000000000 - - - 1.000000000000000 - - - - - - - unspecified - - - true - - - - - - - - - To define a vector field - + - Vector Field + Dirichlet true + + BCtypeBG + - - - - true + + + + Neumann - - Imaginary part is only used for equations -with a harmonic/oscillating driving force + + BCtypeBG + + + + + + + false - - false - - - - + + + true - - Real - - - - - - - true - - - Imaginary - - - - - - - true - - - Scalar - - - - - - - false - - - - 100 - 20 - - - Potential as specified above - - - true - - - true - - - V - - - -1000000000000000000000.000000000000000 - - - 1000000000000000000000.000000000000000 - - - 1.000000000000000 - - - 1.000000000000000 - - - - - - - true - - - - 100 - 20 - - - - Imaginary part of scalar potential - - - true - - - V - - - -1000000000000000000000.000000000000000 - - - 1000000000000000000000.000000000000000 - - - 1.000000000000000 - - - 1.000000000000000 - - - - - - - unspecified + Whether the boundary condition defines a farfield potential - + Farfield / Electric infinity + + + + + + + + + false + + + Electric potential + + + true + + + + + + -1000000000000000000000.000000000000000 + + + 1000000000000000000000.000000000000000 + + + 1.000000000000000 + + + 1.000000000000000 + + + + + + + Potential: + + + + + + + unspecified + + + true + + + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + + + Whether the boundary condition defines a constant potential + + + Potential Constant - + true - - x - - - - - - - true - - - - 100 - 20 - - - Real part of potential x-component + Imaginary part is only used for equations +with a harmonic/oscillating driving force + + + false + + + false + + + + + + true + + + Real + + + + + + + true + + + Imaginary + + + + + + + true + + + Scalar + + + + + + + false + + + + 100 + 20 + + + + Potential as specified above + + + true + + + true + + + V + + + -1000000000000000000000.000000000000000 + + + 1000000000000000000000.000000000000000 + + + 1.000000000000000 + + + 1.000000000000000 + + + + + + + true + + + + 100 + 20 + + + + Imaginary part of scalar potential + + + true + + + V + + + -1000000000000000000000.000000000000000 + + + 1000000000000000000000.000000000000000 + + + 1.000000000000000 + + + 1.000000000000000 + + + + + + + unspecified + + + + + + + + + + true + + + x + + + + + + + true + + + + 100 + 20 + + + + Real part of potential x-component Note: has no effect if a solid was selected - - - true - - - V - - - -1000000000000000000000.000000000000000 - - - 1000000000000000000000.000000000000000 - - - 1.000000000000000 - - - 1.000000000000000 - - - - - - - unspecified - - - - - - - - - - true - - - - 100 - 20 - - - - Imaginary part of potential x-component + + + true + + + V + + + -1000000000000000000000.000000000000000 + + + 1000000000000000000000.000000000000000 + + + 1.000000000000000 + + + 1.000000000000000 + + + + + + + unspecified + + + + + + + + + + true + + + + 100 + 20 + + + + Imaginary part of potential x-component Note: has no effect if a solid was selected - - - true - - - V - - - -1000000000000000000000.000000000000000 - - - 1000000000000000000000.000000000000000 - - - 1.000000000000000 - - - 1.000000000000000 - - - - - - - unspecified - - - - - - - - - - true - - - y - - - - - - - true - - - - 100 - 20 - - - - Real part of potential y-component + + + true + + + V + + + -1000000000000000000000.000000000000000 + + + 1000000000000000000000.000000000000000 + + + 1.000000000000000 + + + 1.000000000000000 + + + + + + + unspecified + + + + + + + + + + true + + + y + + + + + + + true + + + + 100 + 20 + + + + Real part of potential y-component Note: has no effect if a solid was selected - - - true - - - V - - - -1000000000000000000000.000000000000000 - - - 1000000000000000000000.000000000000000 - - - 1.000000000000000 - - - 1.000000000000000 - - - - - - - unspecified - - - - - - - - - - true - - - - 100 - 20 - - - - Imaginary part of potential y-component + + + true + + + V + + + -1000000000000000000000.000000000000000 + + + 1000000000000000000000.000000000000000 + + + 1.000000000000000 + + + 1.000000000000000 + + + + + + + unspecified + + + + + + + + + + true + + + + 100 + 20 + + + + Imaginary part of potential y-component Note: has no effect if a solid was selected - - - true - - - V - - - -1000000000000000000000.000000000000000 - - - 1000000000000000000000.000000000000000 - - - 1.000000000000000 - - - 1.000000000000000 - - - - - - - unspecified - - - - - - - - - - true - - - z - - - - - - - true - - - - 100 - 20 - - - - Real part of potential z-component + + + true + + + V + + + -1000000000000000000000.000000000000000 + + + 1000000000000000000000.000000000000000 + + + 1.000000000000000 + + + 1.000000000000000 + + + + + + + unspecified + + + + + + + + + + true + + + z + + + + + + + true + + + + 100 + 20 + + + + Real part of potential z-component Note: has no effect if a solid was selected - - - true - - - V - - - -1000000000000000000000.000000000000000 - - - 1000000000000000000000.000000000000000 - - - 1.000000000000000 - - - 1.000000000000000 - - - - - - - unspecified - - - - - - - - - - true - - - - 100 - 20 - - - - Imaginary part of potential z-component + + + true + + + V + + + -1000000000000000000000.000000000000000 + + + 1000000000000000000000.000000000000000 + + + 1.000000000000000 + + + 1.000000000000000 + + + + + + + unspecified + + + + + + + + + + true + + + + 100 + 20 + + + + Imaginary part of potential z-component Note: has no effect if a solid was selected + + + true + + + V + + + -1000000000000000000000.000000000000000 + + + 1000000000000000000000.000000000000000 + + + 1.000000000000000 + + + 1.000000000000000 + + + + + + + unspecified + + + + + + + + + + + + + + + Capacitance Body: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + unspecified + + + true + + + + + + + + 55 + 16777215 + + + + Counter of the body (or face) with a capacitance + + + 1 + + + 1 + + + + + + + + + To define a vector field - + + Vector Field + + true - - V - - - -1000000000000000000000.000000000000000 - - - 1000000000000000000000.000000000000000 - - - 1.000000000000000 - - - 1.000000000000000 - - - + + - unspecified + Whether the boundary condition is for the electric force - + Calculate Electric Force - - - - Whether the boundary condition defines a constant potential + + + + - - Potential Constant + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Surface Charge Density: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Surface Charge density + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + - - - - true - - - Whether the boundary condition defines a farfield potential - - - Farfield / Electric infinity - - - - - - - Whether the boundary condition is for the electric force - - - Calculate Electric Force - - - - - - - - - Capacity Body: - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - unspecified - - - true - - - - - - - - 55 - 16777215 - - - - Counter of the body (or face) with a capacitance - - - 1 - - - 1 - - - - - @@ -783,4 +871,7 @@ Note: has no effect if a solid was selected + + + diff --git a/src/Mod/Fem/femobjects/constraint_electrostaticpotential.py b/src/Mod/Fem/femobjects/constraint_electrostaticpotential.py index e3e9554531..749d12cf62 100644 --- a/src/Mod/Fem/femobjects/constraint_electrostaticpotential.py +++ b/src/Mod/Fem/femobjects/constraint_electrostaticpotential.py @@ -195,3 +195,23 @@ class ConstraintElectrostaticPotential(base_fempythonobject.BaseFemPythonObject) ) obj.setPropertyStatus("CapacitanceBodyEnabled", "LockDynamic") obj.CapacitanceBodyEnabled = False + + if not hasattr(obj, "SurfaceChargeDensity"): + obj.addProperty( + "App::PropertySurfaceChargeDensity", + "SurfaceChargeDensity", + "Parameter", + "(free) Surface Charge Density", + ) + obj.setPropertyStatus("SurfaceChargeDensity", "LockDynamic") + obj.SurfaceChargeDensity = "0.0 s*A/mm^2" + + if not hasattr(obj, "Dirichlet"): + obj.addProperty( + "App::PropertyBool", + "Dirichlet", + "Parameter", + "Dirichlet (true) or Neumann (false) type BC", + ) + obj.setPropertyStatus("Dirichlet", "LockDynamic") + obj.Dirichlet = True diff --git a/src/Mod/Fem/femsolver/elmer/equations/electrostatic_writer.py b/src/Mod/Fem/femsolver/elmer/equations/electrostatic_writer.py index 5014df97ff..1751c9b78b 100644 --- a/src/Mod/Fem/femsolver/elmer/equations/electrostatic_writer.py +++ b/src/Mod/Fem/femsolver/elmer/equations/electrostatic_writer.py @@ -125,22 +125,26 @@ 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.Dirichlet: + 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) + elif not obj.Dirichlet and hasattr(obj, "SurfaceChargeDensity"): + sc_density = float(obj.SurfaceChargeDensity.getValueAs("A*s/m^2")) + self.write.boundary(name, "Surface Charge Density", sc_density) if obj.PotentialConstant: self.write.boundary(name, "Potential Constant", True) if obj.ElectricInfinity: diff --git a/src/Mod/Fem/femtaskpanels/task_constraint_electrostaticpotential.py b/src/Mod/Fem/femtaskpanels/task_constraint_electrostaticpotential.py index da268a8b3b..f7a7e12f26 100644 --- a/src/Mod/Fem/femtaskpanels/task_constraint_electrostaticpotential.py +++ b/src/Mod/Fem/femtaskpanels/task_constraint_electrostaticpotential.py @@ -24,7 +24,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" __url__ = "https://www.freecad.org" ## @package task_constraint_electrostaticpotential @@ -88,6 +88,13 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel): self._vectorField_visibility, ) + def _BCtype_clicked(self, button): + self._BCtype(button == self._paramWidget.dirichletBC_RB) + + def _BCtype(self, isDirichlet): + self._paramWidget.neumannGB.setEnabled(not isDirichlet) + self._paramWidget.dirichletGB.setEnabled(isDirichlet) + def _vectorField_visibility(self, visible): self._paramWidget.vectorFieldGB.setVisible(visible) @@ -166,6 +173,20 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel): not self._paramWidget.capacitanceBodyBox.isChecked() ) + # neumann/dirichlet radiogroup selection + self._paramWidget.BCtypeBG.buttonClicked.connect(self._BCtype_clicked) + if self.obj.Dirichlet: + self._paramWidget.dirichletBC_RB.click() + else: + self._paramWidget.neumannBC_RB.click() + + self._paramWidget.surfacechargedensityQSB.setProperty( + "value", self.obj.SurfaceChargeDensity + ) + FreeCADGui.ExpressionBinding(self._paramWidget.surfacechargedensityQSB).bind( + self.obj, "SurfaceChargeDensity" + ) + def _applyPotentialChanges(self, enabledBox, potentialQSB): enabled = enabledBox.isChecked() potential = None @@ -219,3 +240,18 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel): if self.obj.CapacitanceBodyEnabled: self._paramWidget.capacitanceBody_spinBox.setEnabled(True) self.obj.CapacitanceBody = self._paramWidget.capacitanceBody_spinBox.value() + + self.obj.Dirichlet = self._paramWidget.dirichletBC_RB.isChecked() + + try: + self.obj.SurfaceChargeDensity = self._paramWidget.surfacechargedensityQSB.property( + "value" + ) + except ValueError: + FreeCAD.Console.PrintMessage( + "Wrong input. Not recognised input: '{}' " + "SurfaceChargeDensity has not been set.\n".format( + self._paramWidget.surfacechargedensityQSB.text() + ) + ) + self.obj.SurfaceChargeDensity = "0.0 s*A/(mm^2)" From 30c7efbc60f356eca100710b9799815d20011a92 Mon Sep 17 00:00:00 2001 From: marioalexis Date: Sun, 12 Jan 2025 10:17:56 -0300 Subject: [PATCH 3/5] Fem: Fix vector potential unit and use enumeration property for boundary condition --- .../Resources/ui/ElectrostaticPotential.ui | 675 +++++------------- .../constraint_electrostaticpotential.py | 414 ++++++----- .../elmer/equations/electrostatic_writer.py | 32 +- .../task_constraint_electrostaticpotential.py | 435 ++++++++--- 4 files changed, 766 insertions(+), 790 deletions(-) diff --git a/src/Mod/Fem/Gui/Resources/ui/ElectrostaticPotential.ui b/src/Mod/Fem/Gui/Resources/ui/ElectrostaticPotential.ui index fd83f7d508..de85084c5d 100644 --- a/src/Mod/Fem/Gui/Resources/ui/ElectrostaticPotential.ui +++ b/src/Mod/Fem/Gui/Resources/ui/ElectrostaticPotential.ui @@ -13,56 +13,46 @@ Analysis feature properties - - - - - Dirichlet + + + + + - - true - - - BCtypeBG - - - - - - - Neumann - - - BCtypeBG - + + + + + Boundary Condition: + + + + + + + - + - + Dirichlet false - - - - true - - - Whether the boundary condition defines a farfield potential - - - Farfield / Electric infinity - - - - - + + + + Potential: + + + + + false @@ -73,13 +63,7 @@ true - - - - -1000000000000000000000.000000000000000 - - - 1000000000000000000000.000000000000000 + V 1.000000000000000 @@ -89,45 +73,18 @@ - - - - Potential: - - - - - - - unspecified - - - true - - - - - - - Qt::Horizontal - - - - 20 - 20 - - - - - - + + - Whether the boundary condition defines a constant potential + To define scalar potential and magnetic vector potential - Potential Constant + Electromagnetic Potential + + + true @@ -147,7 +104,7 @@ with a harmonic/oscillating driving force false - + true @@ -157,7 +114,7 @@ with a harmonic/oscillating driving force - + true @@ -178,16 +135,20 @@ with a harmonic/oscillating driving force - + + + unspecified + + + + + + + + false - - - 100 - 20 - - Potential as specified above @@ -200,12 +161,6 @@ with a harmonic/oscillating driving force V - - -1000000000000000000000.000000000000000 - - - 1000000000000000000000.000000000000000 - 1.000000000000000 @@ -215,16 +170,20 @@ with a harmonic/oscillating driving force - + + + unspecified + + + + + + + + true - - - 100 - 20 - - Imaginary part of scalar potential @@ -234,12 +193,6 @@ with a harmonic/oscillating driving force V - - -1000000000000000000000.000000000000000 - - - 1000000000000000000000.000000000000000 - 1.000000000000000 @@ -248,16 +201,6 @@ with a harmonic/oscillating driving force - - - - unspecified - - - - - - @@ -269,16 +212,20 @@ with a harmonic/oscillating driving force - + + + unspecified + + + + + + + + true - - - 100 - 20 - - Real part of potential x-component Note: has no effect if a solid was selected @@ -287,13 +234,7 @@ Note: has no effect if a solid was selected true - V - - - -1000000000000000000000.000000000000000 - - - 1000000000000000000000.000000000000000 + Wb/m 1.000000000000000 @@ -303,8 +244,8 @@ Note: has no effect if a solid was selected - - + + unspecified @@ -313,17 +254,11 @@ Note: has no effect if a solid was selected - - + + true - - - 100 - 20 - - Imaginary part of potential x-component Note: has no effect if a solid was selected @@ -332,13 +267,7 @@ Note: has no effect if a solid was selected true - V - - - -1000000000000000000000.000000000000000 - - - 1000000000000000000000.000000000000000 + Wb/m 1.000000000000000 @@ -348,16 +277,6 @@ Note: has no effect if a solid was selected - - - - unspecified - - - - - - @@ -369,16 +288,20 @@ Note: has no effect if a solid was selected - + + + unspecified + + + + + + + + true - - - 100 - 20 - - Real part of potential y-component Note: has no effect if a solid was selected @@ -387,13 +310,7 @@ Note: has no effect if a solid was selected true - V - - - -1000000000000000000000.000000000000000 - - - 1000000000000000000000.000000000000000 + Wb/m 1.000000000000000 @@ -403,8 +320,8 @@ Note: has no effect if a solid was selected - - + + unspecified @@ -413,17 +330,11 @@ Note: has no effect if a solid was selected - - + + true - - - 100 - 20 - - Imaginary part of potential y-component Note: has no effect if a solid was selected @@ -432,13 +343,7 @@ Note: has no effect if a solid was selected true - V - - - -1000000000000000000000.000000000000000 - - - 1000000000000000000000.000000000000000 + Wb/m 1.000000000000000 @@ -448,16 +353,6 @@ Note: has no effect if a solid was selected - - - - unspecified - - - - - - @@ -469,16 +364,20 @@ Note: has no effect if a solid was selected - + + + unspecified + + + + + + + + true - - - 100 - 20 - - Real part of potential z-component Note: has no effect if a solid was selected @@ -487,13 +386,7 @@ Note: has no effect if a solid was selected true - V - - - -1000000000000000000000.000000000000000 - - - 1000000000000000000000.000000000000000 + Wb/m 1.000000000000000 @@ -503,8 +396,8 @@ Note: has no effect if a solid was selected - - + + unspecified @@ -513,17 +406,11 @@ Note: has no effect if a solid was selected - - + + true - - - 100 - 20 - - Imaginary part of potential z-component Note: has no effect if a solid was selected @@ -532,13 +419,7 @@ Note: has no effect if a solid was selected true - V - - - -1000000000000000000000.000000000000000 - - - 1000000000000000000000.000000000000000 + Wb/m 1.000000000000000 @@ -548,62 +429,62 @@ Note: has no effect if a solid was selected - - - - unspecified - - - - - - + + + + true + + + Whether the boundary condition defines a farfield potential + + + Farfield / Electric infinity + + + + + + + Whether the boundary condition defines a constant potential + + + Potential Constant + + + + + + + Whether the boundary condition is for the electric force + + + Calculate Electric Force + + + - + - Capacitance Body: + Capacitance Body: + + + Enabled by 'Calculate Capacity Matrix' in Electrostatic equation - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - unspecified - - - true - - - - - - - - 55 - 16777215 - - + Counter of the body (or face) with a capacitance + + false + 1 @@ -614,87 +495,31 @@ Note: has no effect if a solid was selected - - - - To define a vector field - - - Vector Field - - - true - - - - - - - Whether the boundary condition is for the electric force - - - Calculate Electric Force - - - - - + + - + Neumann - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - + - - - - - Surface Charge Density: - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Surface Charge density - - - - - - - + + + Surface Charge Density: + + - - - - Qt::Vertical + + + + Surface charge density - - - 20 - 40 - + + C/m^2 - + @@ -709,168 +534,6 @@ Note: has no effect if a solid was selected - - - capacitanceBodyBox - toggled(bool) - capacitanceBody_spinBox - setDisabled(bool) - - - 262 - 116 - - - 323 - 116 - - - - - potentialBox - toggled(bool) - potentialQSB - setDisabled(bool) - - - 301 - 19 - - - 206 - 19 - - - - - potentialQSB - valueChanged(Base::Quantity) - realScalarQSB - setValue(Base::Quantity) - - - 126 - 19 - - - 103 - 98 - - - - - reZunspecBox - toggled(bool) - realZQSB - setDisabled(bool) - - - 179 - 178 - - - 103 - 176 - - - - - reYunspecBox - toggled(bool) - realYQSB - setDisabled(bool) - - - 179 - 148 - - - 103 - 150 - - - - - imXunspecBox - toggled(bool) - imagXQSB - setDisabled(bool) - - - 339 - 128 - - - 258 - 127 - - - - - reXunspecBox - toggled(bool) - realXQSB - setDisabled(bool) - - - 179 - 128 - - - 103 - 124 - - - - - imZunspecBox - toggled(bool) - imagZQSB - setDisabled(bool) - - - 339 - 178 - - - 258 - 179 - - - - - imYunspecBox - toggled(bool) - imagYQSB - setDisabled(bool) - - - 339 - 148 - - - 258 - 153 - - - - - imScalarunspecBox - toggled(bool) - imagScalarQSB - setDisabled(bool) - - - 339 - 98 - - - 258 - 101 - - - - diff --git a/src/Mod/Fem/femobjects/constraint_electrostaticpotential.py b/src/Mod/Fem/femobjects/constraint_electrostaticpotential.py index 749d12cf62..f1e7f595ec 100644 --- a/src/Mod/Fem/femobjects/constraint_electrostaticpotential.py +++ b/src/Mod/Fem/femobjects/constraint_electrostaticpotential.py @@ -2,6 +2,7 @@ # * Copyright (c) 2017 Markus Hovorka * # * Copyright (c) 2020 Bernd Hahnebach * # * Copyright (c) 2023 Uwe Stöhr * +# * Copyright (c) 2024 Mario Passaglia * # * * # * This file is part of the FreeCAD CAx development system. * # * * @@ -24,7 +25,7 @@ # *************************************************************************** __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 @@ -33,6 +34,8 @@ __url__ = "https://www.freecad.org" from . import base_fempythonobject +_PropHelper = base_fempythonobject._PropHelper + class ConstraintElectrostaticPotential(base_fempythonobject.BaseFemPythonObject): @@ -40,178 +43,243 @@ 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::PropertyElectromagneticPotential", + name="AV_re_1", + group="Vector Potential", + doc="Real part of potential x-component", + value="0 Wb/m", + ) + ) + prop.append( + _PropHelper( + type="App::PropertyElectromagneticPotential", + name="AV_re_2", + group="Vector Potential", + doc="Real part of potential y-component", + value="0 Wb/m", + ) + ) + prop.append( + _PropHelper( + type="App::PropertyElectromagneticPotential", + name="AV_re_3", + group="Vector Potential", + doc="Real part of potential z-component", + value="0 Wb/m", + ) + ) + prop.append( + _PropHelper( + type="App::PropertyElectromagneticPotential", + name="AV_im_1", + group="Vector Potential", + doc="Imaginary part of potential x-component", + value="0 Wb/m", + ) + ) + prop.append( + _PropHelper( + type="App::PropertyElectromagneticPotential", + name="AV_im_2", + group="Vector Potential", + doc="Imaginary part of potential y-component", + value="0 Wb/m", + ) + ) + prop.append( + _PropHelper( + type="App::PropertyElectromagneticPotential", + name="AV_im_3", + group="Vector Potential", + doc="Imaginary part of 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::PropertyElectricPotential", + name="AV_im", + group="Parameter", + doc="Imaginary part of scalar potential", + value="0 V", + ) + ) + prop.append( + _PropHelper( + type="App::PropertyBool", + name="AV_re_1_Disabled", + group="Vector Potential", + doc="", + value=True, + ) + ) + prop.append( + _PropHelper( + type="App::PropertyBool", + name="AV_re_2_Disabled", + group="Vector Potential", + doc="", + value=True, + ) + ) + prop.append( + _PropHelper( + type="App::PropertyBool", + name="AV_re_3_Disabled", + group="Vector Potential", + doc="", + value=True, + ) + ) + prop.append( + _PropHelper( + type="App::PropertyBool", + name="AV_im_1_Disabled", + group="Vector Potential", + doc="", + value=True, + ) + ) + prop.append( + _PropHelper( + type="App::PropertyBool", + name="AV_im_2_Disabled", + group="Vector Potential", + doc="", + value=True, + ) + ) + prop.append( + _PropHelper( + type="App::PropertyBool", + name="AV_im_3_Disabled", + group="Vector Potential", + doc="", + value=True, + ) + ) + prop.append( + _PropHelper( + type="App::PropertyBool", + name="AV_im_Disabled", + group="Vector Potential", + doc="", + value=True, + ) + ) + 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" - - 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" - - # 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 - - 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 - - if not hasattr(obj, "SurfaceChargeDensity"): - obj.addProperty( - "App::PropertySurfaceChargeDensity", - "SurfaceChargeDensity", - "Parameter", - "(free) Surface Charge Density", - ) - obj.setPropertyStatus("SurfaceChargeDensity", "LockDynamic") - obj.SurfaceChargeDensity = "0.0 s*A/mm^2" - - if not hasattr(obj, "Dirichlet"): - obj.addProperty( - "App::PropertyBool", - "Dirichlet", - "Parameter", - "Dirichlet (true) or Neumann (false) type BC", - ) - obj.setPropertyStatus("Dirichlet", "LockDynamic") - obj.Dirichlet = True + # 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), + ) diff --git a/src/Mod/Fem/femsolver/elmer/equations/electrostatic_writer.py b/src/Mod/Fem/femsolver/elmer/equations/electrostatic_writer.py index 1751c9b78b..6ffba76461 100644 --- a/src/Mod/Fem/femsolver/elmer/equations/electrostatic_writer.py +++ b/src/Mod/Fem/femsolver/elmer/equations/electrostatic_writer.py @@ -125,26 +125,17 @@ class ESwriter: # output the FreeCAD label as comment if obj.Label: self.write.boundary(name, "! FreeCAD Name", obj.Label) - if obj.Dirichlet: + if obj.BoundaryCondition == "Dirichlet": 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) - elif not obj.Dirichlet and hasattr(obj, "SurfaceChargeDensity"): - sc_density = float(obj.SurfaceChargeDensity.getValueAs("A*s/m^2")) - self.write.boundary(name, "Surface Charge Density", sc_density) + 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: @@ -152,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) diff --git a/src/Mod/Fem/femtaskpanels/task_constraint_electrostaticpotential.py b/src/Mod/Fem/femtaskpanels/task_constraint_electrostaticpotential.py index f7a7e12f26..33a17dcff2 100644 --- a/src/Mod/Fem/femtaskpanels/task_constraint_electrostaticpotential.py +++ b/src/Mod/Fem/femtaskpanels/task_constraint_electrostaticpotential.py @@ -2,6 +2,7 @@ # * Copyright (c) 2017 Markus Hovorka * # * Copyright (c) 2020 Bernd Hahnebach * # * Copyright (c) 2023 Uwe Stöhr * +# * Copyright (c) 2024 Mario Passaglia * # * * # * 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, André Kapelrud" +__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 @@ -81,22 +81,138 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel): and self.obj.AV_im_3_Disabled ): self._vectorField_visibility(False) - self._paramWidget.vectorFieldBox.setChecked(False) + self.parameter_widget.vectorFieldBox.setChecked(False) + QtCore.QObject.connect( - self._paramWidget.vectorFieldBox, + self.parameter_widget.vectorFieldBox, QtCore.SIGNAL("toggled(bool)"), self._vectorField_visibility, ) + 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_re, + QtCore.SIGNAL("toggled(bool)"), + self.av_re_enabled_changed, + ) + QtCore.QObject.connect( + self.parameter_widget.ckb_av_re_1, + QtCore.SIGNAL("toggled(bool)"), + self.av_re_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_re_2, + QtCore.SIGNAL("toggled(bool)"), + self.av_re_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_re_3, + QtCore.SIGNAL("toggled(bool)"), + self.av_re_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.ckb_av_im, + QtCore.SIGNAL("toggled(bool)"), + self.av_im_enabled_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.ckb_av_im_1, + QtCore.SIGNAL("toggled(bool)"), + self.av_im_1_enabled_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.ckb_av_im_2, + QtCore.SIGNAL("toggled(bool)"), + self.av_im_2_enabled_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.ckb_av_im_3, + QtCore.SIGNAL("toggled(bool)"), + self.av_im_3_enabled_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.ckb_electric_forcecalculation, + QtCore.SIGNAL("toggled(bool)"), + self.electric_forcecalculation_changed, + ) + QtCore.QObject.connect( + self.parameter_widget.qsb_surface_charge_density, + QtCore.SIGNAL("valueChanged(Base::Quantity)"), + self.surface_charge_density_changed, + ) - def _BCtype_clicked(self, button): - self._BCtype(button == self._paramWidget.dirichletBC_RB) - - def _BCtype(self, isDirichlet): - self._paramWidget.neumannGB.setEnabled(not isDirichlet) - self._paramWidget.dirichletGB.setEnabled(isDirichlet) + self.init_parameter_widget() def _vectorField_visibility(self, visible): - self._paramWidget.vectorFieldGB.setVisible(visible) + self.parameter_widget.vectorFieldGB.setVisible(visible) def open(self): if self._mesh is not None and self._part is not None: @@ -113,7 +229,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() @@ -129,64 +245,222 @@ 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 + + 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.av_re_enabled = not self.obj.PotentialEnabled + self.av_re_1_enabled = not self.obj.AV_re_1_Disabled + self.av_re_2_enabled = not self.obj.AV_re_2_Disabled + self.av_re_3_enabled = not self.obj.AV_re_3_Disabled + self.av_im_enabled = not self.obj.AV_im_Disabled + self.av_im_1_enabled = not self.obj.AV_im_1_Disabled + self.av_im_2_enabled = not self.obj.AV_im_2_Disabled + self.av_im_3_enabled = not self.obj.AV_im_3_Disabled + + self.boundary_condition = self.obj.BoundaryCondition + self.potential_constant = self.obj.PotentialConstant + self.electric_infinity = self.obj.ElectricInfinity + self.electric_forcecalculation = self.obj.ElectricForcecalculation + self.capacitance_body_enabled = self.obj.CapacitanceBodyEnabled + self.capacitance_body = self.obj.CapacitanceBody + + self.surface_charge_density = self.obj.SurfaceChargeDensity + + def _set_params(self): + self.obj.Potential = self.potential + self.obj.PotentialEnabled = self.potential_enabled + + 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.obj.AV_re_1_Disabled = not self.av_re_1_enabled + self.obj.AV_re_2_Disabled = not self.av_re_2_enabled + self.obj.AV_re_3_Disabled = not self.av_re_3_enabled + self.obj.AV_im_Disabled = not self.av_im_enabled + self.obj.AV_im_1_Disabled = not self.av_im_1_enabled + self.obj.AV_im_2_Disabled = not self.av_im_2_enabled + self.obj.AV_im_3_Disabled = not self.av_im_3_enabled + + self.obj.BoundaryCondition = self.boundary_condition + self.obj.PotentialConstant = self.potential_constant + self.obj.ElectricInfinity = self.electric_infinity + self.obj.ElectricForcecalculation = self.electric_forcecalculation + 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) # 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.parameter_widget.qsb_av_re.setProperty("value", self.potential) + self.parameter_widget.qsb_av_re.setEnabled(self.av_re_enabled) + FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_av_re).bind(self.obj, "Potential") - 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.parameter_widget.qsb_av_re_1.setProperty("value", self.av_re_1) + self.parameter_widget.qsb_av_re_1.setEnabled(self.av_re_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_re_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_re_3_enabled) + FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_av_re_3).bind(self.obj, "AV_re_3") + self.parameter_widget.qsb_av_im.setProperty("value", self.av_im) + self.parameter_widget.qsb_av_im.setEnabled(self.av_im_enabled) + FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_av_im).bind(self.obj, "AV_im") + self.parameter_widget.qsb_av_im_1.setProperty("value", self.av_im_1) + self.parameter_widget.qsb_av_im_1.setEnabled(self.av_im_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_im_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_im_3_enabled) + FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_av_im_3).bind(self.obj, "AV_im_3") - self._paramWidget.potentialConstantBox.setChecked(self.obj.PotentialConstant) + self.parameter_widget.ckb_av_re_1.setChecked(self.av_re_1_enabled) + self.parameter_widget.ckb_av_re_2.setChecked(self.av_re_2_enabled) + self.parameter_widget.ckb_av_re_3.setChecked(self.av_re_3_enabled) + self.parameter_widget.ckb_av_im.setChecked(self.av_im_enabled) + self.parameter_widget.ckb_av_im_1.setChecked(self.av_im_1_enabled) + self.parameter_widget.ckb_av_im_2.setChecked(self.av_im_2_enabled) + self.parameter_widget.ckb_av_im_3.setChecked(self.av_im_3_enabled) - self._paramWidget.electricInfinityBox.setChecked(self.obj.ElectricInfinity) + self.parameter_widget.ckb_potential_constant.setChecked(self.potential_constant) - self._paramWidget.electricForcecalculationBox.setChecked(self.obj.ElectricForcecalculation) + self.parameter_widget.ckb_electric_infinity.setChecked(self.electric_infinity) - 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.parameter_widget.ckb_electric_forcecalculation.setChecked( + self.electric_forcecalculation ) - # neumann/dirichlet radiogroup selection - self._paramWidget.BCtypeBG.buttonClicked.connect(self._BCtype_clicked) - if self.obj.Dirichlet: - self._paramWidget.dirichletBC_RB.click() - else: - self._paramWidget.neumannBC_RB.click() + self.parameter_widget.ckb_capacitance_body.setChecked(self.capacitance_body_enabled) + self.parameter_widget.spb_capacitance_body.setValue(self.capacitance_body) - self._paramWidget.surfacechargedensityQSB.setProperty( - "value", self.obj.SurfaceChargeDensity + self.parameter_widget.qsb_surface_charge_density.setProperty( + "value", self.surface_charge_density ) - FreeCADGui.ExpressionBinding(self._paramWidget.surfacechargedensityQSB).bind( + FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_surface_charge_density).bind( self.obj, "SurfaceChargeDensity" ) + self.bc_enum = self.obj.getEnumerationsOfProperty("BoundaryCondition") + self.parameter_widget.cb_boundary_condition.addItems(self.bc_enum) + index = self.bc_enum.index(self.boundary_condition) + self.parameter_widget.cb_boundary_condition.setCurrentIndex(index) + self.boundary_condition_changed(index) + + def potential_changed(self, value): + self.potential = value + + def potential_enabled_changed(self, value): + self.potential_enabled = value + self.parameter_widget.qsb_potential.setEnabled(value) + + def av_re_enabled_changed(self, value): + self.av_re_enabled = value + self.parameter_widget.qsb_av_re.setEnabled(value) + + def av_re_1_enabled_changed(self, value): + self.av_re_1_enabled = value + self.parameter_widget.qsb_av_re_1.setEnabled(value) + + def av_re_2_enabled_changed(self, value): + self.av_re_2_enabled = value + self.parameter_widget.qsb_av_re_2.setEnabled(value) + + def av_re_3_enabled_changed(self, value): + self.av_re_3_enabled = value + self.parameter_widget.qsb_av_re_3.setEnabled(value) + + def av_im_enabled_changed(self, value): + self.av_im_enabled = value + self.parameter_widget.qsb_av_im.setEnabled(value) + + def av_im_1_enabled_changed(self, value): + self.av_im_1_enabled = value + self.parameter_widget.qsb_av_im_1.setEnabled(value) + + def av_im_2_enabled_changed(self, value): + self.av_im_2_enabled = value + self.parameter_widget.qsb_av_im_2.setEnabled(value) + + def av_im_3_enabled_changed(self, value): + self.av_im_3_enabled = value + self.parameter_widget.qsb_av_im_3.setEnabled(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 electric_forcecalculation_changed(self, value): + self.electric_forcecalculation = 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) + def _applyPotentialChanges(self, enabledBox, potentialQSB): enabled = enabledBox.isChecked() potential = None @@ -202,56 +476,37 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel): 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.parameter_widget.reXunspecBox, self.parameter_widget.realXQSB ) self.obj.AV_re_2_Disabled, self.obj.AV_re_2 = self._applyPotentialChanges( - self._paramWidget.reYunspecBox, self._paramWidget.realYQSB + self.parameter_widget.reYunspecBox, self.parameter_widget.realYQSB ) self.obj.AV_re_3_Disabled, self.obj.AV_re_3 = self._applyPotentialChanges( - self._paramWidget.reZunspecBox, self._paramWidget.realZQSB + self.parameter_widget.reZunspecBox, self.parameter_widget.realZQSB ) self.obj.AV_im_Disabled, self.obj.AV_im = self._applyPotentialChanges( - self._paramWidget.imScalarunspecBox, self._paramWidget.imagScalarQSB + self.parameter_widget.imScalarunspecBox, self.parameter_widget.imagScalarQSB ) self.obj.AV_im_1_Disabled, self.obj.AV_im_1 = self._applyPotentialChanges( - self._paramWidget.imXunspecBox, self._paramWidget.imagXQSB + self.parameter_widget.imXunspecBox, self.parameter_widget.imagXQSB ) self.obj.AV_im_2_Disabled, self.obj.AV_im_2 = self._applyPotentialChanges( - self._paramWidget.imYunspecBox, self._paramWidget.imagYQSB + self.parameter_widget.imYunspecBox, self.parameter_widget.imagYQSB ) self.obj.AV_im_3_Disabled, self.obj.AV_im_3 = self._applyPotentialChanges( - self._paramWidget.imZunspecBox, self._paramWidget.imagZQSB + self.parameter_widget.imZunspecBox, self.parameter_widget.imagZQSB ) # because this is an enable the others are disabled, reverse self.obj.PotentialEnabled = not self.obj.PotentialEnabled - self.obj.PotentialConstant = self._paramWidget.potentialConstantBox.isChecked() + self.obj.PotentialConstant = self.parameter_widget.potentialConstantBox.isChecked() - self.obj.ElectricInfinity = self._paramWidget.electricInfinityBox.isChecked() + self.obj.ElectricInfinity = self.parameter_widget.electricInfinityBox.isChecked() - calc_is_checked = self._paramWidget.electricForcecalculationBox.isChecked() + calc_is_checked = self.parameter_widget.electricForcecalculationBox.isChecked() self.obj.ElectricForcecalculation = calc_is_checked # two lines because max line length - 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() - - self.obj.Dirichlet = self._paramWidget.dirichletBC_RB.isChecked() - - try: - self.obj.SurfaceChargeDensity = self._paramWidget.surfacechargedensityQSB.property( - "value" - ) - except ValueError: - FreeCAD.Console.PrintMessage( - "Wrong input. Not recognised input: '{}' " - "SurfaceChargeDensity has not been set.\n".format( - self._paramWidget.surfacechargedensityQSB.text() - ) - ) - self.obj.SurfaceChargeDensity = "0.0 s*A/(mm^2)" + self.obj.SurfaceChargeDensity = self.parameter_widget.surfacechargedensityQSB.property( + "value" + ) From 0194070ce93b57e596f273f02673309c97de9944 Mon Sep 17 00:00:00 2001 From: marioalexis Date: Mon, 20 Jan 2025 00:33:19 -0300 Subject: [PATCH 4/5] Fem: Update electromagnetics boundary conditions --- .../Resources/ui/ElectrostaticPotential.ui | 168 ++++++++---------- .../constraint_electrostaticpotential.py | 76 +++++--- .../elmer/equations/magnetodynamic_writer.py | 23 ++- .../task_constraint_electrostaticpotential.py | 141 +++++---------- 4 files changed, 176 insertions(+), 232 deletions(-) diff --git a/src/Mod/Fem/Gui/Resources/ui/ElectrostaticPotential.ui b/src/Mod/Fem/Gui/Resources/ui/ElectrostaticPotential.ui index de85084c5d..dedb7b97d3 100644 --- a/src/Mod/Fem/Gui/Resources/ui/ElectrostaticPotential.ui +++ b/src/Mod/Fem/Gui/Resources/ui/ElectrostaticPotential.ui @@ -14,12 +14,12 @@ Analysis feature properties - + - + @@ -41,9 +41,9 @@ false - - - + + + @@ -75,8 +75,8 @@ - - + + To define scalar potential and magnetic vector potential @@ -88,8 +88,11 @@ - - + + + + + true @@ -100,10 +103,7 @@ with a harmonic/oscillating driving force false - - false - - + @@ -136,9 +136,6 @@ with a harmonic/oscillating driving force - - unspecified - @@ -147,13 +144,10 @@ with a harmonic/oscillating driving force - false + true - Potential as specified above - - - true + Real part of scalar potential true @@ -171,9 +165,6 @@ with a harmonic/oscillating driving force - - unspecified - @@ -213,9 +204,6 @@ with a harmonic/oscillating driving force - - unspecified - @@ -246,9 +234,6 @@ Note: has no effect if a solid was selected - - unspecified - @@ -289,9 +274,6 @@ Note: has no effect if a solid was selected - - unspecified - @@ -322,9 +304,6 @@ Note: has no effect if a solid was selected - - unspecified - @@ -365,9 +344,6 @@ Note: has no effect if a solid was selected - - unspecified - @@ -398,9 +374,6 @@ Note: has no effect if a solid was selected - - unspecified - @@ -432,64 +405,28 @@ Note: has no effect if a solid was selected - - - - true - - - Whether the boundary condition defines a farfield potential - - - Farfield / Electric infinity - - - - - - - Whether the boundary condition defines a constant potential - - - Potential Constant - - - - - - - Whether the boundary condition is for the electric force - - - Calculate Electric Force - - - - - - - - - Capacitance Body: + + + + + + true - Enabled by 'Calculate Capacity Matrix' in Electrostatic equation + Whether the boundary condition defines a farfield potential + + + Electric Infinity - - + + - Counter of the body (or face) with a capacitance + Whether the boundary condition defines a constant potential - - false - - - 1 - - - 1 + + Potential Constant @@ -503,7 +440,7 @@ Note: has no effect if a solid was selected Neumann - + @@ -524,6 +461,41 @@ Note: has no effect if a solid was selected + + + + Capacitance + + + + + + Capacitance Body: + + + Enabled by 'Calculate Capacity Matrix' in Electrostatic equation + + + + + + + Counter of the body (or face) with a capacitance + + + false + + + 1 + + + 1 + + + + + + @@ -532,9 +504,11 @@ Note: has no effect if a solid was selected QWidget
Gui/QuantitySpinBox.h
+ + Gui::IntSpinBox + QWidget +
Gui/SpinBox.h
+
- - - diff --git a/src/Mod/Fem/femobjects/constraint_electrostaticpotential.py b/src/Mod/Fem/femobjects/constraint_electrostaticpotential.py index f1e7f595ec..f2d1d3381e 100644 --- a/src/Mod/Fem/femobjects/constraint_electrostaticpotential.py +++ b/src/Mod/Fem/femobjects/constraint_electrostaticpotential.py @@ -32,6 +32,8 @@ __url__ = "https://www.freecad.org" # \ingroup FEM # \brief constraint electrostatic potential object +from FreeCAD import Base + from . import base_fempythonobject _PropHelper = base_fempythonobject._PropHelper @@ -68,12 +70,30 @@ class ConstraintElectrostaticPotential(base_fempythonobject.BaseFemPythonObject) 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="Vector Potential", - doc="Real part of potential x-component", + group="Electromagnetic Potential", + doc="Real part of vector potential x-component", value="0 Wb/m", ) ) @@ -81,8 +101,8 @@ class ConstraintElectrostaticPotential(base_fempythonobject.BaseFemPythonObject) _PropHelper( type="App::PropertyElectromagneticPotential", name="AV_re_2", - group="Vector Potential", - doc="Real part of potential y-component", + group="Electromagnetic Potential", + doc="Real part of vector potential y-component", value="0 Wb/m", ) ) @@ -90,8 +110,8 @@ class ConstraintElectrostaticPotential(base_fempythonobject.BaseFemPythonObject) _PropHelper( type="App::PropertyElectromagneticPotential", name="AV_re_3", - group="Vector Potential", - doc="Real part of potential z-component", + group="Electromagnetic Potential", + doc="Real part of vector potential z-component", value="0 Wb/m", ) ) @@ -99,8 +119,8 @@ class ConstraintElectrostaticPotential(base_fempythonobject.BaseFemPythonObject) _PropHelper( type="App::PropertyElectromagneticPotential", name="AV_im_1", - group="Vector Potential", - doc="Imaginary part of potential x-component", + group="Electromagnetic Potential", + doc="Imaginary part of vector potential x-component", value="0 Wb/m", ) ) @@ -108,8 +128,8 @@ class ConstraintElectrostaticPotential(base_fempythonobject.BaseFemPythonObject) _PropHelper( type="App::PropertyElectromagneticPotential", name="AV_im_2", - group="Vector Potential", - doc="Imaginary part of potential y-component", + group="Electromagnetic Potential", + doc="Imaginary part of vector potential y-component", value="0 Wb/m", ) ) @@ -117,8 +137,8 @@ class ConstraintElectrostaticPotential(base_fempythonobject.BaseFemPythonObject) _PropHelper( type="App::PropertyElectromagneticPotential", name="AV_im_3", - group="Vector Potential", - doc="Imaginary part of potential z-component", + group="Electromagnetic Potential", + doc="Imaginary part of vector potential z-component", value="0 Wb/m", ) ) @@ -140,20 +160,11 @@ class ConstraintElectrostaticPotential(base_fempythonobject.BaseFemPythonObject) value=["Dirichlet", "Neumann"], ) ) - prop.append( - _PropHelper( - type="App::PropertyElectricPotential", - name="AV_im", - group="Parameter", - doc="Imaginary part of scalar potential", - value="0 V", - ) - ) prop.append( _PropHelper( type="App::PropertyBool", name="AV_re_1_Disabled", - group="Vector Potential", + group="Electromagnetic Potential", doc="", value=True, ) @@ -162,7 +173,7 @@ class ConstraintElectrostaticPotential(base_fempythonobject.BaseFemPythonObject) _PropHelper( type="App::PropertyBool", name="AV_re_2_Disabled", - group="Vector Potential", + group="Electromagnetic Potential", doc="", value=True, ) @@ -171,7 +182,7 @@ class ConstraintElectrostaticPotential(base_fempythonobject.BaseFemPythonObject) _PropHelper( type="App::PropertyBool", name="AV_re_3_Disabled", - group="Vector Potential", + group="Electromagnetic Potential", doc="", value=True, ) @@ -180,7 +191,7 @@ class ConstraintElectrostaticPotential(base_fempythonobject.BaseFemPythonObject) _PropHelper( type="App::PropertyBool", name="AV_im_1_Disabled", - group="Vector Potential", + group="Electromagnetic Potential", doc="", value=True, ) @@ -189,7 +200,7 @@ class ConstraintElectrostaticPotential(base_fempythonobject.BaseFemPythonObject) _PropHelper( type="App::PropertyBool", name="AV_im_2_Disabled", - group="Vector Potential", + group="Electromagnetic Potential", doc="", value=True, ) @@ -198,7 +209,16 @@ class ConstraintElectrostaticPotential(base_fempythonobject.BaseFemPythonObject) _PropHelper( type="App::PropertyBool", name="AV_im_3_Disabled", - group="Vector Potential", + group="Electromagnetic Potential", + doc="", + value=True, + ) + ) + prop.append( + _PropHelper( + type="App::PropertyBool", + name="AV_re_Disabled", + group="Electromagnetic Potential", doc="", value=True, ) @@ -207,7 +227,7 @@ class ConstraintElectrostaticPotential(base_fempythonobject.BaseFemPythonObject) _PropHelper( type="App::PropertyBool", name="AV_im_Disabled", - group="Vector Potential", + group="Electromagnetic Potential", doc="", value=True, ) diff --git a/src/Mod/Fem/femsolver/elmer/equations/magnetodynamic_writer.py b/src/Mod/Fem/femsolver/elmer/equations/magnetodynamic_writer.py index c67ddf22ba..7bcb968838 100644 --- a/src/Mod/Fem/femsolver/elmer/equations/magnetodynamic_writer.py +++ b/src/Mod/Fem/femsolver/elmer/equations/magnetodynamic_writer.py @@ -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 @@ -289,29 +290,27 @@ 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 not obj.AV_re_Disabled: + potential = obj.AV_re.getValueAs("V").Value if equation.IsHarmonic: self.write.boundary(name, "AV re", 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")) + potential = obj.AV_re_1.getValueAs("Wb/m").Value if equation.IsHarmonic: self.write.boundary(name, "AV re {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")) + potential = obj.AV_re_2.getValueAs("Wb/m").Value if equation.IsHarmonic: self.write.boundary(name, "AV re {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")) + potential = obj.AV_re_3.getValueAs("Wb/m").Value if equation.IsHarmonic: self.write.boundary(name, "AV re {e} 3", round(potential, 6)) else: @@ -319,16 +318,16 @@ class MgDynwriter: # imaginaries are only needed for harmonic equation if equation.IsHarmonic: if not obj.AV_im_Disabled: - potential = float(obj.AV_im.getValueAs("V")) + potential = obj.AV_im.getValueAs("V").Value self.write.boundary(name, "AV im", round(potential, 6)) if not obj.AV_im_1_Disabled: - potential = float(obj.AV_im_1.getValueAs("V")) + potential = obj.AV_im_1.getValueAs("Wb/m").Value 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")) + potential = obj.AV_im_2.getValueAs("Wb/m").Value 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")) + potential = obj.AV_im_3.getValueAs("Wb/m").Value self.write.boundary(name, "AV im {e} 3", round(potential, 6)) def handleMagnetodynamicBndConditions(self, equation): diff --git a/src/Mod/Fem/femtaskpanels/task_constraint_electrostaticpotential.py b/src/Mod/Fem/femtaskpanels/task_constraint_electrostaticpotential.py index 33a17dcff2..7cf8903cd6 100644 --- a/src/Mod/Fem/femtaskpanels/task_constraint_electrostaticpotential.py +++ b/src/Mod/Fem/femtaskpanels/task_constraint_electrostaticpotential.py @@ -70,23 +70,10 @@ 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.parameter_widget.vectorFieldBox.setChecked(False) - QtCore.QObject.connect( - self.parameter_widget.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, @@ -108,6 +95,11 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel): QtCore.SIGNAL("toggled(bool)"), self.av_re_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_re_1, QtCore.SIGNAL("toggled(bool)"), @@ -198,11 +190,6 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel): QtCore.SIGNAL("toggled(bool)"), self.electric_infinity_changed, ) - QtCore.QObject.connect( - self.parameter_widget.ckb_electric_forcecalculation, - QtCore.SIGNAL("toggled(bool)"), - self.electric_forcecalculation_changed, - ) QtCore.QObject.connect( self.parameter_widget.qsb_surface_charge_density, QtCore.SIGNAL("valueChanged(Base::Quantity)"), @@ -211,9 +198,6 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel): self.init_parameter_widget() - def _vectorField_visibility(self, visible): - self.parameter_widget.vectorFieldGB.setVisible(visible) - def open(self): if self._mesh is not None and self._part is not None: self._meshVisible = self._mesh.ViewObject.isVisible() @@ -249,6 +233,7 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel): self.potential = self.obj.Potential self.potential_enabled = self.obj.PotentialEnabled + 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 @@ -257,11 +242,11 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel): self.av_im_2 = self.obj.AV_im_2 self.av_im_3 = self.obj.AV_im_3 - self.av_re_enabled = not self.obj.PotentialEnabled + self.av_re_enabled = not self.obj.AV_re_Disabled + self.av_im_enabled = not self.obj.AV_im_Disabled self.av_re_1_enabled = not self.obj.AV_re_1_Disabled self.av_re_2_enabled = not self.obj.AV_re_2_Disabled self.av_re_3_enabled = not self.obj.AV_re_3_Disabled - self.av_im_enabled = not self.obj.AV_im_Disabled self.av_im_1_enabled = not self.obj.AV_im_1_Disabled self.av_im_2_enabled = not self.obj.AV_im_2_Disabled self.av_im_3_enabled = not self.obj.AV_im_3_Disabled @@ -269,16 +254,15 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel): self.boundary_condition = self.obj.BoundaryCondition self.potential_constant = self.obj.PotentialConstant self.electric_infinity = self.obj.ElectricInfinity - self.electric_forcecalculation = self.obj.ElectricForcecalculation self.capacitance_body_enabled = self.obj.CapacitanceBodyEnabled self.capacitance_body = self.obj.CapacitanceBody - self.surface_charge_density = self.obj.SurfaceChargeDensity def _set_params(self): self.obj.Potential = self.potential self.obj.PotentialEnabled = self.potential_enabled + 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 @@ -287,10 +271,11 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel): self.obj.AV_im_2 = self.av_im_2 self.obj.AV_im_3 = self.av_im_3 + self.obj.AV_re_Disabled = not self.av_re_enabled + self.obj.AV_im_Disabled = not self.av_im_enabled self.obj.AV_re_1_Disabled = not self.av_re_1_enabled self.obj.AV_re_2_Disabled = not self.av_re_2_enabled self.obj.AV_re_3_Disabled = not self.av_re_3_enabled - self.obj.AV_im_Disabled = not self.av_im_enabled self.obj.AV_im_1_Disabled = not self.av_im_1_enabled self.obj.AV_im_2_Disabled = not self.av_im_2_enabled self.obj.AV_im_3_Disabled = not self.av_im_3_enabled @@ -298,7 +283,6 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel): self.obj.BoundaryCondition = self.boundary_condition self.obj.PotentialConstant = self.potential_constant self.obj.ElectricInfinity = self.electric_infinity - self.obj.ElectricForcecalculation = self.electric_forcecalculation self.obj.CapacitanceBodyEnabled = self.capacitance_body_enabled self.obj.CapacitanceBody = self.capacitance_body @@ -313,11 +297,15 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel): ) self.parameter_widget.ckb_potential.setChecked(self.potential_enabled) - # the vector potentials - self.parameter_widget.qsb_av_re.setProperty("value", self.potential) + # scalar potential + self.parameter_widget.qsb_av_re.setProperty("value", self.av_re) self.parameter_widget.qsb_av_re.setEnabled(self.av_re_enabled) - FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_av_re).bind(self.obj, "Potential") + 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_im_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_re_1_enabled) FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_av_re_1).bind(self.obj, "AV_re_1") @@ -327,9 +315,7 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel): self.parameter_widget.qsb_av_re_3.setProperty("value", self.av_re_3) self.parameter_widget.qsb_av_re_3.setEnabled(self.av_re_3_enabled) FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_av_re_3).bind(self.obj, "AV_re_3") - self.parameter_widget.qsb_av_im.setProperty("value", self.av_im) - self.parameter_widget.qsb_av_im.setEnabled(self.av_im_enabled) - FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_av_im).bind(self.obj, "AV_im") + self.parameter_widget.qsb_av_im_1.setProperty("value", self.av_im_1) self.parameter_widget.qsb_av_im_1.setEnabled(self.av_im_1_enabled) FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_av_im_1).bind(self.obj, "AV_im_1") @@ -340,6 +326,7 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel): self.parameter_widget.qsb_av_im_3.setEnabled(self.av_im_3_enabled) FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_av_im_3).bind(self.obj, "AV_im_3") + self.parameter_widget.ckb_av_re.setChecked(self.av_re_enabled) self.parameter_widget.ckb_av_re_1.setChecked(self.av_re_1_enabled) self.parameter_widget.ckb_av_re_2.setChecked(self.av_re_2_enabled) self.parameter_widget.ckb_av_re_3.setChecked(self.av_re_3_enabled) @@ -352,12 +339,11 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel): self.parameter_widget.ckb_electric_infinity.setChecked(self.electric_infinity) - self.parameter_widget.ckb_electric_forcecalculation.setChecked( - self.electric_forcecalculation - ) - self.parameter_widget.ckb_capacitance_body.setChecked(self.capacitance_body_enabled) - self.parameter_widget.spb_capacitance_body.setValue(self.capacitance_body) + self.parameter_widget.spb_capacitance_body.setProperty("value", self.capacitance_body) + FreeCADGui.ExpressionBinding(self.parameter_widget.spb_capacitance_body).bind( + self.obj, "CapacitanceBody" + ) self.parameter_widget.qsb_surface_charge_density.setProperty( "value", self.surface_charge_density @@ -367,10 +353,22 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel): ) self.bc_enum = self.obj.getEnumerationsOfProperty("BoundaryCondition") - self.parameter_widget.cb_boundary_condition.addItems(self.bc_enum) 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.boundary_condition_changed(index) + + # start with electromagnetic inputs hidden if no field is set + if not ( + self.av_re_enabled + or self.av_im_enabled + or self.av_re_1_enabled + or self.av_re_2_enabled + or self.av_re_3_enabled + or self.av_im_1_enabled + or self.av_im_2_enabled + or self.av_im_3_enabled + ): + self.parameter_widget.ckb_electromagnetic.setChecked(False) def potential_changed(self, value): self.potential = value @@ -379,6 +377,9 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel): self.potential_enabled = value self.parameter_widget.qsb_potential.setEnabled(value) + def electromagnetic_enabled_changed(self, value): + self.parameter_widget.gb_electromagnetic.setVisible(value) + def av_re_enabled_changed(self, value): self.av_re_enabled = value self.parameter_widget.qsb_av_re.setEnabled(value) @@ -411,6 +412,9 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel): self.av_im_3_enabled = 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 @@ -438,9 +442,6 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel): def electric_infinity_changed(self, value): self.electric_infinity = value - def electric_forcecalculation_changed(self, value): - self.electric_forcecalculation = value - def capacitance_body_enabled_changed(self, value): self.capacitance_body_enabled = value self.parameter_widget.spb_capacitance_body.setEnabled(value) @@ -460,53 +461,3 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel): elif self.boundary_condition == "Neumann": self.parameter_widget.gb_neumann.setEnabled(True) self.parameter_widget.gb_dirichlet.setEnabled(False) - - 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 - - def _applyWidgetChanges(self): - # apply the voltages and their enabled state - self.obj.AV_re_1_Disabled, self.obj.AV_re_1 = self._applyPotentialChanges( - self.parameter_widget.reXunspecBox, self.parameter_widget.realXQSB - ) - self.obj.AV_re_2_Disabled, self.obj.AV_re_2 = self._applyPotentialChanges( - self.parameter_widget.reYunspecBox, self.parameter_widget.realYQSB - ) - self.obj.AV_re_3_Disabled, self.obj.AV_re_3 = self._applyPotentialChanges( - self.parameter_widget.reZunspecBox, self.parameter_widget.realZQSB - ) - self.obj.AV_im_Disabled, self.obj.AV_im = self._applyPotentialChanges( - self.parameter_widget.imScalarunspecBox, self.parameter_widget.imagScalarQSB - ) - self.obj.AV_im_1_Disabled, self.obj.AV_im_1 = self._applyPotentialChanges( - self.parameter_widget.imXunspecBox, self.parameter_widget.imagXQSB - ) - self.obj.AV_im_2_Disabled, self.obj.AV_im_2 = self._applyPotentialChanges( - self.parameter_widget.imYunspecBox, self.parameter_widget.imagYQSB - ) - self.obj.AV_im_3_Disabled, self.obj.AV_im_3 = self._applyPotentialChanges( - self.parameter_widget.imZunspecBox, self.parameter_widget.imagZQSB - ) - # because this is an enable the others are disabled, reverse - self.obj.PotentialEnabled = not self.obj.PotentialEnabled - - self.obj.PotentialConstant = self.parameter_widget.potentialConstantBox.isChecked() - - self.obj.ElectricInfinity = self.parameter_widget.electricInfinityBox.isChecked() - - calc_is_checked = self.parameter_widget.electricForcecalculationBox.isChecked() - self.obj.ElectricForcecalculation = calc_is_checked # two lines because max line length - - self.obj.SurfaceChargeDensity = self.parameter_widget.surfacechargedensityQSB.property( - "value" - ) From 0757a78cadab68f46ab3a95f870a9b01fdd25dc0 Mon Sep 17 00:00:00 2001 From: marioalexis Date: Tue, 21 Jan 2025 15:13:53 -0300 Subject: [PATCH 5/5] Fem: Rename enable/disable electromagnetic properties --- .../Resources/ui/ElectrostaticPotential.ui | 52 ++----- .../equation_magnetodynamics_elmer.py | 26 ++-- .../constraint_electrostaticpotential.py | 92 ++++++------ .../elmer/equations/magnetodynamic_writer.py | 39 ++--- .../task_constraint_electrostaticpotential.py | 133 ++++++------------ 5 files changed, 123 insertions(+), 219 deletions(-) diff --git a/src/Mod/Fem/Gui/Resources/ui/ElectrostaticPotential.ui b/src/Mod/Fem/Gui/Resources/ui/ElectrostaticPotential.ui index dedb7b97d3..3956a7e83d 100644 --- a/src/Mod/Fem/Gui/Resources/ui/ElectrostaticPotential.ui +++ b/src/Mod/Fem/Gui/Resources/ui/ElectrostaticPotential.ui @@ -103,7 +103,7 @@ with a harmonic/oscillating driving force false - + @@ -114,7 +114,7 @@ with a harmonic/oscillating driving force - + true @@ -135,7 +135,7 @@ with a harmonic/oscillating driving force - + @@ -164,13 +164,6 @@ with a harmonic/oscillating driving force - - - - - - - true @@ -203,7 +196,7 @@ with a harmonic/oscillating driving force - + @@ -215,7 +208,7 @@ with a harmonic/oscillating driving force true - Real part of potential x-component + Real part of vector potential x-component Note: has no effect if a solid was selected @@ -233,19 +226,12 @@ Note: has no effect if a solid was selected - - - - - - - true - Imaginary part of potential x-component + Imaginary part of vector potential x-component Note: has no effect if a solid was selected @@ -273,7 +259,7 @@ Note: has no effect if a solid was selected - + @@ -285,7 +271,7 @@ Note: has no effect if a solid was selected true - Real part of potential y-component + Real part of vector potential y-component Note: has no effect if a solid was selected @@ -303,19 +289,12 @@ Note: has no effect if a solid was selected - - - - - - - true - Imaginary part of potential y-component + Imaginary part of vector potential y-component Note: has no effect if a solid was selected @@ -343,7 +322,7 @@ Note: has no effect if a solid was selected - + @@ -355,7 +334,7 @@ Note: has no effect if a solid was selected true - Real part of potential z-component + Real part of vector potential z-component Note: has no effect if a solid was selected @@ -373,19 +352,12 @@ Note: has no effect if a solid was selected - - - - - - - true - Imaginary part of potential z-component + Imaginary part of vector potential z-component Note: has no effect if a solid was selected diff --git a/src/Mod/Fem/femexamples/equation_magnetodynamics_elmer.py b/src/Mod/Fem/femexamples/equation_magnetodynamics_elmer.py index fa56c42130..bd5778f875 100644 --- a/src/Mod/Fem/femexamples/equation_magnetodynamics_elmer.py +++ b/src/Mod/Fem/femexamples/equation_magnetodynamics_elmer.py @@ -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 diff --git a/src/Mod/Fem/femobjects/constraint_electrostaticpotential.py b/src/Mod/Fem/femobjects/constraint_electrostaticpotential.py index f2d1d3381e..50ac56a951 100644 --- a/src/Mod/Fem/femobjects/constraint_electrostaticpotential.py +++ b/src/Mod/Fem/femobjects/constraint_electrostaticpotential.py @@ -163,73 +163,37 @@ class ConstraintElectrostaticPotential(base_fempythonobject.BaseFemPythonObject) prop.append( _PropHelper( type="App::PropertyBool", - name="AV_re_1_Disabled", + name="EnableAV", group="Electromagnetic Potential", - doc="", - value=True, + doc="Enable scalar potential boundary condition", + value=False, ) ) prop.append( _PropHelper( type="App::PropertyBool", - name="AV_re_2_Disabled", + name="EnableAV_1", group="Electromagnetic Potential", - doc="", - value=True, + doc="Enable vector potential x-component boundary condition", + value=False, ) ) prop.append( _PropHelper( type="App::PropertyBool", - name="AV_re_3_Disabled", + name="EnableAV_2", group="Electromagnetic Potential", - doc="", - value=True, + doc="Enable vector potential y-component boundary condition", + value=False, ) ) prop.append( _PropHelper( type="App::PropertyBool", - name="AV_im_1_Disabled", + name="EnableAV_3", group="Electromagnetic Potential", - doc="", - value=True, - ) - ) - prop.append( - _PropHelper( - type="App::PropertyBool", - name="AV_im_2_Disabled", - group="Electromagnetic Potential", - doc="", - value=True, - ) - ) - prop.append( - _PropHelper( - type="App::PropertyBool", - name="AV_im_3_Disabled", - group="Electromagnetic Potential", - doc="", - value=True, - ) - ) - prop.append( - _PropHelper( - type="App::PropertyBool", - name="AV_re_Disabled", - group="Electromagnetic Potential", - doc="", - value=True, - ) - ) - prop.append( - _PropHelper( - type="App::PropertyBool", - name="AV_im_Disabled", - group="Electromagnetic Potential", - doc="", - value=True, + doc="Enable vector potential z-component boundary condition", + value=False, ) ) prop.append( @@ -303,3 +267,35 @@ class ConstraintElectrostaticPotential(base_fempythonobject.BaseFemPythonObject) old_type="App::PropertyElectricPotential", convert_old_value=lambda x: "{} Wb/m".format(x.getValueAs("V").Value), ) + + # 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") + + # 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") + + except Base.PropertyError: + pass diff --git a/src/Mod/Fem/femsolver/elmer/equations/magnetodynamic_writer.py b/src/Mod/Fem/femsolver/elmer/equations/magnetodynamic_writer.py index 7bcb968838..d0a7e759fc 100644 --- a/src/Mod/Fem/femsolver/elmer/equations/magnetodynamic_writer.py +++ b/src/Mod/Fem/femsolver/elmer/equations/magnetodynamic_writer.py @@ -208,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)) @@ -291,44 +288,38 @@ class MgDynwriter: self.write.boundary(name, "Current Density Im 1", round(currentDensity, 6)) if femutils.is_derived_from(obj, "Fem::ConstraintElectrostaticPotential"): - if not obj.AV_re_Disabled: + 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: + 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: + 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: + 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)) - 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 = obj.AV_im.getValueAs("V").Value - self.write.boundary(name, "AV im", round(potential, 6)) - if not obj.AV_im_1_Disabled: - potential = obj.AV_im_1.getValueAs("Wb/m").Value - self.write.boundary(name, "AV im {e} 1", round(potential, 6)) - if not obj.AV_im_2_Disabled: - potential = obj.AV_im_2.getValueAs("Wb/m").Value - self.write.boundary(name, "AV im {e} 2", round(potential, 6)) - if not obj.AV_im_3_Disabled: 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)) def handleMagnetodynamicBndConditions(self, equation): # the current density can either be a body force or a boundary constraint diff --git a/src/Mod/Fem/femtaskpanels/task_constraint_electrostaticpotential.py b/src/Mod/Fem/femtaskpanels/task_constraint_electrostaticpotential.py index 7cf8903cd6..3d1826e126 100644 --- a/src/Mod/Fem/femtaskpanels/task_constraint_electrostaticpotential.py +++ b/src/Mod/Fem/femtaskpanels/task_constraint_electrostaticpotential.py @@ -91,9 +91,9 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel): self.potential_changed, ) QtCore.QObject.connect( - self.parameter_widget.ckb_av_re, + self.parameter_widget.ckb_av, QtCore.SIGNAL("toggled(bool)"), - self.av_re_enabled_changed, + self.av_enabled_changed, ) QtCore.QObject.connect( self.parameter_widget.qsb_av_re, @@ -101,9 +101,9 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel): self.av_re_changed, ) QtCore.QObject.connect( - self.parameter_widget.ckb_av_re_1, + self.parameter_widget.ckb_av_1, QtCore.SIGNAL("toggled(bool)"), - self.av_re_1_enabled_changed, + self.av_1_enabled_changed, ) QtCore.QObject.connect( self.parameter_widget.qsb_av_re_1, @@ -111,9 +111,9 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel): self.av_re_1_changed, ) QtCore.QObject.connect( - self.parameter_widget.ckb_av_re_2, + self.parameter_widget.ckb_av_2, QtCore.SIGNAL("toggled(bool)"), - self.av_re_2_enabled_changed, + self.av_2_enabled_changed, ) QtCore.QObject.connect( self.parameter_widget.qsb_av_re_2, @@ -121,50 +121,30 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel): self.av_re_2_changed, ) QtCore.QObject.connect( - self.parameter_widget.ckb_av_re_3, + self.parameter_widget.ckb_av_3, QtCore.SIGNAL("toggled(bool)"), - self.av_re_3_enabled_changed, + 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.ckb_av_im, - QtCore.SIGNAL("toggled(bool)"), - self.av_im_enabled_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.ckb_av_im_1, - QtCore.SIGNAL("toggled(bool)"), - self.av_im_1_enabled_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.ckb_av_im_2, - QtCore.SIGNAL("toggled(bool)"), - self.av_im_2_enabled_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.ckb_av_im_3, - QtCore.SIGNAL("toggled(bool)"), - self.av_im_3_enabled_changed, - ) QtCore.QObject.connect( self.parameter_widget.qsb_av_im_3, QtCore.SIGNAL("valueChanged(Base::Quantity)"), @@ -242,14 +222,10 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel): self.av_im_2 = self.obj.AV_im_2 self.av_im_3 = self.obj.AV_im_3 - self.av_re_enabled = not self.obj.AV_re_Disabled - self.av_im_enabled = not self.obj.AV_im_Disabled - self.av_re_1_enabled = not self.obj.AV_re_1_Disabled - self.av_re_2_enabled = not self.obj.AV_re_2_Disabled - self.av_re_3_enabled = not self.obj.AV_re_3_Disabled - self.av_im_1_enabled = not self.obj.AV_im_1_Disabled - self.av_im_2_enabled = not self.obj.AV_im_2_Disabled - self.av_im_3_enabled = not 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.boundary_condition = self.obj.BoundaryCondition self.potential_constant = self.obj.PotentialConstant @@ -271,14 +247,10 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel): self.obj.AV_im_2 = self.av_im_2 self.obj.AV_im_3 = self.av_im_3 - self.obj.AV_re_Disabled = not self.av_re_enabled - self.obj.AV_im_Disabled = not self.av_im_enabled - self.obj.AV_re_1_Disabled = not self.av_re_1_enabled - self.obj.AV_re_2_Disabled = not self.av_re_2_enabled - self.obj.AV_re_3_Disabled = not self.av_re_3_enabled - self.obj.AV_im_1_Disabled = not self.av_im_1_enabled - self.obj.AV_im_2_Disabled = not self.av_im_2_enabled - self.obj.AV_im_3_Disabled = not self.av_im_3_enabled + 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 @@ -299,41 +271,37 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel): # scalar potential self.parameter_widget.qsb_av_re.setProperty("value", self.av_re) - self.parameter_widget.qsb_av_re.setEnabled(self.av_re_enabled) + 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_im_enabled) + 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_re_1_enabled) + 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_re_2_enabled) + 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_re_3_enabled) + 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_im_1_enabled) + 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_im_2_enabled) + 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_im_3_enabled) + 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_re.setChecked(self.av_re_enabled) - self.parameter_widget.ckb_av_re_1.setChecked(self.av_re_1_enabled) - self.parameter_widget.ckb_av_re_2.setChecked(self.av_re_2_enabled) - self.parameter_widget.ckb_av_re_3.setChecked(self.av_re_3_enabled) - self.parameter_widget.ckb_av_im.setChecked(self.av_im_enabled) - self.parameter_widget.ckb_av_im_1.setChecked(self.av_im_1_enabled) - self.parameter_widget.ckb_av_im_2.setChecked(self.av_im_2_enabled) - self.parameter_widget.ckb_av_im_3.setChecked(self.av_im_3_enabled) + 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) @@ -358,16 +326,7 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel): self.parameter_widget.cb_boundary_condition.setCurrentIndex(index) # start with electromagnetic inputs hidden if no field is set - if not ( - self.av_re_enabled - or self.av_im_enabled - or self.av_re_1_enabled - or self.av_re_2_enabled - or self.av_re_3_enabled - or self.av_im_1_enabled - or self.av_im_2_enabled - or self.av_im_3_enabled - ): + 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) def potential_changed(self, value): @@ -380,36 +339,24 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel): def electromagnetic_enabled_changed(self, value): self.parameter_widget.gb_electromagnetic.setVisible(value) - def av_re_enabled_changed(self, value): - self.av_re_enabled = value + def av_enabled_changed(self, value): + self.av_enabled = value self.parameter_widget.qsb_av_re.setEnabled(value) - - def av_re_1_enabled_changed(self, value): - self.av_re_1_enabled = value - self.parameter_widget.qsb_av_re_1.setEnabled(value) - - def av_re_2_enabled_changed(self, value): - self.av_re_2_enabled = value - self.parameter_widget.qsb_av_re_2.setEnabled(value) - - def av_re_3_enabled_changed(self, value): - self.av_re_3_enabled = value - self.parameter_widget.qsb_av_re_3.setEnabled(value) - - def av_im_enabled_changed(self, value): - self.av_im_enabled = value self.parameter_widget.qsb_av_im.setEnabled(value) - def av_im_1_enabled_changed(self, value): - self.av_im_1_enabled = 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_im_2_enabled_changed(self, value): - self.av_im_2_enabled = 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_im_3_enabled_changed(self, value): - self.av_im_3_enabled = 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):