twoPhaseEulerFoam 全解读之二(转)

twoPhaseEulerFoam 全解读之二(

本系列将对OpenFOAM-2.1.1 中的 twoPhaseEulerFoam 求解器进行完全解读,共分三部分:方程推导,代码解读,补充说明。本篇对 twoPhaseEulerFoam 中的 UEqn.H 和 pEqn.H 中的代码进行详细地的解读。

代码解读

UEqn

前一篇导出了分散相的动量守恒方程
( 1 + α b ρ b ρ a C v m ) ( ∂ U a ∂ t + U a ⋅ ∇ U a ) − ∇ ⋅ [ ν e f f ∇ U a ] + ∇ ⋅ [ R c , a ] + ∇ ( α a ) α a ⋅ [ − ν e f f ∇ U a + R c , a ] = − α b ρ a K U a − α b ρ a { C l ( α b ρ b + α a ρ a ) U r × ( ∇ × U ) − C v m ρ b [ ∂ U b ∂ t + U b ⋅ ∇ U b ] } − ∇ p ρ a + g + α b ρ a K U b \begin{aligned} &(1+\frac{\alpha_b \rho_b}{\rho_a} C_{vm})(\frac{\partial U_a}{\partial t} + U_a\cdot \nabla U_a ) -\nabla \cdot \left[ \nu_{eff} \nabla U_a \right ] + \nabla \cdot \left[ R_{c,a}\right] + \frac{\nabla(\alpha_a)}{\alpha_a} \cdot \left[ -\nu_{eff}\nabla U_a + R_{c,a}\right] \\ = & -\frac{\alpha_b}{\rho_a} K U_a - \frac{\alpha_b}{\rho_a} \left\{ {C_l (\alpha_b \rho_b + \alpha_a \rho_a) U_r \times (\nabla \times U) - C_{vm}\rho_b\left[ {\frac{\partial U_b}{\partial t} + U_b \cdot \nabla U_b }\right] } \right\} -\frac{\nabla p}{\rho_a} + g + \frac{\alpha_b}{\rho_a} K U_b \end{aligned} =(1+ρaαbρbCvm)(tUa+UaUa)[νeffUa]+[Rc,a]+αa(αa)[νeffUa+Rc,a]ρaαbKUaρaαb{Cl(αbρb+αaρa)Ur×(×U)Cvmρb[tUb+UbUb]}ρap+g+ρaαbKUb
这一篇分析twoPhaseEulerFoam求解器是怎么来对动量方程进行离散的,以及,如果通过构建压力方程来对速度进行修正以保证两相的连续性。

注意上述动量方程中,有两项还需要处理一下:
U a ⋅ ∇ U a = ∇ ⋅ ( U a U a ) − U a ( ∇ ⋅ U a ) U_a \cdot \nabla U_a=\nabla\cdot(U_aU_a)-U_a(\nabla\cdot U_a) UaUa=(UaUa)Ua(Ua)

∇ ( α a ) α a ⋅ [ − ν e f f ∇ U a ] = ∇ ⋅ [ − ν e f f ( ∇ α a ) α a U a ] − U a ( ∇ ⋅ ( − ν e f f ∇ α a α a ) ) \frac{\nabla(\alpha_a)}{\alpha_a}\cdot\left[-\nu_{eff} \nabla U_a\right] = \nabla \cdot\left[ -\nu_{eff}\frac{(\nabla \alpha_a)}{\alpha_a} U_a \right]-U_a\left(\nabla\cdot(-\nu_{eff}\frac{\nabla \alpha_a}{\alpha_a}) \right) αa(αa)[νeffUa]=[νeffαa(αa)Ua]Ua((νeffαaαa))
转化前后的形式从数学上来等价的,但是在有限体积离散过程中,转化前的 U a ⋅ ∇ U a U_a \cdot \nabla U_a UaUa ∇ ( α a ) α a ⋅ [ − ν e f f ∇ U a ] \frac{\nabla(\alpha_a)}{\alpha_a}\cdot\left[-\nu_{eff} \nabla U_a\right] αa(αa)[νeffUa] 对于 U a U_a Ua来说是非守恒的,转化后的形式是守恒的(参考这篇文献,注意这样转化后,动量方程空间上是守恒的,但时间上仍是不守恒的,这个帖子也有一些有价值的信息)。

这样转化以后,得到的动量方程就跟twoPhaseEulerFoam里的定义是一模一样了:

在这里插入图片描述

下面将动量方程的每一项与twoPhaseEulerFoam的UEqn.H的代码一一对应。

(scalar(1) + Cvm*rhob*beta/rhoa)*
            (
                fvm::ddt(Ua)
              + fvm::div(phia, Ua, "div(phia,Ua)")
              - fvm::Sp(fvc::div(phia), Ua)
            )

fvm::ddt(Ua)对应 ∂ U a ∂ t \frac{\partial U_a}{\partial t} tUa,phia定义为fvc::interpolate(Ua) & mesh.Sf(),于是fvm::div(phia, Ua, “div(phia,Ua)”) 和 fvm::Sp(fvc::div(phia), Ua) 便分别对应 ∇ ⋅ ( U a U a ) \nabla\cdot(U_aU_a) (UaUa) U a ( ∇ ⋅ U a ) U_a(\nabla\cdot U_a) Ua(Ua)了 [ 注一 ]。

- fvm::laplacian(nuEffa, Ua)
+ fvc::div(Rca)
+ fvm::div(phiRa, Ua, "div(phia,Ua)")
- fvm::Sp(fvc::div(phiRa), Ua)

fvm::laplacian(nuEffa, Ua)对应 ∇ ⋅ [ ν e f f ∇ U a ] \nabla \cdot \left[ \nu_{eff} \nabla U_a \right ] [νeffUa],fvc::div(Rca)对应 ∇ ⋅ [ R c , a ] \nabla \cdot \left[ R_{c,a}\right] [Rc,a]
phiRa的定义是

-fvc::interpolate(nuEffa)*mesh.magSf()*fvc::snGrad(alpha)
            /fvc::interpolate(alpha + scalar(0.001))

相当于 − ν e f f ∇ α a α a -\nu_{eff}\frac{\nabla \alpha_a}{\alpha_a} νeffαaαa [ 注二 ]。
于是 fvm::div(phiRa, Ua, “div(phia,Ua)”) 和 fvm::Sp(fvc::div(phiRa), Ua) 便分别对应 $\nabla \cdot\left[ -\nu_{eff} \frac{(\nabla \alpha_a)}{\alpha_a}(\nabla U_a)\right] $ 和 U a ( ∇ ⋅ ( − ν e f f ∇ α a α a ) ) U_a\left(\nabla\cdot(-\nu_{eff}\frac{\nabla \alpha_a}{\alpha_a}) \right) Ua((νeffαaαa))

(fvc::grad(alpha)/(fvc::average(alpha) + scalar(0.001)) & Rca)

对应 ∇ ( α a ) α a ⋅ [ R c , a ] \frac{\nabla(\alpha_a)}{\alpha_a} \cdot \left[ R_{c,a}\right] αa(αa)[Rc,a],其中&运算符已重载为计算矢量与张量的点乘积 [ 注三 ]。

 ==
//  g                          // Buoyancy term transfered to p-equation
- fvm::Sp(beta/rhoa*K, Ua)
//+ beta/rhoa*K*Ub             // Explicit drag transfered to p-equation
- beta/rhoa*(liftCoeff - Cvm*rhob*DDtUb)
        );

