Channel flow in OpenFOAM using Lund’s rescaling

Important

The tutorial was tested with OpenFOAM v1812. Kindly report any difficulties with using newer versions. This tutorial for OpenFOAM 2.3.1 can be found in older versions of the documentation.

This offering is not approved or endorsed by OpenCFD Limited, producer and distributor of the OpenFOAM software and owner of the OPENFOAM® and OpenCFD® trade marks.

Introduction

In this tutorial, channel flow will be simulated. First, a precursor simulation will be setup, which will compute channel flow using periodic boundary conditions in both the streamwise and spanwise directions.

The velocity fields created by the precursor will be used as input for the rescaling procedure developed by Lund et al [LWS98]. It will be used to generate the inflow velocity field for the main simulation, which is also channel flow, but with velocity inlet/poressure outlet boundaries in the streamwise direction.

After completing this tutorial you will be able to do the following.

  • Set-up a precursor channel flow simulation in OpenFOAM.

  • Use the rescaling method developed by Lund et al. to generate inflow fields for the main simulation.

  • Read in the boundary data generated by eddylicious in OpenFOAM.

Essentially, the guidelines found in Using eddylicious with OpenFOAM are applied here to the concrete case of channel flow and Lund’s rescaling procedure to generate the inflow velocity field. It is assumed that the user has some experience in running and setting up simulations in OpenFOAM and is familiar with associated terminology.

Overview of the set-up

As described in the introduction, the goal of this tutorial is to conduct a channel flow simulation using OpenFOAM and eddylicious. Channel flow is a flow between two infinite parallel plates driven by a pressure gradient. The flow is fully defined by the friction velocity-based Reynolds number \(\text{Re}_\tau = u_\tau \delta/\nu\), where \(u_\tau\) is the friction velocity, \(\nu\) is the kinematic viscosity, and \(\delta\) is the half-height of the channel.

The computational cost of the simulation grows with \(\text{Re}_\tau\), therefore in this tutorial we will use the lowest Reynolds number for which DNS data is available, namely \(\text{Re}_\tau = 180\). This will allow using a mesh fine enough to resolve a big part of the turbulent structures present in the fow, yet small enough for the case to be computed in a reasonable time on a single workstation.

../_images/channel_flow.svg

Fig. 4 Channel flow domain.

The common way to set up a channel flow simulation is to create a rectangular domain of a size sufficiently large to contain the largest turbulent structures present in the flow. The domain used in the tutorial is shown in Fig. 4. The size of the domain is \(L_x \times 2\delta \times L_z = 9 \times 2 \times 4\).

To simulate an infinite domain, periodic boundary conditions are commonly applied in the stream- and spanwise directions. The pressure gradient is then introduced via an extra forcing term in the momentum equations.

However, for the purpose of testing an inflow field generation method, a velocity inlet can be used as the boundary condition at \(x=0\), and a pressure outlet at \(x=L_x\).

The peculiarity of this tutorial is that the chosen inflow generation method itself requires us to compute another channel flow (see Lund’s rescaling), which will serve as a precursor simulation for the “main” channel flow simulation. In the precursor simulation periodic boundaries in both stream- and spanwise direction will be used. The same mesh will be used in both simulations, and in both simulations the Reynolds number \(\text{Re}_\tau\) will be set to 180.

Such a set-up might seem completely meaningless, but in fact it can be used as a reference solution within a simulation campaign that tests various inflow generation methods [KPBK04].

The precursor simulation

