赞
踩
Simple系列算法是求解不可压缩流的主要工具。OpenFoam中提供了SimpleFoam求解器、PisoFoam求解器以完成不可压缩流的求解。
但是OpenFoam中的代码与流体力学教材中的讲述并不一致,导致初学者难以理解代码的含义。笔者推荐一篇Martínez撰写的文章《Influence of momentum interpolation methods on the accuracy and convergence of pressure–velocity coupling algorithms in OpenFOAM》,该文章详细地推导了Simple算法、SimpleC算法和Piso算法,更重要的是其最终形式就是OpenFoam所采用的形式。
本文将直接使用Martínez的推导结果,将结果与OpenFoam中的代码对应,方便初学者理解代码含义。
文中公式(40)表示使用Rhie-Chow插值得到的面心速度
u
e
m
=
α
u
(
∑
N
B
A
N
B
u
N
B
∗
+
B
P
)
e
(
A
P
)
e
−
α
u
Δ
y
(
p
E
m
−
p
P
m
)
(
A
P
)
e
u_{e}^{m}=\frac{\alpha_{u}\left(\sum_{N B} A_{N B} u_{N B}^{*}+B_{P}\right)_{e}}{\left(A_{P}\right)_{e}}-\frac{\alpha_{u} \Delta y\left(p_{E}^{m}-p_{P}^{m}\right)}{\left(A_{P}\right)_{e}}
uem=(AP)eαu(∑NBANBuNB∗+BP)e−(AP)eαuΔy(pEm−pPm)面心速度是用来构造连续方程的。考虑不可压缩流,对于任意一个单元,进出各面心的流量之和必然为0。所以针对一个单元,对上式求和(面积加权),即可得到压力方程
∑
S
f
α
u
Δ
y
(
p
E
m
−
p
P
m
)
(
A
P
)
f
=
∑
S
f
α
u
(
∑
N
B
A
N
B
u
N
B
∗
+
B
P
)
f
(
A
P
)
f
\sum {{S_f}{{{\alpha _u}\Delta y\left( {p_E^m - p_P^m} \right)} \over {{{\left( {{A_P}} \right)}_f}}}} = \sum {{S_f}{{{\alpha _u}{{\left( {\sum\limits_{NB} {{A_{NB}}} u_{NB}^* + {B_P}} \right)}_f}} \over {{{\left( {{A_P}} \right)}_f}}}}
∑Sf(AP)fαuΔy(pEm−pPm)=∑Sf(AP)fαu(NB∑ANBuNB∗+BP)f
现在看看SimpleFoam求解器中的代码
fvm::laplacian(rAtU(), p) == fvc::div(phiHbyA)
代码与公式是严格对应的,rAtU是动量方程对角矩阵Ap的倒数。phiHbyA是H矩阵与Ap之商在面心插值后的结果。总之,代码与公式是严格对应的。
文中公式(48)是使用SimpleC算法和Rhie-Chow插值得到的面心速度
u
e
m
=
α
u
(
∑
N
B
A
N
B
u
N
B
∗
+
B
P
)
e
(
A
P
)
e
−
α
u
(
1
(
A
P
)
e
−
1
(
A
P
−
∑
N
B
A
N
B
)
e
)
Δ
y
(
p
E
m
−
1
−
p
P
m
−
1
)
−
α
u
Δ
y
(
p
E
m
−
p
P
m
)
(
A
P
−
∑
N
B
A
N
B
)
e
u_{e}^{m}=\frac{\alpha_{u}\left(\sum_{N B} A_{N B} u_{N B}^{*}+B_{P}\right)_{e}}{\left(A_{P}\right)_{e}}-\alpha_{u}\left(\frac{1}{\left(A_{P}\right)_{e}}-\frac{1}{\left(A_{P}-\sum_{N B} A_{N B}\right)_{e}}\right) \Delta y\left(p_{E}^{m-1}-p_{P}^{m-1}\right)-\frac{\alpha_{u} \Delta y\left(p_{E}^{m}-p_{P}^{m}\right)}{\left(A_{P}-\sum_{N B} A_{N B}\right)_{e}}
uem=(AP)eαu(∑NBANBuNB∗+BP)e−αu((AP)e1−(AP−∑NBANB)e1)Δy(pEm−1−pPm−1)−(AP−∑NBANB)eαuΔy(pEm−pPm)
同样对面求和之后有
∑
S
f
α
u
Δ
y
(
p
F
m
−
p
P
m
)
(
A
P
−
∑
N
B
A
N
B
)
f
=
∑
S
f
(
α
u
(
∑
N
B
A
N
B
u
N
B
∗
+
B
P
)
f
(
A
P
)
f
−
α
u
(
1
(
A
P
)
f
−
1
(
A
P
−
∑
N
B
A
N
B
)
f
)
Δ
y
(
p
F
m
−
1
−
p
P
m
−
1
)
)
\sum {{S_f}{{{\alpha _u}\Delta y\left( {p_F^m - p_P^m} \right)} \over {{{\left( {{A_P} - \sum\limits_{NB} {{A_{NB}}} } \right)}_f}}}} = \sum {{S_f}\left( {{{{\alpha _u}{{\left( {\sum\limits_{NB} {{A_{NB}}} u_{NB}^* + {B_P}} \right)}_f}} \over {{{\left( {{A_P}} \right)}_f}}} - {\alpha _u}\left( {{1 \over {{{\left( {{A_P}} \right)}_f}}} - {1 \over {{{\left( {{A_P} - \sum\limits_{NB} {{A_{NB}}} } \right)}_f}}}} \right)\Delta y\left( {p_F^{m - 1} - p_P^{m - 1}} \right)} \right)}
∑Sf(AP−NB∑ANB)fαuΔy(pFm−pPm)=∑Sf
(AP)fαu(NB∑ANBuNB∗+BP)f−αu
(AP)f1−(AP−NB∑ANB)f1
Δy(pFm−1−pPm−1)
现在看看SimpleFoam求解器中的代码
SimpleC在Simple算法的基础上对一些系数做了修改,如下
if (simple.consistent())
{
rAtU = 1.0/(1.0/rAU - UEqn.H1());
phiHbyA +=
fvc::interpolate(rAtU() - rAU)*fvc::snGrad(p)*mesh.magSf();
HbyA -= (rAU - rAtU())*fvc::grad(p);
}
rAtU 变成了
1
(
A
P
−
∑
N
B
A
N
B
)
f
{1 \over {{{\left( {{A_P} - \sum\limits_{NB} {{A_{NB}}} } \right)}_f}}}
(AP−NB∑ANB)f1,phiHbyA变成了更复杂的形式。
压力泊松方程依然没有变化
fvm::laplacian(rAtU(), p) == fvc::div(phiHbyA)
代码与公式是严格对应的。
文中公式(55)是使用Piso算法和Rhie-Chow插值得到的面心速度
u
e
m
=
α
u
(
∑
N
B
A
N
B
u
N
B
∗
∗
+
B
P
)
e
(
A
P
)
e
−
α
u
Δ
y
(
p
E
m
−
p
P
m
)
(
A
P
)
e
u_{e}^{m}=\frac{\alpha_{u}\left(\sum_{N B} A_{N B} u_{N B}^{* *}+B_{P}\right)_{e}}{\left(A_{P}\right)_{e}}-\frac{\alpha_{u} \Delta y\left(p_{E}^{m}-p_{P}^{m}\right)}{\left(A_{P}\right)_{e}}
uem=(AP)eαu(∑NBANBuNB∗∗+BP)e−(AP)eαuΔy(pEm−pPm)
代码与公式之间是严格对应的。
事实上,Piso算法与Simple算法的压力修正方程并无区别。在OpenFoam中,Piso算法是为了算瞬态,而Simple算法只能算稳态。二者之间的区别主要在压力修正的计算次序上
Piso算法的流程如下:
while (runTime.loop()) { Info<< "Time = " << runTime.userTimeName() << nl << endl; #include "CourantNo.H" // Pressure-velocity PISO corrector { fvModels.correct(); #include "UEqn.H" // --- PISO loop while (piso.correct()) { #include "pEqn.H" } } viscosity->correct(); turbulence->correct(); runTime.write(); Info<< "ExecutionTime = " << runTime.elapsedCpuTime() << " s" << " ClockTime = " << runTime.elapsedClockTime() << " s" << nl << endl; }
代码中的runTime是物理时间,在每个物理时间步下完成速度预测与若干次压力修正。收敛之后,迈向下一个时间步。
Simple算法的流程如下:
while (simple.loop(runTime)) { Info<< "Time = " << runTime.userTimeName() << nl << endl; fvModels.correct(); // --- Pressure-velocity SIMPLE corrector { #include "UEqn.H" #include "pEqn.H" } viscosity->correct(); turbulence->correct(); runTime.write(); Info<< "ExecutionTime = " << runTime.elapsedCpuTime() << " s" << " ClockTime = " << runTime.elapsedClockTime() << " s" << nl << endl; }
代码中的runTime不是物理时间,而是一个递增的整数,代表迭代次数。每一步迭代都需要求解速度预测方程与压力修正方程。收敛后得到的是稳态解。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。