fvm::Sp(beta/rhoaK, Ua)对应 α b ρ a K U a \frac{\alpha_b}{\rho_a} K U_a ρaαbKUa,beta/rhoa(liftCoeff - CvmrhobDDtUb) 对应
α b ρ a { C l ( α b ρ b + α a ρ a ) U r × ( ∇ × U ) − C v m ρ b [ ∂ U b ∂ t + U b ⋅ ∇ U b ] } \frac{\alpha_b}{\rho_a} \left\{ {C_l (\alpha_b \rho_b + \alpha_a \rho_a) U_r \times (\nabla \times U) - C_{vm}\rho_b\left[ {\frac{\partial U_b}{\partial t} + U_b \cdot \nabla U_b }\right] } \right\} ρaαb{Cl(αbρb+αaρa)Ur×(×U)Cvmρb[tUb+UbUb]}
其中变量liftCoeff定义为

volVectorField liftCoeff(Cl*(beta*rhob + alpha*rhoa)*(Ur ^ fvc::curl(U)));

DDtUb定义为

DDtUb =
        fvc::ddt(Ub)
      + fvc::div(phib, Ub)
      - fvc::div(phib)*Ub;

重力 g g g 以及曳力的显式项 $\frac{\alpha_b}{\rho_a} K U_b $ 如注释所述,将会在 pEqn 中考虑,压力梯度项 ∇ p ρ a \frac{\nabla p}{\rho_a} ρap 则将在 pEqn 中用来约束两相的连续性。
至此动量方程的每一项都与UEqn.H的代码对应起来了。


