Skip to content

Commit 13f7b03

Browse files
committed
Fem: Improve constraint BodyHeatSource
1 parent 8ec0916 commit 13f7b03

File tree

7 files changed

+274
-101
lines changed

7 files changed

+274
-101
lines changed

src/Base/UnitsSchemaInternal.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,7 @@ UnitsSchemaInternal::schemaTranslate(const Quantity& quant, double& factor, QStr
551551
}
552552
}
553553
else if (unit == Unit::DissipationRate) {
554-
unitString = QString::fromLatin1("m^2/s^3");
554+
unitString = QString::fromLatin1("W/kg");
555555
factor = 1e6;
556556
}
557557
else if (unit == Unit::InverseLength) {

src/Base/UnitsSchemaMKS.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,7 @@ QString UnitsSchemaMKS::schemaTranslate(const Quantity& quant, double& factor, Q
538538
}
539539
}
540540
else if (unit == Unit::DissipationRate) {
541-
unitString = QString::fromLatin1("m^2/s^3");
541+
unitString = QString::fromLatin1("W/kg");
542542
factor = 1e6;
543543
}
544544
else if (unit == Unit::InverseLength) {

src/Mod/Fem/Gui/Resources/ui/BodyHeatSource.ui

+105-46
Original file line numberDiff line numberDiff line change
@@ -13,56 +13,115 @@
1313
<property name="windowTitle">
1414
<string>Analysis feature properties</string>
1515
</property>
16-
<layout class="QHBoxLayout" name="horizontalLayout">
16+
<layout class="QVBoxLayout" name="horizontalLayout">
1717
<item>
18-
<widget class="QLabel" name="pressureLbl">
19-
<property name="text">
20-
<string>Body heat in W/kg:</string>
18+
<widget class="QGroupBox" name="gpb_heat_source">
19+
<property name="sizePolicy">
20+
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
21+
<horstretch>0</horstretch>
22+
<verstretch>0</verstretch>
23+
</sizepolicy>
2124
</property>
22-
</widget>
23-
</item>
24-
<item>
25-
<spacer name="horizontalSpacer">
26-
<property name="orientation">
27-
<enum>Qt::Horizontal</enum>
28-
</property>
29-
<property name="sizeHint" stdset="0">
30-
<size>
31-
<width>130</width>
32-
<height>19</height>
33-
</size>
34-
</property>
35-
</spacer>
36-
</item>
37-
<item>
38-
<widget class="Gui::QuantitySpinBox" name="bodyheatQSB">
39-
<property name="enabled">
40-
<bool>true</bool>
41-
</property>
42-
<property name="minimumSize">
43-
<size>
44-
<width>100</width>
45-
<height>20</height>
46-
</size>
47-
</property>
48-
<property name="alignment">
49-
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
50-
</property>
51-
<property name="keyboardTracking">
52-
<bool>true</bool>
53-
</property>
54-
<property name="minimum">
55-
<double>0.000000000000000</double>
56-
</property>
57-
<property name="maximum">
58-
<double>1000000000000000000000.000000000000000</double>
59-
</property>
60-
<property name="singleStep">
61-
<double>50.000000000000000</double>
25+
<property name="toolTip">
26+
<string/>
6227
</property>
63-
<property name="value">
64-
<double>0.000000000000000</double>
28+
<property name="title">
29+
<string>Heat Source</string>
6530
</property>
31+
<layout class="QGridLayout" name="g_layout_heat_source">
32+
<item row="0" column="0">
33+
<widget class="QLabel" name="lbl_dissipation_rate">
34+
<property name="text">
35+
<string>Mode:</string>
36+
</property>
37+
</widget>
38+
</item>
39+
<item row="0" column="1">
40+
<widget class="QComboBox" name="cb_mode"/>
41+
</item>
42+
<item row="1" column="0">
43+
<widget class="QLabel" name="lbl_total_power">
44+
<property name="text">
45+
<string>Total Power:</string>
46+
</property>
47+
</widget>
48+
</item>
49+
<item row="1" column="1">
50+
<widget class="Gui::QuantitySpinBox" name="qsb_total_power">
51+
<property name="enabled">
52+
<bool>true</bool>
53+
</property>
54+
<property name="unit" stdset="0">
55+
<string notr="true">W</string>
56+
</property>
57+
<property name="minimumSize">
58+
<size>
59+
<width>100</width>
60+
<height>20</height>
61+
</size>
62+
</property>
63+
<property name="alignment">
64+
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
65+
</property>
66+
<property name="keyboardTracking">
67+
<bool>true</bool>
68+
</property>
69+
<property name="minimum">
70+
<double>0.000000000000000</double>
71+
</property>
72+
<property name="maximum">
73+
<double>1000000000000000000000.000000000000000</double>
74+
</property>
75+
<property name="singleStep">
76+
<double>50.000000000000000</double>
77+
</property>
78+
<property name="value">
79+
<double>0.000000000000000</double>
80+
</property>
81+
</widget>
82+
</item>
83+
<item row="2" column="0">
84+
<widget class="QLabel" name="lbl_dissipation_rate">
85+
<property name="text">
86+
<string>Dissipation Rate:</string>
87+
</property>
88+
</widget>
89+
</item>
90+
<item row="2" column="1">
91+
<widget class="Gui::QuantitySpinBox" name="qsb_dissipation_rate">
92+
<property name="enabled">
93+
<bool>true</bool>
94+
</property>
95+
<property name="unit" stdset="0">
96+
<string notr="true">W/kg</string>
97+
</property>
98+
<property name="minimumSize">
99+
<size>
100+
<width>100</width>
101+
<height>20</height>
102+
</size>
103+
</property>
104+
<property name="alignment">
105+
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
106+
</property>
107+
<property name="keyboardTracking">
108+
<bool>true</bool>
109+
</property>
110+
<property name="minimum">
111+
<double>0.000000000000000</double>
112+
</property>
113+
<property name="maximum">
114+
<double>1000000000000000000000.000000000000000</double>
115+
</property>
116+
<property name="singleStep">
117+
<double>50.000000000000000</double>
118+
</property>
119+
<property name="value">
120+
<double>0.000000000000000</double>
121+
</property>
122+
</widget>
123+
</item>
124+
</layout>
66125
</widget>
67126
</item>
68127
</layout>

src/Mod/Fem/femobjects/constraint_bodyheatsource.py

+57-14
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# ***************************************************************************
22
# * Copyright (c) 2017 Markus Hovorka <[email protected]> *
33
# * Copyright (c) 2020 Bernd Hahnebach <[email protected]> *
4+
# * Copyright (c) 2024 Mario Passaglia <[email protected]> *
45
# * *
56
# * This file is part of the FreeCAD CAx development system. *
67
# * *
@@ -23,34 +24,76 @@
2324
# ***************************************************************************
2425

2526
__title__ = "FreeCAD FEM constraint body heat source document object"
26-
__author__ = "Markus Hovorka, Bernd Hahnebach"
27+
__author__ = "Markus Hovorka, Bernd Hahnebach, Mario Passaglia"
2728
__url__ = "https://www.freecad.org"
2829

2930
## @package constraint_bodyheatsource
3031
# \ingroup FEM
3132
# \brief constraint body heat source object
3233

34+
import FreeCAD
35+
3336
from . import base_fempythonobject
3437

38+
_PropHelper = base_fempythonobject._PropHelper
39+
3540

3641
class ConstraintBodyHeatSource(base_fempythonobject.BaseFemPythonObject):
3742

3843
Type = "Fem::ConstraintBodyHeatSource"
3944

4045
def __init__(self, obj):
4146
super(ConstraintBodyHeatSource, self).__init__(obj)
42-
self.add_properties(obj)
4347

44-
def onDocumentRestored(self, obj):
45-
self.add_properties(obj)
46-
47-
def add_properties(self, obj):
48-
if not hasattr(obj, "HeatSource"):
49-
obj.addProperty(
50-
"App::PropertyFloat",
51-
"HeatSource",
52-
"Base",
53-
"Body heat source"
48+
for prop in self._get_properties():
49+
prop.add_to_object(obj)
50+
51+
52+
def _get_properties(self):
53+
prop = []
54+
55+
prop.append(_PropHelper(
56+
type = "App::PropertyDissipationRate",
57+
name = "DissipationRate",
58+
group = "Constraint Body Heat Source",
59+
doc = "Power dissipated per unit mass",
60+
value = "0 W/kg"
61+
)
62+
)
63+
prop.append(_PropHelper(
64+
type = "App::PropertyPower",
65+
name = "TotalPower",
66+
group = "Constraint Body Heat Source",
67+
doc = "Total power dissipated",
68+
value = "0 W"
5469
)
55-
obj.setPropertyStatus("HeatSource", "LockDynamic")
56-
obj.HeatSource = 0.0
70+
)
71+
prop.append(_PropHelper(
72+
type = "App::PropertyEnumeration",
73+
name = "Mode",
74+
group = "Constraint Body Heat Source",
75+
doc = "Switch quantity input mode",
76+
value = ["Dissipation Rate", "Total Power"]
77+
)
78+
)
79+
80+
return prop
81+
82+
83+
def onDocumentRestored(self, obj):
84+
# update old project with new properties
85+
for prop in self._get_properties():
86+
try:
87+
obj.getPropertyByName(prop.name)
88+
except:
89+
prop.add_to_object(obj)
90+
91+
# migrate old HeatSource property
92+
try:
93+
value = obj.getPropertyByName("HeatSource")
94+
obj.DissipationRate = FreeCAD.Units.Quantity(value, "W/kg")
95+
obj.Mode = "Dissipation Rate"
96+
obj.setPropertyStatus("HeatSource", "-LockDynamic")
97+
obj.removeProperty("HeatSource")
98+
except:
99+
pass

src/Mod/Fem/femsolver/calculix/write_constraint_bodyheatsource.py

+15-8
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525
__author__ = "Mario Passaglia"
2626
__url__ = "https://www.freecad.org"
2727

28-
2928
import FreeCAD
29+
import itertools
3030

3131

3232
def get_analysis_types():
@@ -70,22 +70,29 @@ def write_constraint(f, femobj, bodyheatsource_obj, ccxwriter):
7070

7171
# floats read from ccx should use {:.13G}, see comment in writer module
7272
# search referenced material
73-
ref = bodyheatsource_obj.References
73+
ref = bodyheatsource_obj.References[0]
74+
ref_feat = ref[0]
75+
ref_sub_obj = ref[1][0]
7476
density = None
7577
for mat in ccxwriter.member.mats_linear:
76-
for mat_ref in mat["Object"].References:
77-
if mat_ref[0] == ref[0][0]:
78-
density = FreeCAD.Units.Quantity(mat["Object"].Material["Density"])
79-
break
78+
mat_ref = [*itertools.chain(*[itertools.product([i[0]],i[1]) for i in mat["Object"].References])]
79+
if (ref_feat, ref_sub_obj) in mat_ref:
80+
density = FreeCAD.Units.Quantity(mat["Object"].Material["Density"])
81+
break
8082

8183
if not density:
8284
# search material without references
8385
for mat in ccxwriter.member.mats_linear:
8486
if not mat["Object"].References:
8587
density = FreeCAD.Units.Quantity(mat["Object"].Material["Density"])
88+
break
8689

87-
# get some data from the bodyheatsource_obj (is in power per unit mass)
88-
heat = FreeCAD.Units.Quantity(bodyheatsource_obj.HeatSource, "m^2/s^3") * density
90+
# get data from the bodyheatsource_obj (DissipationRate is in power per unit mass)
91+
if bodyheatsource_obj.Mode == "Dissipation Rate":
92+
heat = bodyheatsource_obj.DissipationRate * density
93+
elif bodyheatsource_obj.Mode == "Total Power":
94+
volume = ref_feat.getSubObject(ref_sub_obj).Volume
95+
heat = bodyheatsource_obj.TotalPower / FreeCAD.Units.Quantity(volume, "mm^3")
8996
# write to file
9097
f.write("*DFLUX\n")
9198
f.write(

src/Mod/Fem/femsolver/elmer/equations/heat_writer.py

+26-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@
3030
## \addtogroup FEM
3131
# @{
3232

33+
import itertools
34+
import FreeCAD
35+
3336
from .. import sifio
3437
from .. import writer as general_writer
3538
from femtools import membertools
@@ -138,7 +141,29 @@ def handleHeatInitial(self, bodies):
138141
self.write.handled(tempObj)
139142

140143
def _outputHeatBodyForce(self, obj, name):
141-
heatSource = self.write.getFromUi(obj.HeatSource, "W/kg", "L^2*T^-3")
144+
if obj.Mode == "Dissipation Rate":
145+
heatSource = obj.DissipationRate.getValueAs("W/kg").Value
146+
147+
elif obj.Mode == "Total Power":
148+
ref = obj.References[0]
149+
ref_feat = ref[0]
150+
ref_sub_obj = ref[1][0]
151+
density = None
152+
for mat in self.write.getMember("App::MaterialObject"):
153+
mat_ref = [*itertools.chain(*[itertools.product([i[0]],i[1]) for i in mat.References])]
154+
if (ref_feat, ref_sub_obj) in mat_ref:
155+
density = FreeCAD.Units.Quantity(mat.Material["Density"])
156+
break
157+
158+
if not density:
159+
# search material without references
160+
for mat in self.write.getMember("App::MaterialObject"):
161+
if not mat.References:
162+
density = FreeCAD.Units.Quantity(mat.Material["Density"])
163+
break
164+
volume = ref_feat.getSubObject(ref_sub_obj).Volume
165+
heatSource = (obj.TotalPower / (density*FreeCAD.Units.Quantity(volume, "mm^3"))).getValueAs("W/kg").Value
166+
142167
if heatSource == 0.0:
143168
# a zero heat would break Elmer (division by zero)
144169
raise general_writer.WriteError("The body heat source must not be zero!")

0 commit comments

Comments
 (0)