从数学公式到 C++ 代码分析喷雾粒子速度计算,以及喷雾引起的气相速度源项
本文下标 p 表示 parcel,g 表示 gas,无下标的也是表示环境气体。
Niklas Nordin 博士论文中的公式:
为了计算粒子的速度,构造速度方程:
mpdtdup=Fp
Fp=−8πD2ρCD∣up−u∣(up−u)
其中:
CD=⎩⎨⎧Rep24(1+61Rep2/3)0.424Rep<1000Rep>1000
Rep=μgρ∣up−u∣Dp
可以推导出:
ap=dtdup=−τuup−u
τu=πρCDDp2∣up−u∣8mp=34ρCp∣up−u∣ρpDp
其中ap 是粒子的加速度,Dp 是粒子的直径。
可以变形为:
dtdup=−τuup−u=−34ρCp∣up−u∣ρpDpup−u=−4ρpDp3(up−u)ρCD∣up−u∣=−4ρpD23(up−u)μgCDμgρ∣up−u∣Dp=−43ρpDp2μgCDRep(up−u)
还原到牛顿第二定律中:
Fp=mpdtdup
=mp43ρpDp2μgCDRep(u−up)
=4ρpDp23mpμgCDRe(u−up)
以下代码中的 mass
经常是指当前 parcel 中包含的一个 particle 的质量,需要乘以粒子数才等于当前 parcel 的总质量。
ReactingParcel::calc
中调用:
vector Su = Zero;
scalar Spu = 0.0;
vector dUTrans = Zero;
this->U_ = this->calcVelocity(cloud, td, dt, Res, mus, mass1, Su, dUTrans, Spu);
|
KinematicParcel::calcVelocity
template<class ParcelType> template<class TrackCloudType> const Foam::vector Foam::KinematicParcel<ParcelType>::calcVelocity ( TrackCloudType& cloud, trackingData& td, const scalar dt, const scalar Re, const scalar mu, const scalar mass, const vector& Su, vector& dUTrans, scalar& Spu ) const { const typename TrackCloudType::parcelType& p = static_cast<const typename TrackCloudType::parcelType&>(*this); typename TrackCloudType::parcelType::trackingData& ttd = static_cast<typename TrackCloudType::parcelType::trackingData&>(td);
const typename TrackCloudType::forceType& forces = cloud.forces();
const forceSuSp Fcp = forces.calcCoupled(p, ttd, dt, mass, Re, mu); const forceSuSp Fncp = forces.calcNonCoupled(p, ttd, dt, mass, Re, mu); const scalar massEff = forces.massEff(p, ttd, mass);
const vector acp = (Fcp.Sp()*td.Uc() + Fcp.Su())/massEff; const vector ancp = (Fncp.Su() + Su)/massEff; const scalar bcp = Fcp.Sp()/massEff;
const vector deltaU = cloud.UIntegrator().delta(U_, dt, acp + ancp, bcp); const vector deltaUncp = ancp*dt; const vector deltaUcp = deltaU - deltaUncp;
vector Unew = U_ + deltaU;
dUTrans -= massEff*deltaUcp;
Spu = dt*Fcp.Sp();
const polyMesh& mesh = cloud.pMesh(); meshTools::constrainDirection(mesh, mesh.solutionD(), Unew); meshTools::constrainDirection(mesh, mesh.solutionD(), dUTrans);
return Unew; }
|
forces.calcCoupled
和 forces.calcNonCoupled
都定义于 ParticleForce
中,但是返回值是 0,在其派生类中重新定义真正的函数,当我们选用 SphereDragForce
时,返回值是4ρDp23mpμCDRe。
然后再回到 KinematicParcel::calcVelocity
:
代码中的变量 | 数学公式 |
---|
Fcp | 4ρpDp23mpμCDRe |
Fncp | 0 |
massEff | mp |
acp | uc Fcp /mp=4ρpDp23ucμCDRe |
ancp | 0 |
bcp | Fcp /mp |
deltaU | mpFcp(uc−up)dt=4ρpDp23μCDRe(uc−up)dt |
deltaUncp | 0 |
deltaUcp | deltaU |
dUTrans | −md∗deltaU |
Spu | dt*Fcp |
其中uc 是粒子当前所在位置的插值气相速度。
可以发现这里的 deltaU
与上文提到的文献中的公式是一样的。这就是粒子速度方程了。
接下来讨论粒子对于气相速度的影响。首先看一下速度输运方程:
首先看一下速度输运方程:
tmp<fvVectorMatrix> tUEqn ( fvm::ddt(rho, U) + fvm::div(phi, U) + MRF.DDt(rho, U) + turbulence->divDevRhoReff(U) == rho()*g + parcels.SU(U) + fvOptions(rho, U) );
if (pimple.momentumPredictor()) { solve(UEqn == -fvc::grad(p));
fvOptions.correct(U); K = 0.5*magSqr(U); }
|
KinematicCloud::SU
template<class CloudType> inline Foam::tmp<Foam::fvVectorMatrix> Foam::KinematicCloud<CloudType>::SU(volVectorField& U) const { if (debug) { Info<< "UTrans min/max = " << min(UTrans()).value() << ", " << max(UTrans()).value() << nl << "UCoeff min/max = " << min(UCoeff()).value() << ", " << max(UCoeff()).value() << endl; }
if (solution_.coupled()) { if (solution_.semiImplicit("U")) { const volScalarField::Internal Vdt(mesh_.V()*this->db().time().deltaT());
return UTrans()/Vdt - fvm::Sp(UCoeff()/Vdt, U) + UCoeff()/Vdt*U; } else { tmp<fvVectorMatrix> tfvm(new fvVectorMatrix(U, dimForce)); fvVectorMatrix& fvm = tfvm.ref();
fvm.source() = -UTrans()/(this->db().time().deltaT());
return tfvm; } }
return tmp<fvVectorMatrix>(new fvVectorMatrix(U, dimForce)); }
|
ReactingParcel::calc
中:
forAll(dMass, i) { scalar dm = np0*dMass[i]; label gid = composition.localToCarrierId(0, i); scalar hs = composition.carrier().Hs(gid, td.pc(), T0);
cloud.rhoTrans(gid)[this->cell()] += dm; cloud.UTrans()[this->cell()] += dm*U0; cloud.hsTrans()[this->cell()] += dm*hs; }
cloud.UTrans()[this->cell()] += np0*dUTrans; cloud.UCoeff()[this->cell()] += np0*Spu;
|
再看一下文献:
∂t∂ρu~i+∂xj∂ρu~iu~j=−∂xi∂p+∂xj∂τij−∂xj∂ρΓij+S˙i
S˙i=Vf1m=1∑np(nd,mm˙d,mud,i,m−nd,mFd,i,m)
可以发现公式第一部分是液滴蒸发变成气相带来的速度,第二部分是液滴和气相之间的相互作用力。这两部分分别对应代码中的 dm*U0
和 np0*dUTrans
。 其中的 dUTrans
在 KinematicParcel::calcVelocity
中计算:dUTrans=−mpdeltaU。然后文献中的F=mddtdeltaU。这是所有 parcel 的合力,即Fi=∑m=1npFd,i,m,这里的i 表示力的三个方向,m 表示对所有 parcel 循环,np 是当前网格 parcel 的个数。nd,m 表示第 m 个 parcel 中 particle 的个数,cotmd,m 表示第 m 个 parcel 的蒸发速率,ud,m 表示第 m 个 parcel 的速度。
事实上,代码中:
UTrans = dm*U0 + np0*dUTrans
SU.source() = - UTrans/deltaT = - (dm*U0 + np0*dUTrans)/deltaT = - (dm*U0 - np0*m*deltaU)/deltaT = - (dm/deltaT*U0 - np0*m*deltaU/deltaT)
|
SU.source()
=−(ndm˙ud−F)