pEqn

压力方程的作用是修正两相速度 U a U_a Ua U b U_b Ub以使速度满足连续性方程。将两相的连续性方程加起来,得到总体的连续性方程如下 [ 注四 ]:
在这里插入图片描述

由于 α a + α b = 1 \alpha_a+\alpha_b=1 αa+αb=1,于是两相连续性方程等价于
∇ ⋅ ( α a U a + α b U b ) = 0 \nabla \cdot (\alpha_a U_a+\alpha_b U_b) = 0 (αaUa+αbUb)=0

再来看压力方程是如何构建起来的。
完整的动量方程离散后,可以写作如下的统一形式:
a p , a U p , a = H ( U a ) − ∇ p ρ a + α b ρ a K U b + g a_{p,a}U_{p,a}=H(U_a)-\frac{\nabla p}{\rho_a}+\frac{\alpha_b}{\rho_a} K U_b +g ap,aUp,a=H(Ua)ρap+ρaαbKUb+g

a p , b U p , b = H ( U b ) − ∇ p ρ b + α a ρ b K U a + g a_{p,b}U_{p,b}=H(U_b)-\frac{\nabla p}{\rho_b}+\frac{\alpha_a}{\rho_b} K U_a +g ap,bUp,b=H(Ub)ρbp+ρbαaKUa+g
其中 H ( U a ) H(U_a) H(Ua) H ( U b ) H(U_b) H(Ub) 包含了动量方程中除 压力梯度项,显式曳力项以及重力项以后所有项的贡献。
由此离散方程可以得到 U a U_a Ua U b U_b Ub 的表达式如下:
U a = 1 a p , a H ( U a ) − ∇ p a p , a ρ a + α b a p , a ρ a K U b + 1 a p , a g U_{a}=\frac{1}{a_{p,a}}H(U_a)-\frac{\nabla p}{a_{p,a}\rho_a}+\frac{\alpha_b}{ a_{p,a} \rho_a} K U_b +\frac{1}{a_{p,a}} g Ua=ap,a1H(Ua)ap,aρap+ap,aρaαbKUb+ap,a1g

U b = 1 a p , b H ( U b ) − ∇ p a p , b ρ b + α a a p , b ρ b K U a + 1 a p , b g U_{b}=\frac{1}{a_{p,b}}H(U_b)-\frac{\nabla p}{a_{p,b}\rho_b}+\frac{\alpha_a}{ a_{p,b} \rho_b} K U_a +\frac{1}{a_{p,b}} g Ub=ap,b1H(Ub)ap,bρbp+ap,bρbαaKUa+ap,b1g

如果此 U a U_a Ua U b U_b Ub 是方程组的解,那么它们必须满足整体的连续性方程,即

在这里插入图片描述
将压力梯度项移到方程的一边,得到
在这里插入图片描述
这便是压力修正方程的原型。
在pEqn.H中,压力方程其实修正的是界面通量,压力方程迭代收敛以后能保证界面通量的连续性。所以,散度表达式需要根据高斯定理写成界面通量之和的形式:
在这里插入图片描述
下标 f _f f 表示该项将要在代码中用界面上的变量来表示,在OpenFOAM中,即surfaceScalarField, S f S_f Sf 表示界面的面积矢量,下面的公式里也是一样。
在这里插入图片描述
以及
∇ ⋅ [ ( α a a p , a ρ a + α b a p , b ρ b ) ∇ p ] = ∑ f ( α a a p , a ρ a + α b a p , b ρ b ) f ( ∇ p ) ⋅ S f \nabla \cdot \left[ (\frac{\alpha_a }{a_{p,a}\rho_a} + \frac{\alpha_b }{a_{p,b}\rho_b}) \nabla p \right ] = \sum_f (\frac{\alpha_a }{a_{p,a}\rho_a} + \frac{\alpha_b }{a_{p,b}\rho_b})_f (\nabla p) \cdot S_f [(ap,aρaαa+ap,bρbαb)p]=f(ap,aρaαa+ap,bρbαb)f(p)Sf
下面是pEqn定义了几个跟界面通量有关的变量:

