Nabla Logo programmer
  Advanced Search
  
  Send us a comment/query
 
  Back to main web site
 
  OpenFOAM guides
  - User guide
  - Programmer’s guide
 
  Index
 
  Changes from OpenFOAM 2.2 to 2.3
 
  Trademarks in the guides
  ©2000-2007 Nabla Ltd.

3.1 Flow around a cylinder

In this example we shall investigate potential flow around a cylinder using potentialFoam. This example introduces the following OpenFOAM features:

  • non-orthogonal meshes;
  • generating an analytical solution to a problem in OpenFOAM.

3.1.1 Problem specification

The problem is defined as follows:

Solution domain
The domain is 2 dimensional and consists of a square domain with a cylinder collocated with the centre of the square as shown in Figure 3.1.
Ux =  1.0 m/s                  p = 0 bar


                  y


                             symmetry       4.0 m
                0        x


                        0.5 m







                4.0 m
\special {t4ht=

Figure 3.1: Geometry of flow round a cylinder


Governing equations
 
  • Mass continuity for an incompressible fluid
     \~/  •U = 0
           \special {t4ht=
    (3.1)

  • Pressure equation for an incompressible, irrotational fluid assuming steady-state conditions
     2
 \~/  p = 0
           \special {t4ht=
    (3.2)

Boundary conditions
 
  • Inlet (left) with fixed velocity U  = (1,0, 0) m/s  \special {t4ht=.
  • Outlet (right) with a fixed pressure p = 0 Pa  \special {t4ht=.
  • No-slip wall (bottom);
  • Symmetry plane (top).
Initial conditions
U  = 0 m/s  \special {t4ht=, p = 0 Pa  \special {t4ht= -- required in OpenFOAM input files but not necessary for the solution since the problem is steady-state.
Solver name
potentialFoam: a potential flow code, i.e. assumes the flow is incompressible, steady, irrotational, inviscid and it ignores gravity.
Case name
cylinder case located in the $OpenFOAM_TUTORIALS/potentialFoam directory.

3.1.2 Note on potentialFoam

potentialFoam is a useful solver to validate OpenFOAM since the assumptions of potential flow are such that an analytical solution exists for cases whose geometries are relatively simple. In this example of flow around a cylinder an analytical solution exists with which we can compare our numerical solution. potentialFoam can also be run more like a utility to provide a (reasonably) conservative initial U  \special {t4ht= field for a problem. When running certain cases, this can useful for avoiding instabilities due to the initial field being unstable. In short, potentialFoam creates a conservative field from a non-conservative initial field supplied by the user.

3.1.3 Mesh generation

Mesh generation using blockMesh has been described in tutorials in the User Guide. In this case, the mesh consists of 10  \special {t4ht= blocks as shown in Figure 3.2.


                                    up
    17                   18          8          7                    6



                              9           4
              8                                           3

                                      9
left                                                                   right

  14                       15  5         0    4                       3

            7                       10                      2
                         6      16        5     1
                                      y

   13               12      11          x   0        1               2
              down                cylinder              down
\special {t4ht=


Figure 3.2: Blocks in cylinder geometry


Remember that all meshes are treated as 3 dimensional in OpenFOAM. If we wish to solve a 2 dimensional problem, we must describe a 3 dimensional mesh that is only one cell thick in the third direction that is not solved. In Figure 3.2 we show only the back plane of the geometry, along z = - 0.5  \special {t4ht=, in which the vertex numbers are numbered 0-18. The other 19 vertices in the front plane, z = +0.5  \special {t4ht=, are numbered in the same order as the back plane, as shown in the mesh description file below:

1  // The OpenFOAM Project // File: blockMeshDict
2  /*
3  -------------------------------------------------------------------------------
4   =========         | dictionary
5   \\      /         |
6    \\    /          | Name:   blockMeshDict
7     \\  /           | Family: FoamX configuration file
8      \\/            |
9      F ield         | OpenFOAM version: 2.3
10      O peration     | Product of Nabla Ltd.
11      A and          |
12      M anipulation  | Email: Enquiries@Nabla.co.uk
13  -------------------------------------------------------------------------------
14  */
15  // FoamX Case Dictionary.
16  
17  FoamFile
18  {
19      version         2.0;
20      format          ascii;
21  
22      root            "";
23      case            "";
24      instance        "";
25      local           "";
26  
27      class           dictionary;
28      object          blockMeshDict;
29  }
30  
31  // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
32  
33  convertToMeters 1;
34  
35  vertices
36  (
37      (0.5 0 -0.5)
38      (1 0 -0.5)
39      (2 0 -0.5)
40      (2 0.707107 -0.5)
41      (0.707107 0.707107 -0.5)
42      (0.353553 0.353553 -0.5)
43      (2 2 -0.5)
44      (0.707107 2 -0.5)
45      (0 2 -0.5)
46      (0 1 -0.5)
47      (0 0.5 -0.5)
48      (-0.5 0 -0.5)
49      (-1 0 -0.5)
50      (-2 0 -0.5)
51      (-2 0.707107 -0.5)
52      (-0.707107 0.707107 -0.5)
53      (-0.353553 0.353553 -0.5)
54      (-2 2 -0.5)
55      (-0.707107 2 -0.5)
56      (0.5 0 0.5)
57      (1 0 0.5)
58      (2 0 0.5)
59      (2 0.707107 0.5)
60      (0.707107 0.707107 0.5)
61      (0.353553 0.353553 0.5)
62      (2 2 0.5)
63      (0.707107 2 0.5)
64      (0 2 0.5)
65      (0 1 0.5)
66      (0 0.5 0.5)
67      (-0.5 0 0.5)
68      (-1 0 0.5)
69      (-2 0 0.5)
70      (-2 0.707107 0.5)
71      (-0.707107 0.707107 0.5)
72      (-0.353553 0.353553 0.5)
73      (-2 2 0.5)
74      (-0.707107 2 0.5)
75  );
76  
77  blocks
78  (
79      hex (5 4 9 10 24 23 28 29) (10 10 1) simpleGrading (1 1 1)
80      hex (0 1 4 5 19 20 23 24) (10 10 1) simpleGrading (1 1 1)
81      hex (1 2 3 4 20 21 22 23) (20 10 1) simpleGrading (1 1 1)
82      hex (4 3 6 7 23 22 25 26) (20 20 1) simpleGrading (1 1 1)
83      hex (9 4 7 8 28 23 26 27) (10 20 1) simpleGrading (1 1 1)
84      hex (15 16 10 9 34 35 29 28) (10 10 1) simpleGrading (1 1 1)
85      hex (12 11 16 15 31 30 35 34) (10 10 1) simpleGrading (1 1 1)
86      hex (13 12 15 14 32 31 34 33) (20 10 1) simpleGrading (1 1 1)
87      hex (14 15 18 17 33 34 37 36) (20 20 1) simpleGrading (1 1 1)
88      hex (15 9 8 18 34 28 27 37) (10 20 1) simpleGrading (1 1 1)
89  );
90  
91  edges
92  (
93      arc 0 5 (0.469846 0.17101 -0.5)
94      arc 5 10 (0.17101 0.469846 -0.5)
95      arc 1 4 (0.939693 0.34202 -0.5)
96      arc 4 9 (0.34202 0.939693 -0.5)
97      arc 19 24 (0.469846 0.17101 0.5)
98      arc 24 29 (0.17101 0.469846 0.5)
99      arc 20 23 (0.939693 0.34202 0.5)
100      arc 23 28 (0.34202 0.939693 0.5)
101      arc 11 16 (-0.469846 0.17101 -0.5)
102      arc 16 10 (-0.17101 0.469846 -0.5)
103      arc 12 15 (-0.939693 0.34202 -0.5)
104      arc 15 9 (-0.34202 0.939693 -0.5)
105      arc 30 35 (-0.469846 0.17101 0.5)
106      arc 35 29 (-0.17101 0.469846 0.5)
107      arc 31 34 (-0.939693 0.34202 0.5)
108      arc 34 28 (-0.34202 0.939693 0.5)
109  );
110  
111  patches
112  (
113      symmetryPlane down
114      (
115          (0 1 20 19)
116          (1 2 21 20)
117          (12 11 30 31)
118          (13 12 31 32)
119      )
120      patch right
121      (
122          (2 3 22 21)
123          (3 6 25 22)
124      )
125      symmetryPlane up
126      (
127          (7 8 27 26)
128          (6 7 26 25)
129          (8 18 37 27)
130          (18 17 36 37)
131      )
132      patch left
133      (
134          (14 13 32 33)
135          (17 14 33 36)
136      )
137      symmetryPlane cylinder
138      (
139          (10 5 24 29)
140          (5 0 19 24)
141          (16 10 29 35)
142          (11 16 35 30)
143      )
144  );
145  
146  mergePatchPairs
147  (
148  );
149  
150  // ************************************************************************* //

3.1.4 Boundary conditions and initial fields

Using FoamX or editing case files by hand, set the boundary conditions in accordance with the problem description in Figure 3.1, i.e. the left boundary should be an Inlet, the right boundary should be an Outlet and the down and cylinder boundaries should be symmetryPlane. The top boundary conditions is chosen so that we can make the most genuine comparison with our analytical solution which uses the assumption that the domain is infinite in the y  \special {t4ht= direction. The result is that the normal gradient of U  \special {t4ht= is small along a plane coinciding with our boundary. We therefore impose the condition that the normal component is zero, i.e. specify the boundary as a symmetryPlane, thereby ensuring that the comparison with the analytical is reasonable.

3.1.5 Running the case

No fluid properties need be specified in this problem since the flow is assumed to be incompressible and inviscid. In the system subdirectory, the controlDict specifies the control parameters for the run. Note that since we assume steady flow, we only run for 1 time step:


1  // The OpenFOAM Project // File: controlDict
2  /*
3  -------------------------------------------------------------------------------
4   =========         | dictionary
5   \\      /         |
6    \\    /          | Name:   controlDict
7     \\  /           | Family: FoamX configuration file
8      \\/            |
9      F ield         | OpenFOAM version: 2.3
10      O peration     | Product of Nabla Ltd.
11      A and          |
12      M anipulation  | Email: Enquiries@Nabla.co.uk
13  -------------------------------------------------------------------------------
14  */
15  // FoamX Case Dictionary.
16  
17  FoamFile
18  {
19      version         2.0;
20      format          ascii;
21  
22      root            "";
23      case            "";
24      instance        "";
25      local           "";
26  
27      class           dictionary;
28      object          controlDict;
29  }
30  
31  // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
32  
33  applicationClass potentialFoam;
34  
35  startFrom       startTime;
36  
37  startTime       0;
38  
39  stopAt          endTime;
40  
41  endTime         1;
42  
43  deltaT          1;
44  
45  writeControl    timeStep;
46  
47  writeInterval   1;
48  
49  cycleWrite      0;
50  
51  writeFormat     ascii;
52  
53  writePrecision  6;
54  
55  writeCompression uncompressed;
56  
57  timeFormat      general;
58  
59  timePrecision   6;
60  
61  runTimeModifiable yes;
62  
63  
64  // ************************************************************************* //

potentialFoam executes an iterative loop around the pressure equation which it solves in order that explicit terms relating to non-orthogonal correction in the Laplacian term may be updated in successive iterations. The number of iterations around the pressure equation is controlled by the nNonOrthogonalCorrectors keyword in controlDict. In the first instance we can set nNonOrthogonalCorrectors to 0 so that no loops are performed, i.e. the pressure equation is solved once, and there is no non-orthogonal correction. The solution is shown in Figure 3.3(a) (at t = 1  \special {t4ht=, when the steady-state simulation is complete).


PIC\special {t4ht=
(a) With no non-orthogonal correction
PIC\special {t4ht=
(b) With non-orthogonal correction
PIC\special {t4ht=
(c) Analytical solution

Figure 3.3: Streamlines of potential flow


We expect the solution to show smooth streamlines passing across the domain as in the analytical solution in Figure 3.3(c), yet there is clearly some error in the regions where there is high non-orthogonality in the mesh, e.g. at the join of blocks 0, 1 and 3. The case can be run a second time with some non-orthogonal correction by setting nNonOrthogonalCorrectors to 3. The solution shows smooth streamlines with no significant error due to non-orthogonality as shown in Figure 3.3(b).

3.1.6 Generating the analytical solution

Source code is included in the $OpenFOAM_TUTORIALS/potentialFoam/analyticalCylinder directory to generate the analytical solution for the potential flow case. The velocity at any point at a distance d  \special {t4ht= and angle h  \special {t4ht= from the cylinder centre is described analytically as

          [    (  )       ]
U   = U    1-   r- 2cos 2h
  x    o o       d
                                                        (r )2
                                               Uy =  U oo   --  sin 2h
                                                          d
\special {t4ht=
(3.3)
where r  \special {t4ht= is the cylinder radius and Uo o  \special {t4ht= is the inlet flow velocity. Here, h  \special {t4ht= describes the angle subtended from the x  \special {t4ht=-axis.

Let us examine some details of the source code in the analyticalCylinder directory. In createFields.H, the velocity field is read in using the IOobject::NO_WRITE option to ensure that the field data can never be overwritten during execution of analyticalCylinder. The inlet velocity and cylinder radius are taken from data read from the mesh and a field UA is set up to store the analytical solution:


1  Info<< "Reading field U\n" << endl;
2  volVectorField U
3  (
4      IOobject
5      (
6          "U",
7          runTime.timeName(),
8          runTime,
9          IOobject::MUST_READ,
10          IOobject::NO_WRITE
11      ),
12      mesh
13  );
14  
15  Info<< "Reading inlet velocity  uInfX\n" << endl;
16  
17  dimensionedScalar uInfX
18  (
19      "uInfx",
20      dimensionSet(0, 1, -1, 0, 0),
21      U.boundaryField()[3][0].x()
22  );
23  Info << "U at inlet = " << uInfX.value() << " m/s" << endl;
24  
25  dimensionedScalar radius
26  (
27      "radius",
28      dimensionSet(0, 1, 0, 0, 0),
29      mag(U.mesh().boundary()[4].Cf()[0])
30  );
31  
32  Info << "Cylinder radius = " << radius.value() << " m" << endl;
33  
34  volVectorField UA
35  (
36      IOobject
37      (
38          "UA",
39          runTime.timeName(),
40          runTime,
41          IOobject::NO_READ,
42          IOobject::AUTO_WRITE
43      ),
44      U
45  );

Thea main code analyticalCylinder.C performs the following tasks:

  • increments the time step by runTime++;
  • generates the analytical solution for field UA using tensor arithmetic;
  • writes the solution to file by runTime.writeObjects().

1  // The OpenFOAM Project // File: analyticalCylinder/analyticalCylinder.C
2  /*
3  -------------------------------------------------------------------------------
4   =========         | Application
5   \\      /         |
6    \\    /          | Name:   analyticalCylinder
7     \\  /           | Family: CFD
8      \\/            |
9      F ield         | OpenFOAM version: 2.3
10      O peration     |
11      A and          | Copyright (C) 2000-2007 Nabla Ltd.
12      M anipulation  |          All Rights Reserved.
13  -------------------------------------------------------------------------------
14  APPLICATION
15      analyticalCylinder
16  
17  DESCRIPTION
18      Generates an analytical solution for potential flow around a cylinder.
19      Can be compared with the solution from the potentialFlow/cylinder example.
20  
21  AUTHOR
22      Chris Greenshields
23  
24  -------------------------------------------------------------------------------
25  */
26  
27  #include "fvCFD.H"
28  
29  
30  // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
31  
32  int main(int argc, char *argv[])
33  {
34  
35  #   include "setRootCase.H"
36  
37  #   include "createDatabase.H"
38  #   include "createMesh.H"
39  #   include "createFields.H"
40  
41  // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
42  
43      Info << "\nEvaluating analytical solution" << endl;
44  
45      volVectorField centres = UA.mesh().C();
46      volScalarField magCentres = mag(centres);
47      volScalarField theta = acos((centres & vector(1,0,0))/magCentres);
48  
49      volVectorField cs2theta =
50          cos(2*theta)*vector(1,0,0)
51        + sin(2*theta)*vector(0,1,0);
52  
53      UA = uInfX*(dimensionedVector(vector(1,0,0))
54        - pow((radius/magCentres),2)*cs2theta);
55  
56      runTime.writeObjects();
57  
58      Info<< "end" << endl;
59  
60      return(0);
61  }
62  
63  // ************************************************************************* //

The utility must be compiled with wmake as normal. It can then be run by typing


    analyticalCylinder $OpenFOAM_RUN/potentialFoam cylinder
The analytical solution is plotted as streamlines as shown in Figure 3.3(c). Note that differences in the analytical and numerical solutions at the top plane are due to the fact that the analytical solution assumes an infinite boundary and the numerical solution specifies a zeroGradient boundary condition at that boundary.

3.1.7 Exercise

Investigate the accuracy of the numerical solution by implementing some measure of comparison between the numercial and analytical in analyticalCylinder.