天天看點

openfoam學習心得—壁面函數在CFD中如何實施

openfoam學習心得—壁面函數在CFD中如何實施

最近研究壁面函數,發現邱教授部落格,講的很是不錯!記錄一下

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、v

openfoam學習心得—壁面函數在CFD中如何實施

f、v主要是針對f-v2湍流模型,這裡我們主要看k、 ε \varepsilon ε、 ω \omega ω、nut,注意檔案夾的名稱以s結尾,說明對于某一個參量,可能存在不止一種壁面函數,我們進去下一級目錄檢視,可以發現 ε \varepsilon ε、 ω \omega ω隻有一種壁面函數,k有兩種,nut足足有八種壁面函數可供選擇!今天筆者主要閱讀kqRwallFunctions源代碼,遂做些标注,友善日後查閱也供他人參考,有了解不對的地方,還望大佬不吝賜教!

openfoam學習心得—壁面函數在CFD中如何實施
openfoam學習心得—壁面函數在CFD中如何實施

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<fvPatchField<Type>>類的對象,這是一個模闆類
        {
            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<fvPatchField<Type>>類的對象
            (
                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>可以了解為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
}
           

繼續閱讀