surfaceScalarField alphaf(fvc::interpolate(alpha));
surfaceScalarField betaf(scalar(1) - alphaf);

volScalarField rUaA(1.0/UaEqn.A());
volScalarField rUbA(1.0/UbEqn.A());

phia == (fvc::interpolate(Ua) & mesh.Sf());
phib == (fvc::interpolate(Ub) & mesh.Sf());

rUaAf = fvc::interpolate(rUaA);
surfaceScalarField rUbAf(fvc::interpolate(rUbA));

Ua = rUaA*UaEqn.H();
Ub = rUbA*UbEqn.H();

surfaceScalarField phiDraga
(
    fvc::interpolate(beta/rhoa*K*rUaA)*phib + rUaAf*(g & mesh.Sf())
);


surfaceScalarField phiDragb
(
    fvc::interpolate(alpha/rhob*K*rUbA)*phia + rUbAf*(g & mesh.Sf())
);


phia = (fvc::interpolate(Ua) & mesh.Sf()) + fvc::ddtPhiCorr(rUaA, Ua, phia) + phiDraga;
phib = (fvc::interpolate(Ub) & mesh.Sf()) + fvc::ddtPhiCorr(rUbA, Ub, phib) + phiDragb;

phi = alphaf*phia + betaf*phib;

surfaceScalarField Dp
(
    "(rho*(1|A(U)))",
    alphaf*rUaAf/rhoa + betaf*rUbAf/rhob
);

phiDraga 和 phiDragb 分别对应 ( α b K a p , a ρ a ) f U b ⋅ S f + ( 1 a p , a ) f g ⋅ S f (\frac{\alpha_b K}{ a_{p,a} \rho_a})_f U_b \cdot S_f +(\frac{1}{a_{p,a}})_f g \cdot S_f (ap,aρaαbK)fUbSf+(ap,a1)fgSf ( α a K a p , b ρ b ) f U a ⋅ S f + ( 1 a p , b ) f g ⋅ S f (\frac{\alpha_a K}{ a_{p,b} \rho_b})_f U_a \cdot S_f +(\frac{1}{a_{p,b}})_f g \cdot S_f (ap,bρbαaK)fUaSf+(ap,b1)fgSf

由于13-14行的定义,28-29行中的 (fvc::interpolate(Ua) & mesh.Sf()) 和 (fvc::interpolate(Ub) & mesh.Sf()) 便分别对应的是 ( 1 a p , a ) f H ( U a ) ⋅ S f (\frac{1}{a_{p,a}})_f H(U_a)\cdot S_f (ap,a1)fH(Ua)Sf ( 1 a p , b ) f H ( U b ) ⋅ S f (\frac{1}{a_{p,b}})_f H(U_b)\cdot S_f (ap,b1)fH(Ub)Sf

有了上面的定义,可以看出31行定义的phi=alphafphia + betafphib便表示了压力方程的左边。

再看33-36行定义的Dp,很显然,表示的是压力方程右边的 ( α a a p , a ρ a + α b a p , b ρ b ) f (\frac{\alpha_a }{a_{p,a}\rho_a} + \frac{\alpha_b }{a_{p,b}\rho_b})_f (ap,aρaαa+ap,bρbαb)f

有了以上的定义,便可以构建用于修正界面通量的压力方程了:

fvScalarMatrix pEqn
  (
     fvm::laplacian(Dp, p) == fvc::div(phi)
  );

如上所述,pEqn收敛以后,得到的就是满足连续性的界面通量了,然后再利用求得的界面通量来修正两相的速度,便得到了满足两相连续性的速度:

Ua += fvc::reconstruct(phiDraga - rUaAf*SfGradp/rhoa);
Ua.correctBoundaryConditions();

