From d0ee6a46a083ce3e5e1434fa8276f49ea4e1a447 Mon Sep 17 00:00:00 2001 From: Uwe Date: Mon, 15 Aug 2022 01:43:02 +0200 Subject: [PATCH] [FEM] fix body heat source constraint - as the name implies, it must be possible to set the heat to different bodies - for this a selection dialog is necessary - check that heat is not zero --- src/Mod/Fem/CMakeLists.txt | 1 + src/Mod/Fem/Gui/CMakeLists.txt | 1 + src/Mod/Fem/Gui/Resources/Fem.qrc | 1 + .../Fem/Gui/Resources/ui/BodyHeatSource.ui | 79 ++++++++++++ src/Mod/Fem/femcommands/commands.py | 2 +- .../femobjects/constraint_bodyheatsource.py | 2 - src/Mod/Fem/femsolver/elmer/writer.py | 32 +++-- .../task_constraint_bodyheatsource.py | 121 ++++++++++++++++++ .../view_constraint_bodyheatsource.py | 10 +- 9 files changed, 236 insertions(+), 13 deletions(-) create mode 100644 src/Mod/Fem/Gui/Resources/ui/BodyHeatSource.ui create mode 100644 src/Mod/Fem/femtaskpanels/task_constraint_bodyheatsource.py diff --git a/src/Mod/Fem/CMakeLists.txt b/src/Mod/Fem/CMakeLists.txt index 8c5e0fba52..340e3ba855 100755 --- a/src/Mod/Fem/CMakeLists.txt +++ b/src/Mod/Fem/CMakeLists.txt @@ -563,6 +563,7 @@ SET(FemGuiObjects_SRCS SET(FemGuiTaskPanels_SRCS femtaskpanels/__init__.py + femtaskpanels/task_constraint_bodyheatsource.py femtaskpanels/task_constraint_centrif.py femtaskpanels/task_constraint_electrostaticpotential.py femtaskpanels/task_constraint_flowvelocity.py diff --git a/src/Mod/Fem/Gui/CMakeLists.txt b/src/Mod/Fem/Gui/CMakeLists.txt index 68678bd9ee..f208dfda0f 100755 --- a/src/Mod/Fem/Gui/CMakeLists.txt +++ b/src/Mod/Fem/Gui/CMakeLists.txt @@ -384,6 +384,7 @@ INSTALL(FILES ${FemGuiIcon_SVG} DESTINATION "${CMAKE_INSTALL_DATADIR}/Mod/Fem/Re # Python modules ui files, they are copied as they are, thus the need not to be added to Fem.qrc # see https://forum.freecadweb.org/viewtopic.php?f=10&t=25833 SET(FemGuiPythonUI_SRCS + Resources/ui/BodyHeatSource.ui Resources/ui/ConstraintCentrif.ui Resources/ui/ConstraintTie.ui Resources/ui/ConstraintSectionPrint.ui diff --git a/src/Mod/Fem/Gui/Resources/Fem.qrc b/src/Mod/Fem/Gui/Resources/Fem.qrc index 202cd4e0e2..247d75ab00 100755 --- a/src/Mod/Fem/Gui/Resources/Fem.qrc +++ b/src/Mod/Fem/Gui/Resources/Fem.qrc @@ -152,6 +152,7 @@ translations/Fem_zh-TW.qm + ui/BodyHeatSource.ui ui/ConstraintCentrif.ui ui/ConstraintSectionPrint.ui ui/ConstraintTie.ui diff --git a/src/Mod/Fem/Gui/Resources/ui/BodyHeatSource.ui b/src/Mod/Fem/Gui/Resources/ui/BodyHeatSource.ui new file mode 100644 index 0000000000..76f049dffa --- /dev/null +++ b/src/Mod/Fem/Gui/Resources/ui/BodyHeatSource.ui @@ -0,0 +1,79 @@ + + + Form + + + + 0 + 0 + 350 + 40 + + + + Constraint Properties + + + + + + Body heat in W/kg: + + + + + + + Qt::Horizontal + + + + 130 + 19 + + + + + + + + true + + + + 100 + 20 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + 0.000000000000000 + + + 1000000000000000000000.000000000000000 + + + 50.000000000000000 + + + 0.000000000000000 + + + + + + + + Gui::QuantitySpinBox + QWidget +
Gui/QuantitySpinBox.h
+
+
+ + +
diff --git a/src/Mod/Fem/femcommands/commands.py b/src/Mod/Fem/femcommands/commands.py index 35f196e47f..466f7d3963 100644 --- a/src/Mod/Fem/femcommands/commands.py +++ b/src/Mod/Fem/femcommands/commands.py @@ -187,7 +187,7 @@ class _ConstraintBodyHeatSource(CommandManager): "Creates a FEM constraint body heat source" ) self.is_active = "with_analysis" - self.do_activated = "add_obj_on_gui_noset_edit" + self.do_activated = "add_obj_on_gui_set_edit" class _ConstraintCentrif(CommandManager): diff --git a/src/Mod/Fem/femobjects/constraint_bodyheatsource.py b/src/Mod/Fem/femobjects/constraint_bodyheatsource.py index f858aedb36..4ca679bd6a 100644 --- a/src/Mod/Fem/femobjects/constraint_bodyheatsource.py +++ b/src/Mod/Fem/femobjects/constraint_bodyheatsource.py @@ -40,8 +40,6 @@ class ConstraintBodyHeatSource(base_fempythonobject.BaseFemPythonObject): def __init__(self, obj): super(ConstraintBodyHeatSource, self).__init__(obj) self.add_properties(obj) - # the constraint does not take any references, thus hide this property - obj.setEditorMode("References", 2) def onDocumentRestored(self, obj): self.add_properties(obj) diff --git a/src/Mod/Fem/femsolver/elmer/writer.py b/src/Mod/Fem/femsolver/elmer/writer.py index 48555fe829..4f45dd862e 100644 --- a/src/Mod/Fem/femsolver/elmer/writer.py +++ b/src/Mod/Fem/femsolver/elmer/writer.py @@ -501,15 +501,31 @@ class Writer(object): self._initial(name, "Temperature", temp) self._handled(obj) + def _outputHeatBodyForce(self, obj, name): + heatSource = self._getFromUi(obj.HeatSource, "W/kg", "L^2*T^-3") + if heatSource == 0.0: + # a zero heat would break Elmer (division by zero) + raise WriteError("The body heat source must not be zero!") + self._bodyForce(name, "Heat Source", heatSource) + def _handleHeatBodyForces(self, bodies): - obj = self._getSingleMember("Fem::ConstraintBodyHeatSource") - if obj is not None: - for name in bodies: - heatSource = self._getFromUi(obj.HeatSource, "W/kg", "L^2*T^-3") - # according Elmer forum W/kg is correct - # http://www.elmerfem.org/forum/viewtopic.php?f=7&t=1765 - # 1 watt = kg * m2 / s3 ... W/kg = m2 / s3 - self._bodyForce(name, "Heat Source", heatSource) + bodyHeats = self._getMember("Fem::ConstraintBodyHeatSource") + for obj in bodyHeats: + if obj.References: + for name in obj.References[0][1]: + self._outputHeatBodyForce(obj, name) + self._handled(obj) + else: + # if there is only one body heat without a reference + # add it to all bodies + if len(bodyHeats) == 1: + for name in bodies: + self._outputHeatBodyForce(obj, name) + else: + raise WriteError( + "Several body heat constraints found without reference to a body.\n" + "Please set a body for each body heat constraint." + ) self._handled(obj) def _handleHeatMaterial(self, bodies): diff --git a/src/Mod/Fem/femtaskpanels/task_constraint_bodyheatsource.py b/src/Mod/Fem/femtaskpanels/task_constraint_bodyheatsource.py new file mode 100644 index 0000000000..96b724d363 --- /dev/null +++ b/src/Mod/Fem/femtaskpanels/task_constraint_bodyheatsource.py @@ -0,0 +1,121 @@ +# *************************************************************************** +# * Copyright (c) 2022 Uwe Stöhr * +# * * +# * This file is part of the FreeCAD CAx development system. * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program 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 Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + +__title__ = "FreeCAD FEM constraint body heat source task panel for the document object" +__author__ = "Uwe Stöhr" +__url__ = "https://www.freecadweb.org" + +## @package task_constraint_bodyheatsource +# \ingroup FEM +# \brief task panel for constraint bodyheatsource object + +import FreeCAD +import FreeCADGui + +from femguiutils import selection_widgets + +from femtools import femutils +from femtools import membertools + + +class _TaskPanel(object): + + def __init__(self, obj): + self._obj = obj + + self._paramWidget = FreeCADGui.PySideUic.loadUi( + FreeCAD.getHomePath() + "Mod/Fem/Resources/ui/BodyHeatSource.ui") + self._initParamWidget() + + # geometry selection widget + # start with Solid in list! + self._selectionWidget = selection_widgets.GeometryElementsSelection( + obj.References, + ["Solid", "Face"], + True, + False + ) + + # form made from param and selection widget + self.form = [self._paramWidget, self._selectionWidget] + + analysis = obj.getParentGroup() + self._mesh = None + self._part = None + if analysis is not None: + self._mesh = membertools.get_single_member(analysis, "Fem::FemMeshObject") + if self._mesh is not None: + self._part = femutils.get_part_to_mesh(self._mesh) + self._partVisible = None + self._meshVisible = None + + def open(self): + if self._mesh is not None and self._part is not None: + self._meshVisible = self._mesh.ViewObject.isVisible() + self._partVisible = self._part.ViewObject.isVisible() + self._mesh.ViewObject.hide() + self._part.ViewObject.show() + + def reject(self): + self._restoreVisibility() + FreeCADGui.ActiveDocument.resetEdit() + return True + + def accept(self): + if self._obj.References != self._selectionWidget.references: + self._obj.References = self._selectionWidget.references + self._applyWidgetChanges() + self._obj.Document.recompute() + FreeCADGui.ActiveDocument.resetEdit() + self._restoreVisibility() + return True + + def _restoreVisibility(self): + if self._mesh is not None and self._part is not None: + if self._meshVisible: + self._mesh.ViewObject.show() + else: + self._mesh.ViewObject.hide() + if self._partVisible: + self._part.ViewObject.show() + else: + self._part.ViewObject.hide() + + def _initParamWidget(self): + self._paramWidget.bodyheatQSB.setProperty( + 'value', self._obj.HeatSource) + self._paramWidget.bodyheatQSB.setProperty("unit", "W/kg") + FreeCADGui.ExpressionBinding(self._paramWidget.bodyheatQSB).bind(self._obj, "HeatSource") + + def _applyWidgetChanges(self): + bodyheat = None + try: + bodyheat = self._paramWidget.bodyheatQSB.property('value').getValueAs("W/kg") + except ValueError: + FreeCAD.Console.PrintMessage( + "Wrong input. Not recognised input: '{}' " + "Body heat has not been set.\n" + .format(self._paramWidget.bodyheatQSB.text()) + ) + if bodyheat is not None: + self._obj.HeatSource = float(bodyheat) diff --git a/src/Mod/Fem/femviewprovider/view_constraint_bodyheatsource.py b/src/Mod/Fem/femviewprovider/view_constraint_bodyheatsource.py index ed58a56030..89083b35c8 100644 --- a/src/Mod/Fem/femviewprovider/view_constraint_bodyheatsource.py +++ b/src/Mod/Fem/femviewprovider/view_constraint_bodyheatsource.py @@ -30,10 +30,16 @@ __url__ = "https://www.freecadweb.org" # \ingroup FEM # \brief view provider for the constraint body heat source object +from femtaskpanels import task_constraint_bodyheatsource from . import view_base_femconstraint class VPConstraintBodyHeatSource(view_base_femconstraint.VPBaseFemConstraint): - def getIcon(self): - return ":/icons/FEM_ConstraintBodyHeatSource.svg" + def setEdit(self, vobj, mode=0): + view_base_femconstraint.VPBaseFemConstraint.setEdit( + self, + vobj, + mode, + task_constraint_bodyheatsource._TaskPanel + )