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.
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.
Unpack
channel_flow_lund_rescaling.zip
found ineddylicious/tutorials
to a location of your preference (commonlyrun
). Two folders will be unpacked,precursor
andmain
. Go inside of theprecursor
folder.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 velocityUbar
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 ); } }In the
controlDict
asurfaces
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.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 insystem/decomposeParDict
. In order to decompose the mesh rundecomposePar
.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, runreconstructPar -latestTime
if you’ve run in parallel.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 theconstant/postChannelDict
file. One-dimensional profiles are output in thepostProcessing/collapsedFields
directory.If you wish, you can compare the results to the DNS [LM15]. The DNS data can be found inside the
postProcessing
directory, in the filesdns_mean.dat
anddns_fluct.dat
. The original archive can be found at the following address http://turbulence.ices.utexas.edu/channel2015/content/Data_2015_0180.htmlThe
post_processing.py
script contains simple code to plot various quanties and compare the to the DNS. The script is found in thepostProcessing
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
andinletTop
.In
0/U
the boundary condition for velocity at the inlets is defined astimeVaryingMappedFixedValue
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.
Go to the case
main
. RunblockMesh
to create the mesh.In order to provide eddylicious the coordinates of the face centres at the inlet plane we use the
postProcess
utility and point it to theinletSurfaces
function object residing insytem/inletSurfaces
. In that file, two surfaces coinciding with the inlet patches are defined. Run the utility:postProcess -func inletSurfaces
. This will create afaceCentres
file for each inlet patch in thepostProcessing/inletSurfaces/0/*patchname*
directories.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
andrescalingConfigTop
for theinletBot
andinletTop
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.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. RunrunLundRescaling --config=rescalingConfigTop
. Note that theconstant/boundaryData
now contains two directories corresponding to the two inlet pathes. Inside, the generated inflow fields are stored.
If possible, decompose the case using
decomposePar
. Run it usingpimpleFoam
. Reconstruct the fields usingreconstructPar
if you’ve run in parallel.Explore the solution using you favorite post processing software! In particular, see if the solution converges to the one obtained in the precursor.