The first part of the tutorial will deal with setting up a precursor simulation that will be later used to generate the inflow fields for the main simulation. Please follow the following steps.

  1. Unpack channel_flow_lund_rescaling.zip found in eddylicious/tutorials to a location of your preference (commonly run). Two folders will be unpacked, precursor and main. Go inside of the precursor folder.

  2. Let us explore the case. Data for time 1000 is available, that is the case has been pre-run to get rid of transients, therefore one can proceed with saving the velocity fields needed for the rescaling procedure directly.

    Opening 1000/U verifies that cycling boundary conditions are applied in both streamwise and spanwise directions.

    inlet
    {
       type    cyclic;
    }
    
    outlet
    {
       type    cyclic;
    }
    
    left
    {
       type    cyclic;
    }
    
    right
    {
       type    cyclic;
    }
    

    In system/fvOptions the mean streamwise velocity Ubar is prescribed. This is equivalent to prescribing a pressure gradient.

    momentumSource
    {
       type            meanVelocityForce;
       active          on;
       selectionMode   all;
    
       meanVelocityForceCoeffs
       {
           selectionMode   all;
           fields  (U);
           patch inlet;
           Ubar        ( 1 0 0 );
       }
    }
    
  3. In the controlDict a surfaces function object is used to save the velocity field from the inlet patch to a file at every time-step.

    sampledSurface
    {
        type surfaces;
        writeControl timeStep;
        writeInterval 1;
        enabled true;
    
        surfaceFormat foam;
        interpolationScheme none;
        interpolate false;
        triangulate false;
    
        fields
        (
           U
        );
    
        surfaces
        (
            inletSurface
            {
                type patch;
                patches (inlet);
            }
        );
    }
    

    The appropriate options make sure that the surface is not triangulated, and that no interpolation of the data is performed, we therefore save all the raw values at all the face centres. The foam format is chosen, since eddylicious can read in data stored in that format.

  4. Run blockMesh in order to create the mesh. It is recommended that you run the case using 4 processors. You can, however, modify this value in system/decomposeParDict. In order to decompose the mesh run decomposePar.

  5. Now everything is ready to run the case. The solver pimpleFoam will be used. Execute the solver. If you are running in parallel, add the -parallel flag and execute the solver with your MPI executable and the appropriate number of cores as an argument. Running the case will take a while. After the execution is complete, run reconstructPar -latestTime if you’ve run in parallel.

  6. Run postChannelFlow (available at https://bitbucket.org/lesituu/postchannelflow) to get the mean velocity and the components of the Reynolds stress tensor averaged along the streamwise and spanwise directions. The setting to the utility are provided in the constant/postChannelDict file. One-dimensional profiles are output in the postProcessing/collapsedFields directory.

  7. If you wish, you can compare the results to the DNS [LM15]. The DNS data can be found inside the postProcessing directory, in the files dns_mean.dat and dns_fluct.dat. The original archive can be found at the following address http://turbulence.ices.utexas.edu/channel2015/content/Data_2015_0180.html

    The post_processing.py script contains simple code to plot various quanties and compare the to the DNS. The script is found in the postProcessing folder as well. But feel free to use your own favorite software to post-process the results.

The main simulation

Now we can proceed with the main simulation that will use the velocity fields sampled in the precursor. The inlet of the main simulation is divided into two patches: inletBot and inletTop.

In 0/U the boundary condition for velocity at the inlets is defined as timeVaryingMappedFixedValue

inletBot
{
   type            timeVaryingMappedFixedValue;
   setAverage      false;
   perturb         0;
   offset          (0 0 0);
}
inletTop
{
   type            timeVaryingMappedFixedValue;
   setAverage      false;
   perturb         0;
   offset          (0 0 0);
}

This allows to read in the velocity values from files located in constant/boundaryData, see OpenFOAM native format.

  1. Go to the case main. Run blockMesh to create the mesh.

  2. In order to provide eddylicious the coordinates of the face centres at the inlet plane we use the postProcess utility and point it to the inletSurfaces function object residing in sytem/inletSurfaces. In that file, two surfaces coinciding with the inlet patches are defined. Run the utility: postProcess -func inletSurfaces. This will create a faceCentres file for each inlet patch in the postProcessing/inletSurfaces/0/*patchname* directories.

  3. Inflow velocity fields are generated for each inlet patch separately. The generation procedure for each patch is controlled by a configuration file. One file for each inlet patch, rescalingConfigBot and rescalingConfigTop for the inletBot and inletTop patch respectively. Explore the config files. See Lund’s rescaling and other relative parts of the User guide to make sure you understand what each option stands for. Note that the chosen values of \(u_\tau\), \(\delta_{99}\) and \(\nu\) are chosen coincide with the ones in the precursor simulation.

  4. Run runLundRescaling --config=rescalingConfigBot. The script will write out some integral properties of the precursor, perform the rescaling and then write out similar properties for the generated inflow fields. The properties of the precursor and the main simulation are almost identical, as is intended. Run runLundRescaling --config=rescalingConfigTop. Note that the constant/boundaryData now contains two directories corresponding to the two inlet pathes. Inside, the generated inflow fields are stored.

  1. If possible, decompose the case using decomposePar. Run it using pimpleFoam. Reconstruct the fields using reconstructPar if you’ve run in parallel.

  2. Explore the solution using you favorite post processing software! In particular, see if the solution converges to the one obtained in the precursor.