本系列来看一下 OpenFOAM 中的热物理类。热物理类比较繁杂,这里先看一下纯物质的热物理模型。本篇先来看看热物理类在求解器中的接口,以2.3.x 版的 twoPhaseEulerFoam
为例。
twoPhaseEulerFoam
中的热物理类的接口在 phaseModel
类中声明:1
2
3
4//- Thermophysical properties
autoPtr<rhoThermo> thermo_;
thermo_(rhoThermo::New(fluid.mesh(), name_))
可见,接口是 rhoThermo
类的指针。
接着看 rhoThermo
类的 New
函数。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15//- Selector
static autoPtr<rhoThermo> New
(
const fvMesh&,
const word& phaseName=word::null
);
Foam::autoPtr<Foam::rhoThermo> Foam::rhoThermo::New
(
const fvMesh& mesh,
const word& phaseName
)
{
return basicThermo::New<rhoThermo>(mesh, phaseName);
}
这里调用的是 basicThermo
类的 New
函数。 这里先提一下继承关系,后面再细说:rhoThermo
类继承自 fluidThermo
, fluidThermo
类继承自 basicThermo
。
1 | //- Generic New for each of the related thermodynamics packages |
根据 RTS 机制的惯例, New
函数的功能是模型选择(selector
),即根据用户指定的关键字来选择对应的模型。 New
函数中先定义了一个 IOdictionary
类的对象, thermoDict
,这个对象对应的正是热物理类的配置文件 thermophysicalProperties
。New
函数里调用了 lookupThermo
函数,这个函数是关键:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105// basicThermoTemplates.C
template<class Thermo, class Table>
typename Table::iterator Foam::basicThermo::lookupThermo
(
const dictionary& thermoDict,
Table* tablePtr
)
{
word thermoTypeName;
if (thermoDict.isDict("thermoType"))
{
const dictionary& thermoTypeDict(thermoDict.subDict("thermoType"));
Info<< "Selecting thermodynamics package " << thermoTypeDict << endl;
const int nCmpt = 7;
const char* cmptNames[nCmpt] =
{
"type",
"mixture",
"transport",
"thermo",
"equationOfState",
"specie",
"energy"
};
// Construct the name of the thermo package from the components
thermoTypeName =
word(thermoTypeDict.lookup("type")) + '<'
+ word(thermoTypeDict.lookup("mixture")) + '<'
+ word(thermoTypeDict.lookup("transport")) + '<'
+ word(thermoTypeDict.lookup("thermo")) + '<'
+ word(thermoTypeDict.lookup("equationOfState")) + '<'
+ word(thermoTypeDict.lookup("specie")) + ">>,"
+ word(thermoTypeDict.lookup("energy")) + ">>>";
// Lookup the thermo package
typename Table::iterator cstrIter = tablePtr->find(thermoTypeName);
// Print error message if package not found in the table
if (cstrIter == tablePtr->end())
{
FatalErrorIn(Thermo::typeName + "::New")
<< "Unknown " << Thermo::typeName << " type " << nl
<< "thermoType" << thermoTypeDict << nl << nl
<< "Valid " << Thermo::typeName << " types are:" << nl << nl;
// Get the list of all the suitable thermo packages available
wordList validThermoTypeNames
(
tablePtr->sortedToc()
);
// Build a table of the thermo packages constituent parts
// Note: row-0 contains the names of constituent parts
List<wordList> validThermoTypeNameCmpts
(
validThermoTypeNames.size() + 1
);
validThermoTypeNameCmpts[0].setSize(nCmpt);
forAll(validThermoTypeNameCmpts[0], j)
{
validThermoTypeNameCmpts[0][j] = cmptNames[j];
}
// Split the thermo package names into their constituent parts
forAll(validThermoTypeNames, i)
{
validThermoTypeNameCmpts[i+1] =
Thermo::splitThermoName(validThermoTypeNames[i], nCmpt);
}
// Print the table of available packages
// in terms of their constituent parts
printTable(validThermoTypeNameCmpts, FatalError);
FatalError<< exit(FatalError);
}
return cstrIter;
}
else
{
thermoTypeName = word(thermoDict.lookup("thermoType"));
Info<< "Selecting thermodynamics package " << thermoTypeName << endl;
typename Table::iterator cstrIter = tablePtr->find(thermoTypeName);
if (cstrIter == tablePtr->end())
{
FatalErrorIn(Thermo::typeName + "::New")
<< "Unknown " << Thermo::typeName << " type "
<< thermoTypeName << nl << nl
<< "Valid " << Thermo::typeName << " types are:" << nl
<< tablePtr->sortedToc() << nl
<< exit(FatalError);
}
return cstrIter;
}
}
可见, loopupThermo
分两种情况处理,一种是 thermophysicalProperties
文件里有一个名为 thermoType
的 subdict
,例如1
2
3
4
5
6
7
8
9
10thermoType
{
type heRhoThermo;
mixture pureMixture;
transport const;
thermo hConst;
equationOfState perfectGas;
specie specie;
energy sensibleInternalEnergy;
}
这种情况下, subdict
里的 7 个关键字将逐一读入,最终将合并起来,得到一个字符串,并赋值给 thermoTypeName
以上面的那种情况为例,最终得到的thermoTypeName
为1
heRhoThermo<pureMixture<const<hConst<perfectGas<specie>>,sensibleInternalEnergy>>>
然后,根据这个关键词,从 hashTable 中找到对应的元素。如果找不到对应的,则报错,并输出所有可选的方案(由 splitThermoName
和 printTable
两个函数完成,细节这里暂且不表)。
另一种情况,直接从 thermophysicalProperties
读取 thermoType
对应的字符串并赋值给 thermoTypeName
,然后据此来从 hashTable 中找到对应的元素。
OpenFOAM 自带的算例中,thermophysicalProperties
文件绝大部分采用前一种方式,因为更直观。后一种方式我在 OpenFOAM-2.3.x 版中只找到一个例子:tutorials/mesh/foamyQuadMesh/OpenCFD/constant/thermophysicalProperties1
thermoType hePsiThermo<pureMixture<const<hConst<perfectGas<specie>>,sensibleEnthalpy>>>;
至此,大致就知道热物理类的接口定义是怎么回事了。但是,这个存储了可选模型的 hashTable 里有哪些内容,又是怎么构建起来的,还有待进一步深入探索。另外,从 thermoType
对应的字符串的样式,能猜到最终热物理类的接口 thermo_
指向的可能是类似 heRhoThermo
类的对象,而且这些类多半是模板类,并有着复杂的继承派生关系,这部分也还有待深入探索。