高分辨率格式
简介
一般地,有限体积法将物理量存储在体心。但是如果需要完成对流项的离散,那么必须将物理量插值到面心。如果使用线性插值(一般也称作中心差分)会导致在较大贝克莱数下发生非物理震荡。所以人们提出了一阶迎风格式,直接用上游的体心物理量作为面心物理量。一阶迎风格式不会发生非物理振荡,但是精度很低。为了提高精度,人们又提出了大量高阶格式(HO),遗憾的是,这些高阶格式并不能保证物理单调性。
在高阶格式(HO)的基础上,人们提出了高分辨率格式(HR)。其中以TVD格式为主要代表(也是OpenFOAM所采用的)。其原理是设置一个通量限制器(limiter),当物理量变化剧烈时退回一阶迎风格式,当物理量变化平缓时返回高阶格式,有效避免振荡。
理论推导
如下图所示,考虑一个单元面
在OpenFOAM中任何一个内部面都有一个owner单元(标记为O)和一个neighbour单元(标记为N),面的法向量由O指向N
面心的物理量可以由体心线性表示
ϕ
f
=
λ
ϕ
O
+
(
1
−
λ
)
ϕ
N
(1)
{\phi _{\rm{f}}} = \lambda {\phi _O} + \left( {1 - \lambda } \right){\phi _N} \tag{1}
ϕf=λϕO+(1−λ)ϕN(1)式中
λ
\lambda
λ称为权重,在OpenFOAM中也是用
λ
\lambda
λ这个希腊字母的。
特殊地,对于均匀网格,如果采用中心差分(CD),那么 λ = λ C D = 0.5 \lambda=\lambda_{\rm{CD}}=0.5 λ=λCD=0.5。
高分辨率格式使用通量限制器
ψ
\psi
ψ控制权重,其计算方式为:
(1)如果流向为从O到N,那么
λ
=
λ
C
D
ψ
+
(
1
−
ψ
)
,
O
→
N
\lambda = {\lambda _{{\rm{CD}}}}\psi + \left( {1 - \psi } \right),O \to N
λ=λCDψ+(1−ψ),O→N
(2)如果流向为从N到O,那么
λ
=
λ
C
D
ψ
,
N
→
O
\lambda = {\lambda _{{\rm{CD}}}}\psi ,N \to O
λ=λCDψ,N→O式中
λ
C
D
\lambda_{\rm{CD}}
λCD是使用中心差分(CD)得到的权重。需要注意,通量限制器
ψ
\psi
ψ是一个场,任何一个单元面都应该有自己的
ψ
\psi
ψ值。
接下来将权重表达式带入式(1)中,化简得到
(1)如果流向为从O到N,那么
ϕ
f
=
ϕ
O
+
ψ
2
(
ϕ
N
−
ϕ
O
)
{\phi _{\rm{f}}} = {\phi _O} + {\psi \over 2}\left( {{\phi _N} - {\phi _O}} \right)
ϕf=ϕO+2ψ(ϕN−ϕO)
(1)如果流向为从N到O,那么
ϕ
f
=
ϕ
N
+
ψ
2
(
ϕ
O
−
ϕ
N
)
{\phi _{\rm{f}}} = {\phi _N} + {\psi \over 2}\left( {{\phi _O} - {\phi _N}} \right)
ϕf=ϕN+2ψ(ϕO−ϕN)
其物理意义是非常明确的,第一项表示一阶迎风,即上游的体心物理量,由于一阶迎风有较大的数值粘性,第二项做出修正,该修正可以使数值粘性减小,最终达到二阶精度。
通量限制器
ψ
\psi
ψ的要求是:当物理量变化剧烈时退回一阶迎风格式,当物理量变化平缓时返回高阶格式,那么需要引入一个无量纲数
r
r
r来检测物理量变化是否剧烈,定量描述剧烈程度。不同的高阶格式即就是设计不同的
ψ
(
r
)
\psi(r)
ψ(r)函数。这里给出
r
r
r的定义
r
=
ϕ
c
e
n
−
ϕ
u
p
ϕ
d
o
w
n
−
ϕ
c
e
n
(2)
r = {{{\phi _{cen}} - {\phi _{up}}} \over {{\phi _{down - }}{\phi _{cen}}}} \tag{2}
r=ϕdown−ϕcenϕcen−ϕup(2)
下角标
c
e
n
cen
cen表示所考察面的上游单元,
u
p
up
up是
c
e
n
cen
cen的上游单元,
d
o
w
n
down
down是
c
e
n
cen
cen的下游单元
但是遗憾的是,对于非结构网格,我们可以很容易知道
c
e
n
cen
cen和
d
o
w
n
down
down单元,但是很难知道
u
p
up
up单元是谁,所以需要用线性近似的方式得到
ϕ
u
p
{\phi _{up}}
ϕup值:
ϕ
u
p
=
ϕ
d
o
w
n
−
2
d
c
e
n
−
d
o
w
n
⋅
(
∇
ϕ
)
c
e
n
{\phi _{up}} = {\phi _{down}} - 2{d_{cen - down}} \cdot {\left( {\nabla \phi } \right)_{cen}}
ϕup=ϕdown−2dcen−down⋅(∇ϕ)cen
式中
d
d
d是一个距离向量,从
c
e
n
cen
cen的体心指向
d
o
w
n
down
down体心,将上式带入式(2)可得
r
=
2
d
c
e
n
−
d
o
w
n
⋅
(
∇
ϕ
)
c
e
n
ϕ
d
o
w
n
−
ϕ
c
e
n
−
1
r = {{2{d_{cen - down}} \cdot {{\left( {\nabla \phi } \right)}_{cen}}} \over {{\phi _{down - }}{\phi _{cen}}}} - 1
r=ϕdown−ϕcen2dcen−down⋅(∇ϕ)cen−1
考虑到OpenFoam的网格格式(owner单元和neigbour):
(1)如果流向为从O到N,那么将
c
e
n
cen
cen替换为O,将
d
o
w
n
down
down替换为N,可得
r
=
2
d
O
N
⋅
(
∇
ϕ
)
O
ϕ
N
−
ϕ
O
−
1
r = {{2{d_{ON}} \cdot {{\left( {\nabla \phi } \right)}_O}} \over {{\phi _{N - }}{\phi _O}}} - 1
r=ϕN−ϕO2dON⋅(∇ϕ)O−1
(2)如果流向为从N到O,那么将
c
e
n
cen
cen替换为N,将
d
o
w
n
down
down替换为O,可得
r
=
2
d
N
O
⋅
(
∇
ϕ
)
N
ϕ
O
−
ϕ
N
−
1
=
2
d
O
N
⋅
(
∇
ϕ
)
N
ϕ
N
−
ϕ
O
−
1
r = {{2{d_{NO}} \cdot {{\left( {\nabla \phi } \right)}_N}} \over {{\phi _{O - }}{\phi _N}}} - 1 = {{2{d_{ON}} \cdot {{\left( {\nabla \phi } \right)}_N}} \over {{\phi _{N - }}{\phi _O}}} - 1
r=ϕO−ϕN2dNO⋅(∇ϕ)N−1=ϕN−ϕO2dON⋅(∇ϕ)N−1
代码简介
OpenFoam中对r的定义位于NVDTVD.H文件
scalar r
(
const scalar faceFlux,
const scalar phiP,//这里P就是owner
const scalar phiN,
const vector& gradcP,//这里P就是owner
const vector& gradcN,
const vector& d
) const
{
scalar gradf = phiN - phiP;
scalar gradcf;
if (faceFlux > 0)
{
gradcf = d & gradcP;
}
else
{
gradcf = d & gradcN;
}
if (mag(gradcf) >= 1000*mag(gradf))
{
return 2*1000*sign(gradcf)*sign(gradf) - 1;
}
else
{
return 2*(gradcf/gradf) - 1;
}
}
一阶迎风格式对 ψ \psi ψ的定义位于upwind.H文件,是均匀的0场
//- Return the interpolation limiter
virtual tmp<surfaceScalarField> limiter
(
const GeometricField<Type, fvPatchField, volMesh>&
) const
{
return surfaceScalarField::New
(
"upwindLimiter",
this->mesh(),
dimensionedScalar(dimless, 0)
);
}
SuperBee 格式对 ψ \psi ψ的定义位于SuperBee.H
scalar limiter
(
const scalar cdWeight,
const scalar faceFlux,
const typename LimiterFunc::phiType& phiP,
const typename LimiterFunc::phiType& phiN,
const typename LimiterFunc::gradPhiType& gradcP,
const typename LimiterFunc::gradPhiType& gradcN,
const vector& d
) const
{
scalar r = LimiterFunc::r
(
faceFlux, phiP, phiN, gradcP, gradcN, d
);
return max(max(min(2*r, 1), min(r, 2)), 0);
}
Minmod 格式对 ψ \psi ψ的定义位于Minmod.H
scalar limiter
(
const scalar cdWeight,
const scalar faceFlux,
const typename LimiterFunc::phiType& phiP,
const typename LimiterFunc::phiType& phiN,
const typename LimiterFunc::gradPhiType& gradcP,
const typename LimiterFunc::gradPhiType& gradcN,
const vector& d
) const
{
scalar r = LimiterFunc::r
(
faceFlux, phiP, phiN, gradcP, gradcN, d
);
return max(min(r, 1), 0);
}
vanLeer格式对 ψ \psi ψ的定义位于vanLeer.H
scalar limiter
(
const scalar,
const scalar faceFlux,
const typename LimiterFunc::phiType& phiP,
const typename LimiterFunc::phiType& phiN,
const typename LimiterFunc::gradPhiType& gradcP,
const typename LimiterFunc::gradPhiType& gradcN,
const vector& d
) const
{
scalar r = LimiterFunc::r
(
faceFlux, phiP, phiN, gradcP, gradcN, d
);
return (r + mag(r))/(1 + mag(r));
}
类库的具体结构和代码注释将在之后的文章中给出