最近研究壁面函数,发现邱教授博客,讲的很是不错!记录一下
http://xiaopingqiu.github.io/2016/04/25/wallFunctions4/
在一般的外流场计算中,一般遇到的边界有入口、出口、对称面以及壁面-v7编程指南P40对此处应用的边界条件进行了说明,我们重点关注壁面,壁面一般设置为v-no-slip,p-法向梯度为0,代入离散方程从而进行求解,当加入湍流模型时,还会存在湍流参量k、 ε \varepsilon ε、 ω \omega ω,nut,博主主要想归纳在运用壁面函数时,到底该如何对这些参量设置边界条件。
openfoam中的壁面函数按其计算位置分为两种—第一种计算壁面上的值,第二种计算靠近壁面第一层网格,其中心的值。
openfoam里面求解器源代码都位于applications里面,如壁面函数等预先定义好的类位于src里面,其主要有六个k、 ε \varepsilon ε、 ω \omega ω,nut、f、vf、v主要是针对f-v2湍流模型,这里我们主要看k、 ε \varepsilon ε、 ω \omega ω、nut,注意文件夹的名称以s结尾,说明对于某一个参量,可能存在不止一种壁面函数,我们进去下一级目录查看,可以发现 ε \varepsilon ε、 ω \omega ω只有一种壁面函数,k有两种,nut足足有八种壁面函数可供选择!今天笔者主要阅读kqRwallFunctions源代码,遂做些标注,方便日后查阅也供他人参考,有理解不对的地方,还望大佬不吝赐教!
kqRwallFunction.H-这是类声明,固没有出现函数体
namespace Foam //名称空间
{
template<class Type> //模板类定义符,Type可以是任何类
class kqRWallFunctionFvPatchField
:
public zeroGradientFvPatchField<Type> //该类公有继承于模板类
{
public: //公有成员
//- Runtime type information
TypeName("kqRWallFunction"); //成员变量初始化
// Constructors
//- Construct from patch and internal field
kqRWallFunctionFvPatchField //构造函数 无返回值,以类名命名,初始化以引用类型传递参数
(
const fvPatch&,
const DimensionedField<Type, volMesh>&
);
//- Construct from patch, internal field and dictionary
kqRWallFunctionFvPatchField
(
const fvPatch&,
const DimensionedField<Type, volMesh>&,
const dictionary&
); //构造函数的重载
//- Construct by mapping given
// kqRWallFunctionFvPatchField
// onto a new patch
kqRWallFunctionFvPatchField
(
const kqRWallFunctionFvPatchField&,
const fvPatch&,
const DimensionedField<Type, volMesh>&,
const fvPatchFieldMapper&
);
//- Copy constructor
kqRWallFunctionFvPatchField
(
const kqRWallFunctionFvPatchField&
);
//- Construct and return a clone
virtual tmp<fvPatchField<Type>> clone() const //虚函数,可在子类中重新定义,返回值是一个tmp>类的对象,这是一个模板类
{
return tmp<fvPatchField<Type>>
(
new kqRWallFunctionFvPatchField(*this)//*this表示一个kqRWallFunctionFvPatchField 对象,调用了上面的copy构造函数
);
}
//- Copy constructor setting internal field reference
kqRWallFunctionFvPatchField
(
const kqRWallFunctionFvPatchField&,
const DimensionedField<Type, volMesh>&
);
//- Construct and return a clone setting internal field reference
virtual tmp<fvPatchField<Type>> clone
(
const DimensionedField<Type, volMesh>& iF
) const
{
return tmp<fvPatchField<Type>> //生成tmp>类的对象
(
new kqRWallFunctionFvPatchField(*this, iF)//其实函数参数是一个指针,指向kqRWallFunctionFvPatchField对象
);
}
// Member Functions---成员函数
//- Evaluate the patchField
virtual void evaluate
(
const Pstream::commsTypes commsType = Pstream::commsTypes::blocking
);
//- Write
virtual void write(Ostream&) const;
};
kqRwallFunction.C
#include "kqRWallFunctionFvPatchField.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class Type> //同上,模板类修饰符
Foam::kqRWallFunctionFvPatchField<Type>::kqRWallFunctionFvPatchField
(
const fvPatch& p,
const DimensionedField<Type, volMesh>& iF
)
:
zeroGradientFvPatchField<Type>(p, iF)
{}//调用父类构造函数
template<class Type>
Foam::kqRWallFunctionFvPatchField<Type>::kqRWallFunctionFvPatchField
(
const fvPatch& p,
const DimensionedField<Type, volMesh>& iF,
const dictionary& dict
)
:
zeroGradientFvPatchField<Type>(p, iF, dict)
{}
template<class Type>
Foam::kqRWallFunctionFvPatchField<Type>::kqRWallFunctionFvPatchField
(
const kqRWallFunctionFvPatchField& ptf,
const fvPatch& p,
const DimensionedField<Type, volMesh>& iF,
const fvPatchFieldMapper& mapper
)
:
zeroGradientFvPatchField<Type>(ptf, p, iF, mapper)
{}
template<class Type>
Foam::kqRWallFunctionFvPatchField<Type>::kqRWallFunctionFvPatchField
(
const kqRWallFunctionFvPatchField& tkqrwfpf
)
:
zeroGradientFvPatchField<Type>(tkqrwfpf)
{}
template<class Type>
Foam::kqRWallFunctionFvPatchField<Type>::kqRWallFunctionFvPatchField
(
const kqRWallFunctionFvPatchField& tkqrwfpf,
const DimensionedField<Type, volMesh>& iF
)
:
zeroGradientFvPatchField<Type>(tkqrwfpf, iF)
{}
//全是调用父类构造函数,这个类就是个空壳
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class Type>
void Foam::kqRWallFunctionFvPatchField<Type>::evaluate
(
const Pstream::commsTypes commsType
)
{
zeroGradientFvPatchField<Type>::evaluate(commsType);//调用父类函数
}
template<class Type>
void Foam::kqRWallFunctionFvPatchField<Type>::write(Ostream& os) const
{
zeroGradientFvPatchField<Type>::write(os); //又是调用父类
writeEntry(os, "value", *this);
}
读完这份源码,唯一的感受就是,kqRwallFunction这个边界条件就是zeroGradient,完全没有引入新的东西。
kLowReWallFunction.C
这是另外一个k壁面函数,虽然叫做LowRe但是也适用于HighRe,其继承于fixedValueFvPatchField,可以看出其为一个固定值边界条件,我们主要分析它的成员函数:
void kLowReWallFunctionFvPatchScalarField::updateCoeffs()
{
if (updated())//判断patch单元的值是否更新
{
return;
}
const label patchi = patch().index();//边界是被划分为不同的patch,这是每个patch的标号(label)
const turbulenceModel& turbModel = db().lookupObject<turbulenceModel>
(
IOobject::groupName
(
turbulenceModel::propertiesName,
internalField().group()
)
); //初始化一个对象
const nutWallFunctionFvPatchScalarField& nutw =
nutWallFunctionFvPatchScalarField::nutw(turbModel, patchi);
const scalarField& y = turbModel.y()[patchi]; //算near wall distant
// tmp可以理解为volScalarField* 其实也就是个包装过的指针,搭配new堆内存使用
const tmp<volScalarField> tk = turbModel.k();
const volScalarField& k = tk();//算第一个单元的k值
const tmp<scalarField> tnuw = turbModel.nu(patchi);
const scalarField& nuw = tnuw(); //算第一个单元的粘度值
const scalar Cmu25 = pow025(nutw.Cmu());//算摩擦速度Cmu25=Cmu^0.25
scalarField& kw = *this;//初始化修正的k
// Set k wall values
forAll(kw, facei)
{
label celli = patch().faceCells()[facei];//由面值算单元值
scalar uTau = Cmu25*sqrt(k[celli]);//算摩擦速度
scalar yPlus = uTau*y[facei]/nuw[facei];//算y+
if (yPlus > nutw.yPlusLam())
{
scalar Ck = -0.416;
scalar Bk = 8.366;
kw[facei] = Ck/nutw.kappa()*log(yPlus) + Bk;//注意这里是kw[facei],也就是说边界上的湍动能是固定值
}
else
{
scalar C = 11.0;
scalar Cf = (1.0/sqr(yPlus + C) + 2.0*yPlus/pow3(C) - 1.0/sqr(C));
kw[facei] = 2400.0/sqr(Ceps2_)*Cf;
}
kw[facei] *= sqr(uTau);//个人认为这个时候K场边界上应该是零梯度的,因为k+应该是面中心的值但是代码却是 kw[facei],说明面中心的值等于面上的值。
}
// Limit kw to avoid failure of the turbulence model due to division by kw
kw = max(kw, small);
fixedValueFvPatchField<scalar>::updateCoeffs();//执行父类的函数,更新update值
// TODO: perform averaging for cells sharing more than one boundary face
}