Fem: Improve constraint BodyHeatSource
This commit is contained in:
@@ -551,7 +551,7 @@ UnitsSchemaInternal::schemaTranslate(const Quantity& quant, double& factor, QStr
|
||||
}
|
||||
}
|
||||
else if (unit == Unit::DissipationRate) {
|
||||
unitString = QString::fromLatin1("m^2/s^3");
|
||||
unitString = QString::fromLatin1("W/kg");
|
||||
factor = 1e6;
|
||||
}
|
||||
else if (unit == Unit::InverseLength) {
|
||||
|
||||
@@ -538,7 +538,7 @@ QString UnitsSchemaMKS::schemaTranslate(const Quantity& quant, double& factor, Q
|
||||
}
|
||||
}
|
||||
else if (unit == Unit::DissipationRate) {
|
||||
unitString = QString::fromLatin1("m^2/s^3");
|
||||
unitString = QString::fromLatin1("W/kg");
|
||||
factor = 1e6;
|
||||
}
|
||||
else if (unit == Unit::InverseLength) {
|
||||
|
||||
@@ -13,56 +13,115 @@
|
||||
<property name="windowTitle">
|
||||
<string>Analysis feature properties</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<layout class="QVBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="pressureLbl">
|
||||
<property name="text">
|
||||
<string>Body heat in W/kg:</string>
|
||||
<widget class="QGroupBox" name="gpb_heat_source">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<property name="toolTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>130</width>
|
||||
<height>19</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Gui::QuantitySpinBox" name="bodyheatQSB">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="keyboardTracking">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1000000000000000000000.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>50.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.000000000000000</double>
|
||||
<property name="title">
|
||||
<string>Heat Source</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="g_layout_heat_source">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="lbl_dissipation_rate">
|
||||
<property name="text">
|
||||
<string>Mode:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="cb_mode"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="lbl_total_power">
|
||||
<property name="text">
|
||||
<string>Total Power:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="Gui::QuantitySpinBox" name="qsb_total_power">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="unit" stdset="0">
|
||||
<string notr="true">W</string>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="keyboardTracking">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1000000000000000000000.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>50.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="lbl_dissipation_rate">
|
||||
<property name="text">
|
||||
<string>Dissipation Rate:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="Gui::QuantitySpinBox" name="qsb_dissipation_rate">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="unit" stdset="0">
|
||||
<string notr="true">W/kg</string>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="keyboardTracking">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1000000000000000000000.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>50.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2017 Markus Hovorka <m.hovorka@live.de> *
|
||||
# * Copyright (c) 2020 Bernd Hahnebach <bernd@bimstatik.org> *
|
||||
# * Copyright (c) 2024 Mario Passaglia <mpassaglia@cbc.uba.ar> *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
# * *
|
||||
@@ -23,15 +24,19 @@
|
||||
# ***************************************************************************
|
||||
|
||||
__title__ = "FreeCAD FEM constraint body heat source document object"
|
||||
__author__ = "Markus Hovorka, Bernd Hahnebach"
|
||||
__author__ = "Markus Hovorka, Bernd Hahnebach, Mario Passaglia"
|
||||
__url__ = "https://www.freecad.org"
|
||||
|
||||
## @package constraint_bodyheatsource
|
||||
# \ingroup FEM
|
||||
# \brief constraint body heat source object
|
||||
|
||||
import FreeCAD
|
||||
|
||||
from . import base_fempythonobject
|
||||
|
||||
_PropHelper = base_fempythonobject._PropHelper
|
||||
|
||||
|
||||
class ConstraintBodyHeatSource(base_fempythonobject.BaseFemPythonObject):
|
||||
|
||||
@@ -39,18 +44,56 @@ class ConstraintBodyHeatSource(base_fempythonobject.BaseFemPythonObject):
|
||||
|
||||
def __init__(self, obj):
|
||||
super(ConstraintBodyHeatSource, self).__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::PropertyDissipationRate",
|
||||
name = "DissipationRate",
|
||||
group = "Constraint Body Heat Source",
|
||||
doc = "Power dissipated per unit mass",
|
||||
value = "0 W/kg"
|
||||
)
|
||||
)
|
||||
prop.append(_PropHelper(
|
||||
type = "App::PropertyPower",
|
||||
name = "TotalPower",
|
||||
group = "Constraint Body Heat Source",
|
||||
doc = "Total power dissipated",
|
||||
value = "0 W"
|
||||
)
|
||||
)
|
||||
prop.append(_PropHelper(
|
||||
type = "App::PropertyEnumeration",
|
||||
name = "Mode",
|
||||
group = "Constraint Body Heat Source",
|
||||
doc = "Switch quantity input mode",
|
||||
value = ["Dissipation Rate", "Total Power"]
|
||||
)
|
||||
)
|
||||
|
||||
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:
|
||||
prop.add_to_object(obj)
|
||||
|
||||
def add_properties(self, obj):
|
||||
if not hasattr(obj, "HeatSource"):
|
||||
obj.addProperty(
|
||||
"App::PropertyFloat",
|
||||
"HeatSource",
|
||||
"Base",
|
||||
"Body heat source"
|
||||
)
|
||||
obj.setPropertyStatus("HeatSource", "LockDynamic")
|
||||
obj.HeatSource = 0.0
|
||||
# migrate old HeatSource property
|
||||
try:
|
||||
value = obj.getPropertyByName("HeatSource")
|
||||
obj.DissipationRate = FreeCAD.Units.Quantity(value, "W/kg")
|
||||
obj.Mode = "Dissipation Rate"
|
||||
obj.setPropertyStatus("HeatSource", "-LockDynamic")
|
||||
obj.removeProperty("HeatSource")
|
||||
except:
|
||||
pass
|
||||
|
||||
@@ -25,8 +25,8 @@ __title__ = "FreeCAD FEM calculix constraint body heat source"
|
||||
__author__ = "Mario Passaglia"
|
||||
__url__ = "https://www.freecad.org"
|
||||
|
||||
|
||||
import FreeCAD
|
||||
import itertools
|
||||
|
||||
|
||||
def get_analysis_types():
|
||||
@@ -70,22 +70,29 @@ def write_constraint(f, femobj, bodyheatsource_obj, ccxwriter):
|
||||
|
||||
# floats read from ccx should use {:.13G}, see comment in writer module
|
||||
# search referenced material
|
||||
ref = bodyheatsource_obj.References
|
||||
ref = bodyheatsource_obj.References[0]
|
||||
ref_feat = ref[0]
|
||||
ref_sub_obj = ref[1][0]
|
||||
density = None
|
||||
for mat in ccxwriter.member.mats_linear:
|
||||
for mat_ref in mat["Object"].References:
|
||||
if mat_ref[0] == ref[0][0]:
|
||||
density = FreeCAD.Units.Quantity(mat["Object"].Material["Density"])
|
||||
break
|
||||
mat_ref = [*itertools.chain(*[itertools.product([i[0]],i[1]) for i in mat["Object"].References])]
|
||||
if (ref_feat, ref_sub_obj) in mat_ref:
|
||||
density = FreeCAD.Units.Quantity(mat["Object"].Material["Density"])
|
||||
break
|
||||
|
||||
if not density:
|
||||
# search material without references
|
||||
for mat in ccxwriter.member.mats_linear:
|
||||
if not mat["Object"].References:
|
||||
density = FreeCAD.Units.Quantity(mat["Object"].Material["Density"])
|
||||
break
|
||||
|
||||
# get some data from the bodyheatsource_obj (is in power per unit mass)
|
||||
heat = FreeCAD.Units.Quantity(bodyheatsource_obj.HeatSource, "m^2/s^3") * density
|
||||
# get data from the bodyheatsource_obj (DissipationRate is in power per unit mass)
|
||||
if bodyheatsource_obj.Mode == "Dissipation Rate":
|
||||
heat = bodyheatsource_obj.DissipationRate * density
|
||||
elif bodyheatsource_obj.Mode == "Total Power":
|
||||
volume = ref_feat.getSubObject(ref_sub_obj).Volume
|
||||
heat = bodyheatsource_obj.TotalPower / FreeCAD.Units.Quantity(volume, "mm^3")
|
||||
# write to file
|
||||
f.write("*DFLUX\n")
|
||||
f.write(
|
||||
|
||||
@@ -30,6 +30,9 @@ __url__ = "https://www.freecad.org"
|
||||
## \addtogroup FEM
|
||||
# @{
|
||||
|
||||
import itertools
|
||||
import FreeCAD
|
||||
|
||||
from .. import sifio
|
||||
from .. import writer as general_writer
|
||||
from femtools import membertools
|
||||
@@ -138,7 +141,29 @@ class Heatwriter:
|
||||
self.write.handled(tempObj)
|
||||
|
||||
def _outputHeatBodyForce(self, obj, name):
|
||||
heatSource = self.write.getFromUi(obj.HeatSource, "W/kg", "L^2*T^-3")
|
||||
if obj.Mode == "Dissipation Rate":
|
||||
heatSource = obj.DissipationRate.getValueAs("W/kg").Value
|
||||
|
||||
elif obj.Mode == "Total Power":
|
||||
ref = obj.References[0]
|
||||
ref_feat = ref[0]
|
||||
ref_sub_obj = ref[1][0]
|
||||
density = None
|
||||
for mat in self.write.getMember("App::MaterialObject"):
|
||||
mat_ref = [*itertools.chain(*[itertools.product([i[0]],i[1]) for i in mat.References])]
|
||||
if (ref_feat, ref_sub_obj) in mat_ref:
|
||||
density = FreeCAD.Units.Quantity(mat.Material["Density"])
|
||||
break
|
||||
|
||||
if not density:
|
||||
# search material without references
|
||||
for mat in self.write.getMember("App::MaterialObject"):
|
||||
if not mat.References:
|
||||
density = FreeCAD.Units.Quantity(mat.Material["Density"])
|
||||
break
|
||||
volume = ref_feat.getSubObject(ref_sub_obj).Volume
|
||||
heatSource = (obj.TotalPower / (density*FreeCAD.Units.Quantity(volume, "mm^3"))).getValueAs("W/kg").Value
|
||||
|
||||
if heatSource == 0.0:
|
||||
# a zero heat would break Elmer (division by zero)
|
||||
raise general_writer.WriteError("The body heat source must not be zero!")
|
||||
|
||||
@@ -29,6 +29,8 @@ __url__ = "https://www.freecad.org"
|
||||
# \ingroup FEM
|
||||
# \brief task panel for constraint bodyheatsource object
|
||||
|
||||
from PySide import QtCore
|
||||
|
||||
import FreeCAD
|
||||
import FreeCADGui
|
||||
|
||||
@@ -41,15 +43,35 @@ from femtools import membertools
|
||||
class _TaskPanel(object):
|
||||
|
||||
def __init__(self, obj):
|
||||
self._obj = obj
|
||||
self.obj = obj
|
||||
|
||||
self._paramWidget = FreeCADGui.PySideUic.loadUi(
|
||||
self.parameter_widget = FreeCADGui.PySideUic.loadUi(
|
||||
FreeCAD.getHomePath() + "Mod/Fem/Resources/ui/BodyHeatSource.ui")
|
||||
self._initParamWidget()
|
||||
|
||||
self.init_parameter_widget()
|
||||
|
||||
QtCore.QObject.connect(
|
||||
self.parameter_widget.qsb_dissipation_rate,
|
||||
QtCore.SIGNAL("valueChanged(Base::Quantity)"),
|
||||
self.dissipation_rate_changed
|
||||
)
|
||||
|
||||
QtCore.QObject.connect(
|
||||
self.parameter_widget.qsb_total_power,
|
||||
QtCore.SIGNAL("valueChanged(Base::Quantity)"),
|
||||
self.total_power_changed
|
||||
)
|
||||
|
||||
QtCore.QObject.connect(
|
||||
self.parameter_widget.cb_mode,
|
||||
QtCore.SIGNAL("currentIndexChanged(int)"),
|
||||
self.mode_changed
|
||||
)
|
||||
|
||||
|
||||
# geometry selection widget
|
||||
# start with Solid in list!
|
||||
self._selectionWidget = selection_widgets.GeometryElementsSelection(
|
||||
self.selection_widget = selection_widgets.GeometryElementsSelection(
|
||||
obj.References,
|
||||
["Solid", "Face"],
|
||||
True,
|
||||
@@ -57,7 +79,7 @@ class _TaskPanel(object):
|
||||
)
|
||||
|
||||
# form made from param and selection widget
|
||||
self.form = [self._paramWidget, self._selectionWidget]
|
||||
self.form = [self.selection_widget, self.parameter_widget]
|
||||
|
||||
analysis = obj.getParentGroup()
|
||||
self._mesh = None
|
||||
@@ -77,20 +99,22 @@ class _TaskPanel(object):
|
||||
self._part.ViewObject.show()
|
||||
|
||||
def reject(self):
|
||||
self._restoreVisibility()
|
||||
self.restore_visibility()
|
||||
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()
|
||||
self.obj.References = self.selection_widget.references
|
||||
self.obj.DissipationRate = self.dissipation_rate
|
||||
self.obj.TotalPower = self.total_power
|
||||
self.obj.Mode = self.mode
|
||||
|
||||
self.obj.Document.recompute()
|
||||
FreeCADGui.ActiveDocument.resetEdit()
|
||||
self._restoreVisibility()
|
||||
self.restore_visibility()
|
||||
return True
|
||||
|
||||
def _restoreVisibility(self):
|
||||
def restore_visibility(self):
|
||||
if self._mesh is not None and self._part is not None:
|
||||
if self._meshVisible:
|
||||
self._mesh.ViewObject.show()
|
||||
@@ -101,21 +125,36 @@ class _TaskPanel(object):
|
||||
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)
|
||||
def init_parameter_widget(self):
|
||||
self.dissipation_rate = self.obj.DissipationRate
|
||||
self.total_power = self.obj.TotalPower
|
||||
FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_dissipation_rate)\
|
||||
.bind(self.obj, "DissipationRate")
|
||||
self.parameter_widget.qsb_dissipation_rate.setProperty("value", self.dissipation_rate)
|
||||
|
||||
FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_total_power)\
|
||||
.bind(self.obj, "TotalPower")
|
||||
self.parameter_widget.qsb_total_power.setProperty("value", self.total_power)
|
||||
|
||||
self.mode = self.obj.Mode
|
||||
self.mode_enum = self.obj.getEnumerationsOfProperty("Mode")
|
||||
self.parameter_widget.cb_mode.addItems(self.mode_enum)
|
||||
index = self.mode_enum.index(self.mode)
|
||||
self.parameter_widget.cb_mode.setCurrentIndex(index)
|
||||
self.mode_changed(index)
|
||||
|
||||
def dissipation_rate_changed(self, base_quantity_value):
|
||||
self.dissipation_rate = base_quantity_value
|
||||
|
||||
def total_power_changed(self, base_quantity_value):
|
||||
self.total_power = base_quantity_value
|
||||
|
||||
def mode_changed(self, index):
|
||||
self.mode = self.mode_enum[index]
|
||||
if self.mode == "Dissipation Rate":
|
||||
self.parameter_widget.qsb_dissipation_rate.setEnabled(True)
|
||||
self.parameter_widget.qsb_total_power.setEnabled(False)
|
||||
elif self.mode == "Total Power":
|
||||
self.parameter_widget.qsb_dissipation_rate.setEnabled(False)
|
||||
self.parameter_widget.qsb_total_power.setEnabled(True)
|
||||
|
||||
Reference in New Issue
Block a user