From d4dca9fd935596796a9f64dfcb01b95a3c99ec76 Mon Sep 17 00:00:00 2001 From: marioalexis Date: Sat, 1 Mar 2025 09:34:27 -0300 Subject: [PATCH] Fem: Improve current density boundary condition --- src/Mod/Fem/Gui/CMakeLists.txt | 1 + .../symbols/ConstraintCurrentDensity.iv | 55 ++ .../Fem/Gui/Resources/ui/CurrentDensity.ui | 703 +++++++----------- .../equation_magnetodynamics_2D_elmer.py | 4 +- .../femobjects/constraint_currentdensity.py | 262 ++++--- .../equations/magnetodynamic2D_writer.py | 14 +- .../elmer/equations/magnetodynamic_writer.py | 14 +- .../elmer/equations/staticcurrent_writer.py | 11 +- .../task_constraint_currentdensity.py | 281 +++++-- .../view_constraint_currentdensity.py | 22 + 10 files changed, 720 insertions(+), 647 deletions(-) create mode 100644 src/Mod/Fem/Gui/Resources/symbols/ConstraintCurrentDensity.iv diff --git a/src/Mod/Fem/Gui/CMakeLists.txt b/src/Mod/Fem/Gui/CMakeLists.txt index 754bb348b0..8f343f3008 100755 --- a/src/Mod/Fem/Gui/CMakeLists.txt +++ b/src/Mod/Fem/Gui/CMakeLists.txt @@ -373,6 +373,7 @@ SET(FemGuiSymbol_IV Resources/symbols/ConstraintContact.iv Resources/symbols/ConstraintDisplacement.iv Resources/symbols/ConstraintElectrostaticPotential.iv + Resources/symbols/ConstraintCurrentDensity.iv Resources/symbols/ConstraintFixed.iv Resources/symbols/ConstraintForce.iv Resources/symbols/ConstraintHeatFlux.iv diff --git a/src/Mod/Fem/Gui/Resources/symbols/ConstraintCurrentDensity.iv b/src/Mod/Fem/Gui/Resources/symbols/ConstraintCurrentDensity.iv new file mode 100644 index 0000000000..d231f0b9de --- /dev/null +++ b/src/Mod/Fem/Gui/Resources/symbols/ConstraintCurrentDensity.iv @@ -0,0 +1,55 @@ +#Inventor V2.1 ascii + +# SPDX-License-Identifier: LGPL-2.1-or-later + +#/*************************************************************************** +# * Copyright (c) 2025 Mario Passaglia * +# * * +# * This file is part of FreeCAD. * +# * * +# * FreeCAD is free software: you can redistribute it and/or modify it * +# * under the terms of the GNU Lesser General Public License as * +# * published by the Free Software Foundation, either version 2.1 of the * +# * License, or (at your option) any later version. * +# * * +# * FreeCAD is distributed in the hope that it will be useful, but * +# * WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * +# * Lesser General Public License for more details. * +# * * +# * You should have received a copy of the GNU Lesser General Public * +# * License along with FreeCAD. If not, see * +# * . * +# * * +# ************************************************************************** + + +Separator { + + Separator { + + Switch { + + Separator { + + Translation { + translation 0 3.3333334 0 + } + Cone { + bottomRadius 0.66666669 + height 1.3333334 + + } + Translation { + translation 0 -2 0 + + } + Cylinder { + radius 0.26666668 + height 2.6666667 + + } + } + } + } +} diff --git a/src/Mod/Fem/Gui/Resources/ui/CurrentDensity.ui b/src/Mod/Fem/Gui/Resources/ui/CurrentDensity.ui index 15d61e8109..b3030d591b 100644 --- a/src/Mod/Fem/Gui/Resources/ui/CurrentDensity.ui +++ b/src/Mod/Fem/Gui/Resources/ui/CurrentDensity.ui @@ -13,371 +13,272 @@ Analysis feature properties - - - - - Current density: + + + + + + + Select Custom mode to enable vector current density + + + + + + Mode: + + + + + + + - - + + + + + true - - Real + + Imaginary part is only used for equations +with harmonic/oscillating driving current - - - - - - true - - - Imaginary + + false + + + + + true + + + Real + + + + + + + true + + + Imaginary + + + + + + + x + + + + + + + true + + + Real part of current density x-component + + + true + + + A/m^2 + + + 1.000000000000000 + + + 0.000000000000000 + + + + + + + true + + + Imaginary part of current density x-component + + + true + + + A/m^2 + + + 1.000000000000000 + + + 0.000000000000000 + + + + + + + y + + + + + + + true + + + Real part of current density y-component + + + true + + + A/m^2 + + + 1.000000000000000 + + + 0.000000000000000 + + + + + + + true + + + Imaginary part of current density y-component + + + true + + + A/m^2 + + + 1.000000000000000 + + + 0.000000000000000 + + + + + + + z + + + + + + + true + + + Real part of current density z-component + + + true + + + A/m^2 + + + 1.000000000000000 + + + 0.000000000000000 + + + + + + + true + + + Imaginary part of current density z-component + + + true + + + A/m^2 + + + 1.000000000000000 + + + 0.000000000000000 + + + + - - - true - - - x - - - - - - - true - - - - 100 - 20 - + + + - Real part of potential x-component -Note: if a face was selected this will be the value - in normal face direction - settings for y and z will be ignored - - - true - - - - - - -1000000000000000000000.000000000000000 - - - 1000000000000000000000.000000000000000 - - - 1.000000000000000 - - - 1.000000000000000 - - - - - - - unspecified - - - - - - - - - - true - - - - 100 - 20 - - - - Imaginary part of potential x-component -Note: if a face was selected this will be the value - in normal face direction - settings for y and z will be ignored - - - true - - - - - - -1000000000000000000000.000000000000000 - - - 1000000000000000000000.000000000000000 - - - 1.000000000000000 - - - 1.000000000000000 - - - - - - - unspecified - - - - - - - - - - true - - - y - - - - - - - true - - - - 100 - 20 - - - - Real part of potential y-component -Note: for 2D only setting for x is possible, - setting for y will be ignored - - - true - - - - - - -1000000000000000000000.000000000000000 - - - 1000000000000000000000.000000000000000 - - - 1.000000000000000 - - - 1.000000000000000 - - - - - - - unspecified - - - - - - - - - - true - - - - 100 - 20 - - - - Imaginary part of potential y-component -Note: for 2D only setting for x is possible, - setting for y will be ignored - - - true - - - - - - -1000000000000000000000.000000000000000 - - - 1000000000000000000000.000000000000000 - - - 1.000000000000000 - - - 1.000000000000000 - - - - - - - unspecified - - - - - - - - - - true - - - z - - - - - - - true - - - - 100 - 20 - - - - Real part of potential z-component - - - true - - - - - - -1000000000000000000000.000000000000000 - - - 1000000000000000000000.000000000000000 - - - 1.000000000000000 - - - 1.000000000000000 - - - - - - - unspecified - - - - - - - - - - true - - - - 100 - 20 - - - - Imaginary part of potential z-component - - - true - - - - - - -1000000000000000000000.000000000000000 - - - 1000000000000000000000.000000000000000 - - - 1.000000000000000 - - - 1.000000000000000 - - - - - - - unspecified - - - - - - - - - - Normal: - - - - - - - true - - - A/m^2 - - - Qt::AlignLeft|Qt::AlignTrailing|Qt::AlignVCenter - - - true - - - -1000000000000000000000.000000000000000 - - - 1000000000000000000000.000000000000000 - - - 1.000000000000000 - - - 0.000000000000 - + Current density normal to surface + + + + + + true + + + Real + + + + + + + true + + + Imaginary + + + + + + + Normal: + + + + + + + A/m^2 + + + + + + + A/m^2 + + + + @@ -390,102 +291,4 @@ Note: for 2D only setting for x is possible, - - - reXunspecBox - toggled(bool) - realXQSB - setDisabled(bool) - - - 152 - 61 - - - 80 - 61 - - - - - reYunspecBox - toggled(bool) - realYQSB - setDisabled(bool) - - - 152 - 87 - - - 80 - 87 - - - - - imZunspecBox - toggled(bool) - imagZQSB - setDisabled(bool) - - - 297 - 113 - - - 224 - 113 - - - - - imYunspecBox - toggled(bool) - imagYQSB - setDisabled(bool) - - - 297 - 87 - - - 224 - 87 - - - - - imXunspecBox - toggled(bool) - imagXQSB - setDisabled(bool) - - - 297 - 61 - - - 224 - 61 - - - - - reZunspecBox - toggled(bool) - realZQSB - setDisabled(bool) - - - 152 - 113 - - - 80 - 113 - - - - diff --git a/src/Mod/Fem/femexamples/equation_magnetodynamics_2D_elmer.py b/src/Mod/Fem/femexamples/equation_magnetodynamics_2D_elmer.py index 6f99c1ff5a..1571d16a39 100644 --- a/src/Mod/Fem/femexamples/equation_magnetodynamics_2D_elmer.py +++ b/src/Mod/Fem/femexamples/equation_magnetodynamics_2D_elmer.py @@ -252,8 +252,8 @@ def setup(doc=None, solvertype="elmer"): # constraint current density CurrentDensity = ObjectsFem.makeConstraintCurrentDensity(doc, "CurrentDensity") CurrentDensity.References = [(BooleanFragments, "Face2")] - CurrentDensity.CurrentDensity_re_1 = "250000.000 A/m^2" - CurrentDensity.CurrentDensity_re_1_Disabled = False + CurrentDensity.NormalCurrentDensity_re = "250000.000 A/m^2" + CurrentDensity.Mode = "Normal" analysis.addObject(CurrentDensity) # mesh diff --git a/src/Mod/Fem/femobjects/constraint_currentdensity.py b/src/Mod/Fem/femobjects/constraint_currentdensity.py index 3fa5781060..c97a67d255 100644 --- a/src/Mod/Fem/femobjects/constraint_currentdensity.py +++ b/src/Mod/Fem/femobjects/constraint_currentdensity.py @@ -1,5 +1,6 @@ # *************************************************************************** # * Copyright (c) 2023 Uwe Stöhr * +# * Copyright (c) 2025 Mario Passaglia * # * * # * This file is part of the FreeCAD CAx development system. * # * * @@ -22,15 +23,19 @@ # *************************************************************************** __title__ = "FreeCAD FEM constraint current density document object" -__author__ = "Uwe Stöhr" +__author__ = "Uwe Stöhr, Mario Passaglia" __url__ = "https://www.freecad.org" ## @package constraint_currentdensity # \ingroup FEM # \brief constraint current density object +from FreeCAD import Base + from . import base_fempythonobject +_PropHelper = base_fempythonobject._PropHelper + class ConstraintCurrentDensity(base_fempythonobject.BaseFemPythonObject): @@ -38,110 +43,159 @@ class ConstraintCurrentDensity(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::PropertyCurrentDensity", + name="CurrentDensity_re_1", + group="Current Density", + doc="Real part of current density x-component", + value="0 A/m^2", + ) + ) + prop.append( + _PropHelper( + type="App::PropertyCurrentDensity", + name="CurrentDensity_re_2", + group="Current Density", + doc="Real part of current density y-component", + value="0 A/m^2", + ) + ) + prop.append( + _PropHelper( + type="App::PropertyCurrentDensity", + name="CurrentDensity_re_3", + group="Current Density", + doc="Real part of current density z-component", + value="0 A/m^2", + ) + ) + prop.append( + _PropHelper( + type="App::PropertyCurrentDensity", + name="CurrentDensity_im_1", + group="Current Density", + doc="Imaginary part of current density x-component", + value="0 A/m^2", + ) + ) + prop.append( + _PropHelper( + type="App::PropertyCurrentDensity", + name="CurrentDensity_im_2", + group="Current Density", + doc="Imaginary part of current density y-component", + value="0 A/m^2", + ) + ) + prop.append( + _PropHelper( + type="App::PropertyCurrentDensity", + name="CurrentDensity_im_3", + group="Current Density", + doc="Imaginary part of current density z-component", + value="0 A/m^2", + ) + ) + prop.append( + _PropHelper( + type="App::PropertyBool", + name="EnableCurrentDensity_1", + group="Current Density", + doc="Enable currenty density x component", + value=False, + ) + ) + prop.append( + _PropHelper( + type="App::PropertyBool", + name="EnableCurrentDensity_2", + group="Current Density", + doc="Enable currenty density y component", + value=False, + ) + ) + prop.append( + _PropHelper( + type="App::PropertyBool", + name="EnableCurrentDensity_3", + group="Current Density", + doc="Enable currenty density z component", + value=False, + ) + ) + prop.append( + _PropHelper( + type="App::PropertyCurrentDensity", + name="NormalCurrentDensity_re", + group="Current Density", + doc="Real part of current density normal to boundary", + value="0 A/m^2", + ) + ) + prop.append( + _PropHelper( + type="App::PropertyCurrentDensity", + name="NormalCurrentDensity_im", + group="Current Density", + doc="Imaginary part of current density normal to boundary", + value="0 A/m^2", + ) + ) + prop.append( + _PropHelper( + type="App::PropertyEnumeration", + name="Mode", + group="Current Density", + doc="Set current boundary condition direction mode", + value=["Custom", "Normal"], + ) + ) + + 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, "CurrentDensity_re_1"): - obj.addProperty( - "App::PropertyCurrentDensity", - "CurrentDensity_re_1", - "Vector Potential", - "Real part of current density x-component", - ) - obj.setPropertyStatus("CurrentDensity_re_1", "LockDynamic") - obj.CurrentDensity_re_1 = "0 A/m^2" - if not hasattr(obj, "CurrentDensity_re_2"): - obj.addProperty( - "App::PropertyCurrentDensity", - "CurrentDensity_re_2", - "Vector Potential", - "Real part of current density y-component", - ) - obj.setPropertyStatus("CurrentDensity_re_2", "LockDynamic") - obj.CurrentDensity_re_2 = "0 A/m^2" - if not hasattr(obj, "CurrentDensity_re_3"): - obj.addProperty( - "App::PropertyCurrentDensity", - "CurrentDensity_re_3", - "Vector Potential", - "Real part of current density z-component", - ) - obj.setPropertyStatus("CurrentDensity_re_3", "LockDynamic") - obj.CurrentDensity_re_3 = "0 A/m^2" - if not hasattr(obj, "CurrentDensity_im_1"): - obj.addProperty( - "App::PropertyCurrentDensity", - "CurrentDensity_im_1", - "Vector Potential", - "Imaginary part of current density x-component", - ) - obj.setPropertyStatus("CurrentDensity_im_1", "LockDynamic") - obj.CurrentDensity_im_1 = "0 A/m^2" - if not hasattr(obj, "CurrentDensity_im_2"): - obj.addProperty( - "App::PropertyCurrentDensity", - "CurrentDensity_im_2", - "Vector Potential", - "Imaginary part of current density y-component", - ) - obj.setPropertyStatus("CurrentDensity_im_2", "LockDynamic") - obj.CurrentDensity_im_2 = "0 A/m^2" - if not hasattr(obj, "CurrentDensity_im_3"): - obj.addProperty( - "App::PropertyCurrentDensity", - "CurrentDensity_im_3", - "Vector Potential", - "Imaginary part of current density z-component", - ) - obj.setPropertyStatus("CurrentDensity_im_3", "LockDynamic") - obj.CurrentDensity_im_3 = "0 A/m^2" - if not hasattr(obj, "NormalCurrentDensity"): - obj.addProperty( - "App::PropertyCurrentDensity", - "NormalCurrentDensity", - "Current Density", - "Current density normal to boundary", - ) - obj.setPropertyStatus("NormalCurrentDensity", "LockDynamic") - obj.NormalCurrentDensity = "0 A/m^2" + # enable current density properties from old properties + try: + obj.EnableCurrentDensity_1 = not obj.getPropertyByName( + "CurrentDensity_re_1_Disabled" + ) or not obj.getPropertyByName("CurrentDensity_im_1_Disabled") - # now the enable bools - if not hasattr(obj, "CurrentDensity_re_1_Disabled"): - obj.addProperty( - "App::PropertyBool", "CurrentDensity_re_1_Disabled", "Vector Potential", "" - ) - obj.setPropertyStatus("CurrentDensity_re_1_Disabled", "LockDynamic") - obj.CurrentDensity_re_1_Disabled = True - if not hasattr(obj, "CurrentDensity_re_2_Disabled"): - obj.addProperty( - "App::PropertyBool", "CurrentDensity_re_2_Disabled", "Vector Potential", "" - ) - obj.setPropertyStatus("CurrentDensity_re_2_Disabled", "LockDynamic") - obj.CurrentDensity_re_2_Disabled = True - if not hasattr(obj, "CurrentDensity_re_3_Disabled"): - obj.addProperty( - "App::PropertyBool", "CurrentDensity_re_3_Disabled", "Vector Potential", "" - ) - obj.setPropertyStatus("CurrentDensity_re_3_Disabled", "LockDynamic") - obj.CurrentDensity_re_3_Disabled = True - if not hasattr(obj, "CurrentDensity_im_1_Disabled"): - obj.addProperty( - "App::PropertyBool", "CurrentDensity_im_1_Disabled", "Vector Potential", "" - ) - obj.setPropertyStatus("CurrentDensity_im_1_Disabled", "LockDynamic") - obj.CurrentDensity_im_1_Disabled = True - if not hasattr(obj, "CurrentDensity_im_2_Disabled"): - obj.addProperty( - "App::PropertyBool", "CurrentDensity_im_2_Disabled", "Vector Potential", "" - ) - obj.setPropertyStatus("CurrentDensity_im_2_Disabled", "LockDynamic") - obj.CurrentDensity_im_2_Disabled = True - if not hasattr(obj, "CurrentDensity_im_3_Disabled"): - obj.addProperty( - "App::PropertyBool", "CurrentDensity_im_3_Disabled", "Vector Potential", "" - ) - obj.setPropertyStatus("CurrentDensity_im_3_Disabled", "LockDynamic") - obj.CurrentDensity_im_3_Disabled = True + obj.EnableCurrentDensity_2 = not obj.getPropertyByName( + "CurrentDensity_re_2_Disabled" + ) or not obj.getPropertyByName("CurrentDensity_im_2_Disabled") + + obj.EnableCurrentDensity_3 = not obj.getPropertyByName( + "CurrentDensity_re_3_Disabled" + ) or not obj.getPropertyByName("CurrentDensity_im_3_Disabled") + + # remove old properties + obj.setPropertyStatus("CurrentDensity_re_1_Disabled", "-LockDynamic") + obj.removeProperty("CurrentDensity_re_1_Disabled") + obj.setPropertyStatus("CurrentDensity_re_2_Disabled", "-LockDynamic") + obj.removeProperty("CurrentDensity_re_2_Disabled") + obj.setPropertyStatus("CurrentDensity_re_3_Disabled", "-LockDynamic") + obj.removeProperty("CurrentDensity_re_3_Disabled") + obj.setPropertyStatus("CurrentDensity_im_1_Disabled", "-LockDynamic") + obj.removeProperty("CurrentDensity_im_1_Disabled") + obj.setPropertyStatus("CurrentDensity_im_2_Disabled", "-LockDynamic") + obj.removeProperty("CurrentDensity_im_2_Disabled") + obj.setPropertyStatus("CurrentDensity_im_3_Disabled", "-LockDynamic") + obj.removeProperty("CurrentDensity_im_3_Disabled") + + except Base.PropertyError: + pass diff --git a/src/Mod/Fem/femsolver/elmer/equations/magnetodynamic2D_writer.py b/src/Mod/Fem/femsolver/elmer/equations/magnetodynamic2D_writer.py index 8444a44325..6bc835060b 100644 --- a/src/Mod/Fem/femsolver/elmer/equations/magnetodynamic2D_writer.py +++ b/src/Mod/Fem/femsolver/elmer/equations/magnetodynamic2D_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 @@ -135,16 +136,13 @@ class MgDyn2Dwriter: ) def _outputMagnetodynamic2DBodyForce(self, obj, name, equation): - if hasattr(obj, "CurrentDensity_re_1"): - # output only if current density is enabled and needed - if not obj.CurrentDensity_re_1_Disabled: - currentDensity = float(obj.CurrentDensity_re_1.getValueAs("A/m^2")) - self.write.bodyForce(name, "Current Density", round(currentDensity, 6)) + if femutils.is_derived_from(obj, "Fem::ConstraintCurrentDensity") and obj.Mode == "Normal": + currentDensity = obj.NormalCurrentDensity_re.getValueAs("A/m^2").Value + self.write.bodyForce(name, "Current Density", round(currentDensity, 6)) # imaginaries are only needed for harmonic equation if equation.IsHarmonic: - if not obj.CurrentDensity_im_1_Disabled: - currentDensity = float(obj.CurrentDensity_im_1.getValueAs("A/m^2")) - self.write.bodyForce(name, "Current Density Im", round(currentDensity, 6)) + currentDensity = obj.NormalCurrentDensity_im.getValueAs("A/m^2").Value + self.write.bodyForce(name, "Current Density Im", round(currentDensity, 6)) if hasattr(obj, "Magnetization_re_1"): # output only if magnetization is enabled and needed diff --git a/src/Mod/Fem/femsolver/elmer/equations/magnetodynamic_writer.py b/src/Mod/Fem/femsolver/elmer/equations/magnetodynamic_writer.py index d0a7e759fc..d5c32e7d28 100644 --- a/src/Mod/Fem/femsolver/elmer/equations/magnetodynamic_writer.py +++ b/src/Mod/Fem/femsolver/elmer/equations/magnetodynamic_writer.py @@ -162,26 +162,26 @@ class MgDynwriter: ) def _outputMagnetodynamicBodyForce(self, obj, name, equation): - if hasattr(obj, "CurrentDensity_re_1"): + if femutils.is_derived_from(obj, "Fem::ConstraintCurrentDensity") and obj.Mode == "Custom": # output only if current density is enabled and needed - if not obj.CurrentDensity_re_1_Disabled: + if obj.EnableCurrentDensity_re_1: currentDensity = float(obj.CurrentDensity_re_1.getValueAs("A/m^2")) self.write.bodyForce(name, "Current Density 1", round(currentDensity, 6)) - if not obj.CurrentDensity_re_2_Disabled: + if obj.EnableCurrentDensity_re_2: currentDensity = float(obj.CurrentDensity_re_2.getValueAs("A/m^2")) self.write.bodyForce(name, "Current Density 2", round(currentDensity, 6)) - if not obj.CurrentDensity_re_3_Disabled: + if obj.EnableCurrentDensity_re_3: currentDensity = float(obj.CurrentDensity_re_3.getValueAs("A/m^2")) self.write.bodyForce(name, "Current Density 3", round(currentDensity, 6)) # imaginaries are only needed for harmonic equation if equation.IsHarmonic: - if not obj.CurrentDensity_im_1_Disabled: + if obj.EnableCurrentDensity_im_1: currentDensity = float(obj.CurrentDensity_im_1.getValueAs("A/m^2")) self.write.bodyForce(name, "Current Density Im 1", round(currentDensity, 6)) - if not obj.CurrentDensity_im_2_Disabled: + if obj.EnableCurrentDensity_im_2: currentDensity = float(obj.CurrentDensity_im_2.getValueAs("A/m^2")) self.write.bodyForce(name, "Current Density Im 2", round(currentDensity, 6)) - if not obj.CurrentDensity_im_3_Disabled: + if obj.EnableCurrentDensity_im_3: currentDensity = float(obj.CurrentDensity_im_3.getValueAs("A/m^2")) self.write.bodyForce(name, "Current Density Im 3", round(currentDensity, 6)) diff --git a/src/Mod/Fem/femsolver/elmer/equations/staticcurrent_writer.py b/src/Mod/Fem/femsolver/elmer/equations/staticcurrent_writer.py index af12735a12..edb35d1fbb 100644 --- a/src/Mod/Fem/femsolver/elmer/equations/staticcurrent_writer.py +++ b/src/Mod/Fem/femsolver/elmer/equations/staticcurrent_writer.py @@ -96,10 +96,13 @@ class SCwriter: # output the FreeCAD label as comment if obj.Label: self.write.boundary(name, "! FreeCAD Name", obj.Label) - self.write.boundary(name, "Current Density BC", True) - self.write.boundary( - name, "Current Density", obj.NormalCurrentDensity.getValueAs("A/m^2").Value - ) + if obj.Mode == "Normal": + self.write.boundary(name, "Current Density BC", True) + self.write.boundary( + name, + "Current Density", + obj.NormalCurrentDensity_re.getValueAs("A/m^2").Value, + ) self.write.handled(obj) diff --git a/src/Mod/Fem/femtaskpanels/task_constraint_currentdensity.py b/src/Mod/Fem/femtaskpanels/task_constraint_currentdensity.py index 113b25680f..fcc2a761f0 100644 --- a/src/Mod/Fem/femtaskpanels/task_constraint_currentdensity.py +++ b/src/Mod/Fem/femtaskpanels/task_constraint_currentdensity.py @@ -1,5 +1,6 @@ # *************************************************************************** # * Copyright (c) 2023 Uwe Stöhr * +# * Copyright (c) 2025 Mario Passaglia * # * * # * This file is part of the FreeCAD CAx development system. * # * * @@ -22,13 +23,15 @@ # *************************************************************************** __title__ = "FreeCAD FEM constraint current density task panel for the document object" -__author__ = "Uwe Stöhr" +__author__ = "Uwe Stöhr, Mario Passaglia" __url__ = "https://www.freecad.org" ## @package task_constraint_currentdensity # \ingroup FEM # \brief task panel for constraint current density object +from PySide import QtCore + import FreeCAD import FreeCADGui @@ -43,10 +46,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/CurrentDensity.ui" ) - self._initParamWidget() # geometry selection widget # start with Solid in list! @@ -55,7 +57,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 @@ -67,6 +69,69 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel): self._partVisible = None self._meshVisible = None + QtCore.QObject.connect( + self.parameter_widget.cb_mode, + QtCore.SIGNAL("currentIndexChanged(int)"), + self.mode_changed, + ) + QtCore.QObject.connect( + self.parameter_widget.ckb_current_density_1, + QtCore.SIGNAL("toggled(bool)"), + self.current_density_1_enabled_changed, + ) + QtCore.QObject.connect( + self.parameter_widget.qsb_current_density_re_1, + QtCore.SIGNAL("valueChanged(Base::Quantity)"), + self.current_density_re_1_changed, + ) + QtCore.QObject.connect( + self.parameter_widget.ckb_current_density_2, + QtCore.SIGNAL("toggled(bool)"), + self.current_density_2_enabled_changed, + ) + QtCore.QObject.connect( + self.parameter_widget.qsb_current_density_re_2, + QtCore.SIGNAL("valueChanged(Base::Quantity)"), + self.current_density_re_2_changed, + ) + QtCore.QObject.connect( + self.parameter_widget.ckb_current_density_3, + QtCore.SIGNAL("toggled(bool)"), + self.current_density_3_enabled_changed, + ) + QtCore.QObject.connect( + self.parameter_widget.qsb_current_density_re_3, + QtCore.SIGNAL("valueChanged(Base::Quantity)"), + self.current_density_re_3_changed, + ) + QtCore.QObject.connect( + self.parameter_widget.qsb_current_density_im_1, + QtCore.SIGNAL("valueChanged(Base::Quantity)"), + self.current_density_im_1_changed, + ) + QtCore.QObject.connect( + self.parameter_widget.qsb_current_density_im_2, + QtCore.SIGNAL("valueChanged(Base::Quantity)"), + self.current_density_im_2_changed, + ) + QtCore.QObject.connect( + self.parameter_widget.qsb_current_density_im_3, + QtCore.SIGNAL("valueChanged(Base::Quantity)"), + self.current_density_im_3_changed, + ) + QtCore.QObject.connect( + self.parameter_widget.qsb_normal_current_density_re, + QtCore.SIGNAL("valueChanged(Base::Quantity)"), + self.normal_current_density_re_changed, + ) + QtCore.QObject.connect( + self.parameter_widget.qsb_normal_current_density_im, + QtCore.SIGNAL("valueChanged(Base::Quantity)"), + self.normal_current_density_im_changed, + ) + + self.init_parameter_widget() + def open(self): if self._mesh is not None and self._part is not None: self._meshVisible = self._mesh.ViewObject.isVisible() @@ -82,7 +147,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() @@ -98,86 +163,158 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel): else: self._part.ViewObject.hide() - def _initParamWidget(self): - self._paramWidget.realXQSB.setProperty("value", self.obj.CurrentDensity_re_1) - FreeCADGui.ExpressionBinding(self._paramWidget.realXQSB).bind( + def _get_params(self): + self.mode = self.obj.Mode + + self.current_density_re_1 = self.obj.CurrentDensity_re_1 + self.current_density_re_2 = self.obj.CurrentDensity_re_2 + self.current_density_re_3 = self.obj.CurrentDensity_re_3 + self.current_density_im_1 = self.obj.CurrentDensity_im_1 + self.current_density_im_2 = self.obj.CurrentDensity_im_2 + self.current_density_im_3 = self.obj.CurrentDensity_im_3 + + self.current_density_1_enabled = self.obj.EnableCurrentDensity_1 + self.current_density_2_enabled = self.obj.EnableCurrentDensity_2 + self.current_density_3_enabled = self.obj.EnableCurrentDensity_3 + + self.normal_current_density_re = self.obj.NormalCurrentDensity_re + self.normal_current_density_im = self.obj.NormalCurrentDensity_im + + def _set_params(self): + self.obj.Mode = self.mode + + self.obj.CurrentDensity_re_1 = self.current_density_re_1 + self.obj.CurrentDensity_re_2 = self.current_density_re_2 + self.obj.CurrentDensity_re_3 = self.current_density_re_3 + self.obj.CurrentDensity_im_1 = self.current_density_im_1 + self.obj.CurrentDensity_im_2 = self.current_density_im_2 + self.obj.CurrentDensity_im_3 = self.current_density_im_3 + + self.obj.EnableCurrentDensity_1 = self.current_density_1_enabled + self.obj.EnableCurrentDensity_2 = self.current_density_2_enabled + self.obj.EnableCurrentDensity_3 = self.current_density_3_enabled + + self.obj.NormalCurrentDensity_re = self.normal_current_density_re + self.obj.NormalCurrentDensity_im = self.normal_current_density_im + + def init_parameter_widget(self): + self._get_params() + + # custom current density + self.parameter_widget.qsb_current_density_re_1.setProperty( + "value", self.current_density_re_1 + ) + self.parameter_widget.qsb_current_density_re_1.setEnabled(self.current_density_1_enabled) + FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_current_density_re_1).bind( self.obj, "CurrentDensity_re_1" ) - self._paramWidget.realYQSB.setProperty("value", self.obj.CurrentDensity_re_2) - FreeCADGui.ExpressionBinding(self._paramWidget.realYQSB).bind( + + self.parameter_widget.qsb_current_density_re_2.setProperty( + "value", self.current_density_re_2 + ) + self.parameter_widget.qsb_current_density_re_2.setEnabled(self.current_density_2_enabled) + FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_current_density_re_2).bind( self.obj, "CurrentDensity_re_2" ) - self._paramWidget.realZQSB.setProperty("value", self.obj.CurrentDensity_re_3) - FreeCADGui.ExpressionBinding(self._paramWidget.realZQSB).bind( + + self.parameter_widget.qsb_current_density_re_3.setProperty( + "value", self.current_density_re_3 + ) + self.parameter_widget.qsb_current_density_re_3.setEnabled(self.current_density_3_enabled) + FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_current_density_re_3).bind( self.obj, "CurrentDensity_re_3" ) - self._paramWidget.imagXQSB.setProperty("value", self.obj.CurrentDensity_im_1) - FreeCADGui.ExpressionBinding(self._paramWidget.imagXQSB).bind( + + self.parameter_widget.qsb_current_density_im_1.setProperty( + "value", self.current_density_im_1 + ) + self.parameter_widget.qsb_current_density_im_1.setEnabled(self.current_density_1_enabled) + FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_current_density_im_1).bind( self.obj, "CurrentDensity_im_1" ) - self._paramWidget.imagYQSB.setProperty("value", self.obj.CurrentDensity_im_2) - FreeCADGui.ExpressionBinding(self._paramWidget.imagYQSB).bind( + + self.parameter_widget.qsb_current_density_im_2.setProperty( + "value", self.current_density_im_2 + ) + self.parameter_widget.qsb_current_density_im_2.setEnabled(self.current_density_2_enabled) + FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_current_density_im_2).bind( self.obj, "CurrentDensity_im_2" ) - self._paramWidget.imagZQSB.setProperty("value", self.obj.CurrentDensity_im_3) - FreeCADGui.ExpressionBinding(self._paramWidget.imagZQSB).bind( + + self.parameter_widget.qsb_current_density_im_3.setProperty( + "value", self.current_density_im_3 + ) + self.parameter_widget.qsb_current_density_im_3.setEnabled(self.current_density_3_enabled) + FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_current_density_im_3).bind( self.obj, "CurrentDensity_im_3" ) - self._paramWidget.normalQSB.setProperty("value", self.obj.NormalCurrentDensity) - FreeCADGui.ExpressionBinding(self._paramWidget.normalQSB).bind( - self.obj, "NormalCurrentDensity" + + self.parameter_widget.ckb_current_density_1.setChecked(self.current_density_1_enabled) + self.parameter_widget.ckb_current_density_2.setChecked(self.current_density_2_enabled) + self.parameter_widget.ckb_current_density_3.setChecked(self.current_density_3_enabled) + + self.parameter_widget.qsb_normal_current_density_re.setProperty( + "value", self.normal_current_density_re + ) + FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_normal_current_density_re).bind( + self.obj, "NormalCurrentDensity_re" + ) + self.parameter_widget.qsb_normal_current_density_im.setProperty( + "value", self.normal_current_density_im + ) + FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_normal_current_density_im).bind( + self.obj, "NormalCurrentDensity_im" ) - self._paramWidget.reXunspecBox.setChecked(self.obj.CurrentDensity_re_1_Disabled) - self._paramWidget.reYunspecBox.setChecked(self.obj.CurrentDensity_re_2_Disabled) - self._paramWidget.reZunspecBox.setChecked(self.obj.CurrentDensity_re_3_Disabled) - self._paramWidget.imXunspecBox.setChecked(self.obj.CurrentDensity_im_1_Disabled) - self._paramWidget.imYunspecBox.setChecked(self.obj.CurrentDensity_im_2_Disabled) - self._paramWidget.imZunspecBox.setChecked(self.obj.CurrentDensity_im_3_Disabled) + self.mode_enum = self.obj.getEnumerationsOfProperty("Mode") + index = self.mode_enum.index(self.mode) + self.parameter_widget.cb_mode.addItems(self.mode_enum) + self.parameter_widget.cb_mode.setCurrentIndex(index) - def _applyCurrentDensityChanges(self, enabledBox, currentDensityQSB): - enabled = enabledBox.isChecked() - currentdensity = None - try: - currentdensity = currentDensityQSB.property("value") - except ValueError: - FreeCAD.Console.PrintMessage( - "Wrong input. Not recognised input: '{}' " - "Current density has not been set.\n".format(currentDensityQSB.text()) - ) - currentdensity = "0.0 A/m^2" - return enabled, currentdensity + def current_density_1_enabled_changed(self, value): + self.current_density_1_enabled = value + self.parameter_widget.qsb_current_density_re_1.setEnabled(value) + self.parameter_widget.qsb_current_density_im_1.setEnabled(value) - def _applyWidgetChanges(self): - # apply the current densities and their enabled state - self.obj.CurrentDensity_re_1_Disabled, self.obj.CurrentDensity_re_1 = ( - self._applyCurrentDensityChanges( - self._paramWidget.reXunspecBox, self._paramWidget.realXQSB - ) - ) - self.obj.CurrentDensity_re_2_Disabled, self.obj.CurrentDensity_re_2 = ( - self._applyCurrentDensityChanges( - self._paramWidget.reYunspecBox, self._paramWidget.realYQSB - ) - ) - self.obj.CurrentDensity_re_3_Disabled, self.obj.CurrentDensity_re_3 = ( - self._applyCurrentDensityChanges( - self._paramWidget.reZunspecBox, self._paramWidget.realZQSB - ) - ) - self.obj.CurrentDensity_im_1_Disabled, self.obj.CurrentDensity_im_1 = ( - self._applyCurrentDensityChanges( - self._paramWidget.imXunspecBox, self._paramWidget.imagXQSB - ) - ) - self.obj.CurrentDensity_im_2_Disabled, self.obj.CurrentDensity_im_2 = ( - self._applyCurrentDensityChanges( - self._paramWidget.imYunspecBox, self._paramWidget.imagYQSB - ) - ) - self.obj.CurrentDensity_im_3_Disabled, self.obj.CurrentDensity_im_3 = ( - self._applyCurrentDensityChanges( - self._paramWidget.imZunspecBox, self._paramWidget.imagZQSB - ) - ) - self.obj.NormalCurrentDensity = self._paramWidget.normalQSB.property("value") + def current_density_2_enabled_changed(self, value): + self.current_density_2_enabled = value + self.parameter_widget.qsb_current_density_re_2.setEnabled(value) + self.parameter_widget.qsb_current_density_im_2.setEnabled(value) + + def current_density_3_enabled_changed(self, value): + self.current_density_3_enabled = value + self.parameter_widget.qsb_current_density_re_3.setEnabled(value) + self.parameter_widget.qsb_current_density_im_3.setEnabled(value) + + def current_density_re_1_changed(self, value): + self.current_density_re_1 = value + + def current_density_re_2_changed(self, value): + self.current_density_re_2 = value + + def current_density_re_3_changed(self, value): + self.current_density_re_3 = value + + def current_density_im_1_changed(self, value): + self.current_density_im_1 = value + + def current_density_im_2_changed(self, value): + self.current_density_im_2 = value + + def current_density_im_3_changed(self, value): + self.current_density_im_3 = value + + def normal_current_density_re_changed(self, value): + self.normal_current_density_re = value + + def normal_current_density_im_changed(self, value): + self.normal_current_density_im = value + + def mode_changed(self, index): + self.mode = self.mode_enum[index] + if self.mode == "Custom": + self.parameter_widget.gb_custom.setEnabled(True) + self.parameter_widget.gb_normal.setEnabled(False) + elif self.mode == "Normal": + self.parameter_widget.gb_custom.setEnabled(False) + self.parameter_widget.gb_normal.setEnabled(True) diff --git a/src/Mod/Fem/femviewprovider/view_constraint_currentdensity.py b/src/Mod/Fem/femviewprovider/view_constraint_currentdensity.py index f747fa0ee9..e85602dd39 100644 --- a/src/Mod/Fem/femviewprovider/view_constraint_currentdensity.py +++ b/src/Mod/Fem/femviewprovider/view_constraint_currentdensity.py @@ -29,13 +29,35 @@ __url__ = "https://www.freecad.org" # \ingroup FEM # \brief view provider for the constraint current density object +from pivy import coin + from femtaskpanels import task_constraint_currentdensity from . import view_base_femconstraint class VPConstraintCurrentDensity(view_base_femconstraint.VPBaseFemConstraint): + def __init__(self, vobj): + super().__init__(vobj) + mat = vobj.ShapeAppearance[0] + mat.DiffuseColor = (0.71, 0.40, 0.11, 0.0) + vobj.ShapeAppearance = mat + def setEdit(self, vobj, mode=0): return view_base_femconstraint.VPBaseFemConstraint.setEdit( self, vobj, mode, task_constraint_currentdensity._TaskPanel ) + + def attach(self, vobj): + super().attach(vobj) + vobj.loadSymbol(self.resource_symbol_dir + "ConstraintCurrentDensity.iv") + + def updateData(self, obj, prop): + if prop == "Mode": + symb = obj.ViewObject.SymbolNode.getChild(0) + if obj.Mode == "Normal": + obj.ViewObject.RotateSymbol = True + symb.whichChild.setValue(0) + elif obj.Mode == "Custom": + obj.ViewObject.RotateSymbol = False + symb.whichChild.setValue(-1)