Ub += fvc::reconstruct(phiDragb - rUbAf*SfGradp/rhob);
Ub.correctBoundaryConditions();

U = alpha*Ua + beta*Ub;

注意,Ua和Ub为什么是这样来修正呢?回想上面变量定义那个代码段的13-14行,这两行将Ua和Ub分别定义成了 1 a p , a H ( U a ) \frac{1}{a_{p,a}} H(U_a) ap,a1H(Ua) 1 a p , b H ( U b ) \frac{1}{a_{p,b}} H(U_b) ap,b1H(Ub)
回想Ua和Ub的离散方程的统一形式
U a = 1 a p , a H ( U a ) − ∇ p a p , a ρ a + α b a p , a ρ a K U b + 1 a p , a g U_{a}=\frac{1}{a_{p,a}}H(U_a)-\frac{\nabla p}{a_{p,a}\rho_a}+\frac{\alpha_b}{ a_{p,a} \rho_a} K U_b +\frac{1}{a_{p,a}} g Ua=ap,a1H(Ua)ap,aρap+ap,aρaαbKUb+ap,a1g

U b = 1 a p , b H ( U b ) − ∇ p a p , b ρ b + α a a p , b ρ b K U a + 1 a p , b g U_{b}=\frac{1}{a_{p,b}}H(U_b)-\frac{\nabla p}{a_{p,b}\rho_b}+\frac{\alpha_a}{ a_{p,b} \rho_b} K U_a +\frac{1}{a_{p,b}} g Ub=ap,b1H(Ub)ap,bρbp+ap,bρbαaKUa+ap,b1g

会发现13-14行定义的Ua和Ub都少了几项,所以缺了的这几项的贡献需要在速度修正步骤加回来,而Ua+=后面的fvc::reconstruct(phiDraga - rUaAf*SfGradp/rhoa)刚好就对应着Ua缺少的那几项。因为经过压力方程修正以后,界面通量是连续的,所以,将缺失的几项对应的界面通量通过reconstruct函数从界面通量重构从对体中心的速度的贡献,便得到了满足连续性的体中心速度了。对Ub也是同样的。

经过以上步骤,便能得到满足整体连续性的两相速度Ua 和 Ub了。


注释

【注一】:OpenFOAM 里的div函数,字面意义上看起来好像是散度的意思,实际上,div函数执行的是加和运算。举例说,对于fvc::div(phia),phia是surfaceScalarField,其值为(fvc::interpolate(Ua) & mesh.Sf()),即将存储在体中心的Ua插值到每个网格对应的面的面心,然后用面心的速度与该面的面积矢量点乘。从代码中看,fvc::div(phia)对应的是 ∇ ⋅ U a \nabla \cdot U_a Ua,根据高斯定理,也就是 ∑ f ( U a ) f ⋅ S f \sum_f (U_a)_f \cdot S_f f(Ua)fSf,而phia对应着 ( U a ) f ⋅ S f (U_a)_f \cdot S_f (Ua)fSf,所以,fvc::div(phia)实际进行的运算是将包围每个网格的面上的通量加起来。更详细的说明见我的另一篇博文。
【注二】:注意这里的 ∇ α a α a \frac{\nabla \alpha_a}{\alpha_a} αaαa 在代码中的表示方法,详细说明见我的另一篇博文。
【注三】:注意这里的 ∇ α a α a \frac{\nabla \alpha_a}{\alpha_a} αaαa 在代码中的表示方法,以及与上一个 ∇ α a α a \frac{\nabla \alpha_a}{\alpha_a} αaαa 的区别,详细说明见我的另一篇博文。
【注四】:这里说的总体的连续性方程指的是总体体积的守恒,而不是总体质量的守恒,这二者的差异见Henrik Rusche 的 PHD 论文 P112 的说明。


参考资料
  • Henrik Rusche, PHD Thesis, Computational Fluid Dynamics of Dispersed Two-Phase Flows at High Phase Fractions, Imperial College of Science, Technology & Medicine, Department of Mechanical Engineering, 2002
  • https://openfoamwiki.net/index.php/BubbleFoam
  • http://www.cfd-online.com/Forums/openfoam-solving/71141-rewriting-twophaseeulerfoam-conservative-form.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值