CFD Online Discussion Forums

CFD Online Discussion Forums (https://www.cfd-online.com/Forums/)
-   OpenFOAM Post-Processing (https://www.cfd-online.com/Forums/openfoam-post-processing/)
-   -   How to calculate the LES turbulent kinetic erengy in OpenFOAM (https://www.cfd-online.com/Forums/openfoam-post-processing/224563-how-calculate-les-turbulent-kinetic-erengy-openfoam.html)

wangziyang February 25, 2020 01:56

How to calculate the LES turbulent kinetic erengy in OpenFOAM
 
hi

i recently want to calculate the turbulent kinetic erengy using LES,

when i search on the net, i only search the formula: k= 0.5((u')^2+(v')^2+(w')^2)

where,u'=u-umean,v'=v-vmean,w'=w-wmean


i think this formula is uncorrect,but i can't find how to calculate LES TKE in openfoam

help!

best wishes!

ziwang

cjc96 February 27, 2020 07:57

Hey!

This is asked quite a lot on the forum, you'll probably find a fair few discussions about if you were to type in "LES TKE CFD-Online" into Google. Your formula for Turbulent Turbulent Kinetic Energy is (more or less) correct.

I've recently posted a thread where I was working on a function to output the ratio of resolved/total TKE for my own LES work, see here.

The quick version of which is that the 'R' post-processing function will provide you with the sub-grid Reynolds Stress Tensor, and the 'UPrime2Mean' calculation in the 'fieldAverage' function will provide you with the resolved Reynolds Stress Tensor, where:

k = \frac{1}{2}tr(R)

so your total Turbulent Kinetic Energy is:

k_{total} = k_{sub-grid} + k_{resolved} = \frac{1}{2}tr(R) + \frac{1}{2}tr(UPrime2Mean)

Hopefully this and the links provided should be enough to see you through!

Luiz August 27, 2020 16:51

Since someone might be as lazy as myself, here goes the code that adds the totalTKE into account:
Code:

totalTKE
{
    type            coded;
    libs            ("libutilityFunctionObjects.so");
    name            totalTKE;
    executeControl    timeStep;
    writeControl    writeTime;
    // timeStart        0;
    // timeEnd        0;
    enabled            true;

/*---------------------------------------------------------------------------*\

    Total Turbulent Kinect Energy Evaluation
        ** Requires fieldAverage Function to Obtain UPrime2Mean**
            ** Resolved Reynolds Stress Tensor
        ** Requires turbulenceFields Function to Obtain R**
            ** Subgrid Reynolds Stress Tensor

\*---------------------------------------------------------------------------*/

    codeExecute
    #{
        static autoPtr<volScalarField> totalTKE;

        if
        (
            mesh().foundObject<volSymmTensorField>("UPrime2Mean")
            &&
            mesh().foundObject<volSymmTensorField>("turbulenceProperties:R")
            &&
            mesh().foundObject<volScalarField>("totalTKE") == 0
        )
        {
            Info << "Turbulent Kinect Energy:" << endl;
            Info << "    Initialising" << endl;
            Info << "    Calculating" << nl << endl;

            totalTKE.set
            (
                new volScalarField
                (
                    IOobject
                    (
                        "totalTKE",
                        mesh().time().timeName(),
                        mesh(),
                        IOobject::NO_READ,
                        IOobject::AUTO_WRITE
                    ),
                    mesh(),
                    dimensionedScalar
                    (
                        "totalTKE",
                        dimensionSet(0,2,-2,0,0,0,0),
                        0
                    )
                )
            );

            const volSymmTensorField& R = mesh().lookupObjectRef<volSymmTensorField>("turbulenceProperties:R");
            const volSymmTensorField& UPrime2Mean = mesh().lookupObjectRef<volSymmTensorField>("UPrime2Mean");

            volScalarField& totalTKE = mesh().lookupObjectRef<volScalarField>("totalTKE");
            totalTKE = (0.5 * tr(R)) + (0.5 * tr(UPrime2Mean));
            totalTKE.write();
        }

        else if
        (
            mesh().foundObject<volSymmTensorField>("UPrime2Mean")
            &&
            mesh().foundObject<volSymmTensorField>("turbulenceProperties:R")
            &&
            mesh().foundObject<volScalarField>("totalTKE")
        )
        {
            Info << "Turbulent Kinect Energy:" << endl;
            Info << "    Calculating" << nl << endl;

            const volSymmTensorField& R = mesh().lookupObjectRef<volSymmTensorField>("turbulenceProperties:R");
            const volSymmTensorField& UPrime2Mean = mesh().lookupObjectRef<volSymmTensorField>("UPrime2Mean");

            volScalarField& totalTKE = mesh().lookupObjectRef<volScalarField>("totalTKE");
            totalTKE = (0.5 * tr(R)) + (0.5 * tr(UPrime2Mean));
            totalTKE.write();
        }

        else
        {
            Info << "Turbulent Kinect Energy:" << endl;
            Warning << endl
                    << "    Unable to Calculate Turbulent Kinect Energy" << endl
                    << "    UPrime2Mean and/or R Unavailable" << endl
                    << "    Enable fieldAverage and turbulenceFields Functions" << nl << endl;
        }
    #};
}

Note that this most be in system folder and called by controlDict.
The only changes from cjc96 function are the referencing to R (from R to turbulenceProperties:R) and the calculation itself. I checked function results with some literature data available and it seems to yield adequate values.

yarrald December 25, 2020 11:08

Does the order of the functions call matter? If I want to time average the totalTKE so I can compare it to RANS, I need to do the following:

fieldAverage U to get Uprime2Mean
turbulenceProperties to get R
totalTKE function to using the above two
fieldAverage TKE to get the time average of the above.

Obviously there are various calls in here, will openFOAM handle this so long as they are all in the controlDict? Or do I need to place them in the order they need to be called?

Luiz December 26, 2020 10:45

Yes, the order of the function matters when calling it. Personally, I add the totalTKE as an external file, so in the controlDict I only include this function, similar to what you do with residuals. But nothing stops you from adding it all to the controlDict file, it should work exactly the same.

The order you presented is fine and this should work. A noticed bug occurs when you start totalTKE along with the field average and the R function it will not identify the required fields and most likely crash. A quick fix for this is making it start one timestep after the fieldAveraging and the R start.

Also, it will save at each timestep. you can disable this by deleting the line
Code:

totalTKE.write();
By doing so you can use the normal time controls available in openFOAM (eg. timeStart, timeEnd, writeTime ...)

abas.rahmani86 April 11, 2022 06:32

How to add this to the controlDict
 
Quote:

Originally Posted by Luiz (Post 781500)
Since someone might be as lazy as myself, here goes the code that adds the totalTKE into account:
Code:

totalTKE
{
    type            coded;
    libs            ("libutilityFunctionObjects.so");
    name            totalTKE;
    executeControl    timeStep;
    writeControl    writeTime;
    // timeStart        0;
    // timeEnd        0;
    enabled            true;

/*---------------------------------------------------------------------------*\

    Total Turbulent Kinect Energy Evaluation
        ** Requires fieldAverage Function to Obtain UPrime2Mean**
            ** Resolved Reynolds Stress Tensor
        ** Requires turbulenceFields Function to Obtain R**
            ** Subgrid Reynolds Stress Tensor

\*---------------------------------------------------------------------------*/

    codeExecute
    #{
        static autoPtr<volScalarField> totalTKE;

        if
        (
            mesh().foundObject<volSymmTensorField>("UPrime2Mean")
            &&
            mesh().foundObject<volSymmTensorField>("turbulenceProperties:R")
            &&
            mesh().foundObject<volScalarField>("totalTKE") == 0
        )
        {
            Info << "Turbulent Kinect Energy:" << endl;
            Info << "    Initialising" << endl;
            Info << "    Calculating" << nl << endl;

            totalTKE.set
            (
                new volScalarField
                (
                    IOobject
                    (
                        "totalTKE",
                        mesh().time().timeName(),
                        mesh(),
                        IOobject::NO_READ,
                        IOobject::AUTO_WRITE
                    ),
                    mesh(),
                    dimensionedScalar
                    (
                        "totalTKE",
                        dimensionSet(0,2,-2,0,0,0,0),
                        0
                    )
                )
            );

            const volSymmTensorField& R = mesh().lookupObjectRef<volSymmTensorField>("turbulenceProperties:R");
            const volSymmTensorField& UPrime2Mean = mesh().lookupObjectRef<volSymmTensorField>("UPrime2Mean");

            volScalarField& totalTKE = mesh().lookupObjectRef<volScalarField>("totalTKE");
            totalTKE = (0.5 * tr(R)) + (0.5 * tr(UPrime2Mean));
            totalTKE.write();
        }

        else if
        (
            mesh().foundObject<volSymmTensorField>("UPrime2Mean")
            &&
            mesh().foundObject<volSymmTensorField>("turbulenceProperties:R")
            &&
            mesh().foundObject<volScalarField>("totalTKE")
        )
        {
            Info << "Turbulent Kinect Energy:" << endl;
            Info << "    Calculating" << nl << endl;

            const volSymmTensorField& R = mesh().lookupObjectRef<volSymmTensorField>("turbulenceProperties:R");
            const volSymmTensorField& UPrime2Mean = mesh().lookupObjectRef<volSymmTensorField>("UPrime2Mean");

            volScalarField& totalTKE = mesh().lookupObjectRef<volScalarField>("totalTKE");
            totalTKE = (0.5 * tr(R)) + (0.5 * tr(UPrime2Mean));
            totalTKE.write();
        }

        else
        {
            Info << "Turbulent Kinect Energy:" << endl;
            Warning << endl
                    << "    Unable to Calculate Turbulent Kinect Energy" << endl
                    << "    UPrime2Mean and/or R Unavailable" << endl
                    << "    Enable fieldAverage and turbulenceFields Functions" << nl << endl;
        }
    #};
}

Note that this most be in system folder and called by controlDict.
The only changes from cjc96 function are the referencing to R (from R to turbulenceProperties:R) and the calculation itself. I checked function results with some literature data available and it seems to yield adequate values.

Thank you for sharing the script. Please help me to find how to add this to the controlDict. If it is possible, please share a system file that uses it.:)

NLeb July 14, 2022 04:10

Here's all you need to add at the bottom of your controlDict to get it working. If there is an existing "functions" section in your controlDict, then just combine their contents together. This was on OpenFOAMv2206.

Code:


functions
{
    fieldAverage
    {
        type            fieldAverage;
        libs            (fieldFunctionObjects);
        executeControl  timeStep;
        writeControl    writeTime;
        enabled        true;
       
        fields
        (
            U
            {
                mean            yes;
                prime2Mean      yes;
                base            time;
            }
        );
    }

    turbulenceFields
    {
        type            turbulenceFields;
        libs            (fieldFunctionObjects);
        executeControl  timeStep;
        writeControl    writeTime;
        enabled        true;

        field          R;
    }

    totalTKE
    {
        type            coded;
        libs            ("libutilityFunctionObjects.so");
        name            totalTKE;
        executeControl  timeStep;
        writeControl    writeTime;
        enabled        true;

    /*---------------------------------------------------------------------------*\

        Total Turbulent Kinect Energy Evaluation
            ** Requires fieldAverage Function to Obtain UPrime2Mean**
                ** Resolved Reynolds Stress Tensor
            ** Requires turbulenceFields Function to Obtain R**
                ** Subgrid Reynolds Stress Tensor

    \*---------------------------------------------------------------------------*/

        codeExecute
        #{
            static autoPtr<volScalarField> totalTKE;

            if
            (
                mesh().foundObject<volSymmTensorField>("UPrime2Mean")
                &&
                mesh().foundObject<volSymmTensorField>("turbulenceProperties:R")
                &&
                mesh().foundObject<volScalarField>("totalTKE") == 0
            )
            {
                Info << "Turbulent Kinect Energy:" << endl;
                Info << "    Initialising" << endl;
                Info << "    Calculating" << nl << endl;

                totalTKE.set
                (
                    new volScalarField
                    (
                        IOobject
                        (
                            "totalTKE",
                            mesh().time().timeName(),
                            mesh(),
                            IOobject::NO_READ,
                            IOobject::AUTO_WRITE
                        ),
                        mesh(),
                        dimensionedScalar
                        (
                            "totalTKE",
                            dimensionSet(0,2,-2,0,0,0,0),
                            0
                        )
                    )
                );

                const volSymmTensorField& R = mesh().lookupObjectRef<volSymmTensorField>("turbulenceProperties:R");
                const volSymmTensorField& UPrime2Mean = mesh().lookupObjectRef<volSymmTensorField>("UPrime2Mean");

                volScalarField& totalTKE = mesh().lookupObjectRef<volScalarField>("totalTKE");
                totalTKE = (0.5 * tr(R)) + (0.5 * tr(UPrime2Mean));
                totalTKE.write();
            }

            else if
            (
                mesh().foundObject<volSymmTensorField>("UPrime2Mean")
                &&
                mesh().foundObject<volSymmTensorField>("turbulenceProperties:R")
                &&
                mesh().foundObject<volScalarField>("totalTKE")
            )
            {
                Info << "Turbulent Kinect Energy:" << endl;
                Info << "    Calculating" << nl << endl;

                const volSymmTensorField& R = mesh().lookupObjectRef<volSymmTensorField>("turbulenceProperties:R");
                const volSymmTensorField& UPrime2Mean = mesh().lookupObjectRef<volSymmTensorField>("UPrime2Mean");

                volScalarField& totalTKE = mesh().lookupObjectRef<volScalarField>("totalTKE");
                totalTKE = (0.5 * tr(R)) + (0.5 * tr(UPrime2Mean));
                totalTKE.write();
            }

            else
            {
                Info << "Turbulent Kinect Energy:" << endl;
                Warning << endl
                        << "    Unable to Calculate Turbulent Kinect Energy" << endl
                        << "    UPrime2Mean and/or R Unavailable" << endl
                        << "    Enable fieldAverage and turbulenceFields Functions" << nl << endl;
            }
        #};
    }
}


sadsid July 16, 2023 13:33

Can we also use this approach in the case of the Smagorinsky model?

Quote:

Originally Posted by NLeb (Post 831665)
Here's all you need to add at the bottom of your controlDict to get it working. If there is an existing "functions" section in your controlDict, then just combine their contents together. This was on OpenFOAMv2206.

Code:


functions
{
    fieldAverage
    {
        type            fieldAverage;
        libs            (fieldFunctionObjects);
        executeControl  timeStep;
        writeControl    writeTime;
        enabled        true;
       
        fields
        (
            U
            {
                mean            yes;
                prime2Mean      yes;
                base            time;
            }
        );
    }

    turbulenceFields
    {
        type            turbulenceFields;
        libs            (fieldFunctionObjects);
        executeControl  timeStep;
        writeControl    writeTime;
        enabled        true;

        field          R;
    }

    totalTKE
    {
        type            coded;
        libs            ("libutilityFunctionObjects.so");
        name            totalTKE;
        executeControl  timeStep;
        writeControl    writeTime;
        enabled        true;

    /*---------------------------------------------------------------------------*\

        Total Turbulent Kinect Energy Evaluation
            ** Requires fieldAverage Function to Obtain UPrime2Mean**
                ** Resolved Reynolds Stress Tensor
            ** Requires turbulenceFields Function to Obtain R**
                ** Subgrid Reynolds Stress Tensor

    \*---------------------------------------------------------------------------*/

        codeExecute
        #{
            static autoPtr<volScalarField> totalTKE;

            if
            (
                mesh().foundObject<volSymmTensorField>("UPrime2Mean")
                &&
                mesh().foundObject<volSymmTensorField>("turbulenceProperties:R")
                &&
                mesh().foundObject<volScalarField>("totalTKE") == 0
            )
            {
                Info << "Turbulent Kinect Energy:" << endl;
                Info << "    Initialising" << endl;
                Info << "    Calculating" << nl << endl;

                totalTKE.set
                (
                    new volScalarField
                    (
                        IOobject
                        (
                            "totalTKE",
                            mesh().time().timeName(),
                            mesh(),
                            IOobject::NO_READ,
                            IOobject::AUTO_WRITE
                        ),
                        mesh(),
                        dimensionedScalar
                        (
                            "totalTKE",
                            dimensionSet(0,2,-2,0,0,0,0),
                            0
                        )
                    )
                );

                const volSymmTensorField& R = mesh().lookupObjectRef<volSymmTensorField>("turbulenceProperties:R");
                const volSymmTensorField& UPrime2Mean = mesh().lookupObjectRef<volSymmTensorField>("UPrime2Mean");

                volScalarField& totalTKE = mesh().lookupObjectRef<volScalarField>("totalTKE");
                totalTKE = (0.5 * tr(R)) + (0.5 * tr(UPrime2Mean));
                totalTKE.write();
            }

            else if
            (
                mesh().foundObject<volSymmTensorField>("UPrime2Mean")
                &&
                mesh().foundObject<volSymmTensorField>("turbulenceProperties:R")
                &&
                mesh().foundObject<volScalarField>("totalTKE")
            )
            {
                Info << "Turbulent Kinect Energy:" << endl;
                Info << "    Calculating" << nl << endl;

                const volSymmTensorField& R = mesh().lookupObjectRef<volSymmTensorField>("turbulenceProperties:R");
                const volSymmTensorField& UPrime2Mean = mesh().lookupObjectRef<volSymmTensorField>("UPrime2Mean");

                volScalarField& totalTKE = mesh().lookupObjectRef<volScalarField>("totalTKE");
                totalTKE = (0.5 * tr(R)) + (0.5 * tr(UPrime2Mean));
                totalTKE.write();
            }

            else
            {
                Info << "Turbulent Kinect Energy:" << endl;
                Warning << endl
                        << "    Unable to Calculate Turbulent Kinect Energy" << endl
                        << "    UPrime2Mean and/or R Unavailable" << endl
                        << "    Enable fieldAverage and turbulenceFields Functions" << nl << endl;
            }
        #};
    }
}




All times are GMT -4. The time now is 04:05.