OpenFOAM – Run-time Postprocessing

Run-time postprocessing

In the earlier spillway and swak4Foam tutorials Paraview were used a lot for postprocessing. This works rather well on small and moderate cases, but when it comes to really large cases with tenths of millions of cells, this might not be practical. In such cases you should consider what you need, and configure OpenFOAM to give you those data during the simulation (and not try to extract it with Paraview later). Then the data will be extracted from the analysis while it is run in parallel. Most of the common prostprocessing tasks can be done this way. The surface elevation probe in the swak4Foam tutorial is one example of such run-time postprocessing, the forces and lift coefficient calculation in the airfoil is another.

The purpose of this tutorial is to:

  • Show how you can use programs such as GNU Octave to create meshes with nonregular shapes by using blockMesh only
  • Show a few of the possible run-time postprocessing features of OpenFoam and swak4Foam

The case we will use as an example is the emptying of a bottle mostly filled with a liquid held with the bottom up. The interesting questions are:

  • What is the filling level at a certain time?
  • At what rate does the liquid flow out?
  • How does the liquid-air interface look in the bottle's neck?
  • And how does the liquid surface look like?

Prerequisites

Before you start on this tutorial, please make sure that you have

  • A decent laptop or workstation
  • A working OpenFOAM 2.x.x installation
  • GNU Octave (Matlab will probably also work with minor modifications, although not tested)
  • Done the basic cavity and damBreak tutorials that is distributed together with OpenFOAM and described in the documentation
  • Done the spillway and swak4Foam tutorials provided here (or in any other way installed and familiarized yourself with swak4Foam)

1: Setup of initial case

The infamous damBreak tutorial will be used as a base case. You might choose yourself weather you want to use turbulence modelling or not. In the rest of this guide it is assumed that the simple laminar base case is used. Copy the tutorial into a folder of your choise, and possibly rename the folder to something else, such as beerBottle:

Terminal window

cp -r $FOAM_TUTORIALS/multiphase/interFoam/laminar/damBreak ./beerBottle

You should also switch the direction of gravity from the negative y-direction to the negative z-direction as we have done earlier, i.e. the acceleration field should be (0 0 -9.81) m^2/s.

2: Mesh generation and boundary conditions


The domain will for computational reasons be 2D, and the dimensions are as shown in the figure above. As this might be a bit difficult to implement by hand, we have prepared a small script meshgen.m that writes a constant/polyMesh/blockMeshDict file. This is an extremely fast and efficient way do generate simple meshes compared to the method previous used with snappyHexMesh and extrudeMesh. Please look at the script and the blockMeshDict it produces, and make sure you understand. If in doubt about the syntax of the blockMeshDict-file, please consult the OpenFOAM documentation. The mesh is very easily generated by the commands:

Terminal window

chmod +x meshgen.m
./meshgen.m
blockMesh

You should set the boundary conditions yourself (hint: the inletOutlet patch should be defined with a inletOutlet boundary condition).

3: Defining output data

As previously stated we are interested in some general output variables. Some of this can be extracted by using native OpenFOAM tools, and some output is easiest generated by swak4Foam. Brefore proceeding you should add some libraries to system/controlDict and include some files:

system/controlDict

libs (
                "libOpenFOAM.so"
                "libsimpleSwakFunctionObjects.so"
                "libswakFunctionObjects.so"
            );
        
       functions
       {
           #include "sampledSets"
           #include "sampledSurf"
       }

Now create the files system/sampledSets and system/sampledSurf:

Terminal window

touch system/sampledSets
                touch system/sampledSurf

You can of course also just put everything in one file, or even in ciontrolDict itself, but some prefer to put postprocessing configuration in separate files (like done here).

Total filling level

The total liquid filling is easiest calculated as the volume integral of the phase fraction. This is done by a native OpenFOAM volumeIntegrate function. Add the following to the system/sampledSets-file:

system/sampledSets

totalLiquid
                {
                    type volumeIntegrate;
                    fields ( alpha1 );
                    verbose true;
                }

Cut plane and surface profile

Since we are interested in the air-liquid interface in the bottle's neck, we must define a cut plane through the section we are interested in. For the liquid surface we must calculate an isosurface with alpha1=0.5. Both operations is some by the native OpenFOAM functions cuttingPlane and isoSurface. Add the following to system/sampledSurf:

system/sampledSurf

cuttingPlane
                {
                    type                      surfaces;
                    functionObjectLibs        ("libsampling.so");
                    outputControl             outputTime;
                 
                    surfaceFormat             vtk;
                    fields                    ( p U alpha1 );
                 
                    interpolationScheme        cellPoint;
                 
                    surfaces
                    (
                        neckCut
                        {
                            type                cuttingPlane;
                            planeType           pointAndNormal;
                            pointAndNormalDict
                            {
                                basePoint       (0 0 0.015166667);  // Notet that the plane does not match up with the mesh
                                normalVector    (0 0 1);
                            }
                            interpolate         true;
                        }
                         
                        freeSurface
                        {
                            type                isoSurface;
                            isoField            alpha1;
                            isoValue            0.5;
                            interpolate         true;
                        }
                    );
                }

Unless any modifications are done to the mesh, the cutting plane is not intersecting any internal faces in the mesh. This is done intentionally to show that you can define completely arbitrary planes without concern about the location of the internal faces. It would be quite a lot of work if all of the sample planes were to be relocated each time you changed the mesh resolution (for example in a convergence study).

Interpolation and integration

You should be aware that both integration and interpolation at run-time is costly operations (especially integrating over interpolated planes), and you should carefully consider your needs. If you are careless in your definitions you could end up using more CPU time on postprocessing than the analysis itself (however this might of course actually be what you want).

Rate of flow out of domain

The rate of flow out of the domain is easiest calculated using a swakExpression. Append the following lines to your system/sampledSets-file:

system/sampledSets

volFlow
                {
                    type                swakExpression;
                    valueType           patch;
                    patchName           inletOutlet;
                     
                    verbose             true;
                    expression          "alpha1*U&Sf()";
                    accumulations       ( sum );
                }

4: Running the simulation

Now you have to configure your decomposition the way you want it (done in system/decomposeParDict), decompose the domain and execute the simulation:

Terminal window

decomposePar
                mpirun -np 4 interFoam -parallel

5: Results and postprocessing

Your output planes, surfaces and variables should show up in folders created in the root directory of the case. If you for example want to plot the filling level together with the flow rate of liquid out of the domain, you can do this in gnuplot with the following commands:

set xlabel 'Time (s)'
set ylabel 'Volume of liquid (m^3)'
set y2label 'Flow rate (m^3/s)'
 
set y2tics
set yrange [0:*]
set y2range [0:*]
set grid
 
set term png size 800,600
set output 'fillLevel.png'
plot 'volumeIntegrate_totalLiquid/0/alpha1' axes x1y1 with lines title 'Volume of liquid', \
     'swakExpression_volFlow/0/volFlow' axes x1y2 with lines title 'Flow rate'

The resulting plot will look like:

Try to look at the other results you get, the volume flow and the isosurfaces.

You can of course still open the case in Paraview. Here is two stills form the discharge process:

6: Further work

If you want to test yourself's blockMeshDict-skills, you can try to make a full 3D grid. This should not be too difficult...

7: Download

You can download all necessary case files in beerBottle.tar.gz. Scripts to run and clean the case is also attached. Note that you need Gnuplot make the fill level plot.

Scroll to Top