You are on page 1of 48

Chapter 3 - Solutions of the Newtonian viscous-flow equations

Incompressible Newtonian viscous flows are governed by the Navier-Stokes equations


u
1
+ (u )u = p + 2 u + f ,
t

u = 0,

(1)
(2)

where u, p, , and f are the velocity vector, pressure, density, kinematic viscosity and body
forces respectively. The equations as written are independent of coordinate system, but they look
exactly the same using Cartesian coordinates. Of equally great importance, at least in chapter 3,
are the Navier-Stokes equations in cylindrical coordinates. The cylindrical coordinates, r, , z, are
given in terms of the Cartesian coordinates x, y, z as
x = r cos ,
y = r sin ,
z = z.
The Cartesian position vector is thus
x = r cos i + r sin j + zk.
The unit vectors in cylindrical coordinates are
ir =
i =
iz =

dx
dr
| dx
dr |
dx
d
| dx
d |
dx
dz
| dx
dz |

= cos i + sin j,
= sin i + cos j,
= k.

The velocity vectors in Cartesian and cylindrical coordinates read respectively


u(x, y, z, t) = ux i + uy j + uz k
u(r, , z, t) = ur ir + u i + uz iz
The gradient and the divergence of the velocity vector u in cylindrical coordinates are given
respectively by

= ir
+ i
+ iz
(3)
r
r
z
1 rvr
1 v
vz
u=
+
+
(4)
r r
r
z
Suggested assignment 1 Show that the following expressions are true

+ v
+ vz
r  r 
z
1

1 2
2
2 =
r
+ 2 2+ 2
r r
r
r
z

u = vr

(5)
(6)

y
x

2h

Figure 1: Laminar plane channel flow.


Suggested solution:



u = (vr ir + v i + vz iz ) ir
+ i
+ iz
r
r
z
v

+ i i
+ iz iz vz
u = ir ir vr
r
r
z
1

+ v
+ vz
u = vr
r
r
z
The cylindrical unit vectors are orthogonal, so the only nonzero terms are those with ik ik for
k = r, , z.
To find the Laplacian use the formula for divergence of a vector and insert for Eq. (3)
2 =

1 1r
1 r r
+
+ z
r r
r
z
2
1

1
2 =
r
+ 2 2+ 2
r r
r
r
z

2 =

Suggested assignment 2 Start from Eq. (1) and derive the momentum equations for Cylindrical
coordinates. The results are given in App B of White.

Laminar parallel shear flows


The Navier-Stokes equations are nonlinear because of the convective term, (u )u, and in general
not analytically solvable for most problems in fluid mechanics. The equations can be solved
analytically when the convective term is zero and for a few other simplified flows. In chapter 3 of
White we start by considering the types of flow where convection is zero.
The convection term is never negligible for turbulent flows, where the flow rapidly changes
direction in a seemingly chaotic fashion. We will get back to turbulent flows in Chapter 6. For
now we assume the flow is laminar. For a laminar flow the convection term will be zero for a
parallel shear flow where the geometry is infinite in at least one direction and the velocity vector is
parallel to the walls of the geometry. For example, a pipe flow or a plane channel flow as shown in
Fig. 1, where there is only one nonzero component of the velocity vector, and the velocity vector
is parallel to the surrounding walls. The gradient of this velocity component is normal to the wall

and as such u u = 0 and the Navier-Stokes equations reduce to the linear equations
u
1
= p + 2 u + f ,
t

u = 0.

(7)
(8)

Since the equations are linear it should not be surprising to find that there are many analytical
solutions available for laminar parallel shear flows.
If the only nonzero velocity component is in the x-direction, then u = (u, 0, 0) and the
Navier-Stokes equations reduce to
u
1 p
=
+ 2 u + fx ,
t
x
u
= 0.
x

(9)
(10)

which is also valid for the axial component of cylindrical coordinates (see Ch. 3-2.2). There are
two types of parallel shear flows: Couette and Poiseuille. Couette flows are driven by moving
walls. Friction, i.e., drag or viscous forces are then responsible for "dragging" the fluid with a
direction aligned with the wall. For Poiseuille flows the driving force is a pressure gradient that
can be generated using a pump.
Couette flows
We will first look at a steady plane Couette flow, like in Chapter 3-2.1, where the height of the
plane channel is 2h. There is no applied pressure and no gravitational forces in the x-direction, so
the Navier-Stokes equations reduce further to
2 u = 0,
u
= 0,
x

(11)
(12)

with boundary conditions u(h) = 0 and u(h) = U (see Fig. 3-1 in [7]). The exact solution of
these equations is
U
y
u(y) =
1+
.
(13)
2
h
We will now solve the Couette flow numerically using FEniCS, which is a software used for solving
differential equations with the finite element method (http://fenicsproject.org). An excellent
tutorial for quickly getting started with FEniCS can be found here [1].
FEniCS solves PDEs by expressing the original problem (the PDEs with boundary and
initial conditions) as a variational problem. The core of the recipe for turning a PDE into a
variational problem is to multiply the PDE by a function v, integrate the resulting equation over
the computational domain (typically called ), and perform integration by parts of terms with
second-order derivatives. The function v which multiplies the PDE is in the mathematical finite
element literature called a test function. The unknown function u to be approximated is referred
to as a trial function. The terms test and trial function are used in FEniCS programs too.
In this course we will learn how to use the FEniCS software, but the focus will be on the
physics of flow. We will use FEniCS to generate numerical solutions that we can easily play
with to enhance our understanding of what the mathematical equations represent, but we will
not go through the inner details of the finite element method. For those interested in a deeper
understanding, the finite element method is taught in, e.g., INF5620 and INF5650.
In the current case of a Couette flow we will solve Eq. (11). We assume here for completeness
that the equation has an additional constant source f
2 u = f.
3

(14)

We now multiply the Poisson equation by the test function v and integrate over the domain
= [h, h],
Z
Z
2
( u)v dx =
f v dx .
(15)

Note that dx is used to represent a volume integral. For Cartesian coordinates dx is equal to
dxdydz, whereas for cylindrical coordinates it equals rdrddz.
Next we apply integration by parts to the integrand on the left hand side with a second-order
derivative,
Z
Z
Z
u
(2 u)v dx =
u v dx +
v ds,
(16)

n
u
where n
is the derivative of u in the outward normal direction at the boundary (here at y = h).
The test function v is required to vanish on the parts of the boundary where u is known, which in
the present problem implies that v = 0 for y = h. The second term on the right-hand side of
Eq. (16) therefore vanishes for the current problem and we are left with
Z
Z

u v dx =
f v dx ,
(17)

which is also referred to as the weak form of the original boundary value problem (2 u = f
with boundary conditions). The finite element method discretizes and solves this weak form of
the problem on a domain divided into non-overlapping cells. In 2D we typically apply triangles,
whereas in 3D tetrahedrons are applied. For 1D problems like the Couette flow we simply divide
the computational domain into non-overlapping intervals.
The final step required for building a finite element solution is to choose an appropriate function
space for our solution. A function space can for example be piecewise linear functions or piecewise
polynomials of a higher degree. Different function spaces can be chosen for the trial and test
functions, but in general they only differ on the boundaries. The test and trial spaces V and V
are in the present problem defined as
V = {v H 1 () : v = 0 on y = h},
1

V = {v H () : v = 0 on y = h and v = U on y = h} ,

(18)
(19)

Briefly, H 1 () is known as the Sobolev space containing functions v such that v 2 and ||v||2
have finite integrals over . You will learn more about the Sobolev space in a basic finite element
course. For now it will be sufficient to know that you need to choose a function space and for
fluid flow it is usually appropriate to choose a space consisting of piecewise linear or quadratic
polynomials.
Note that the proper mathematical statement of our variational problem now goes as follows:
Find u V such that
Z
Z

u v dx =
f v dx v V .
(20)

Implementation The entire implementation that solves the variational problem (20) is given
in Listing 1. If this bit of code is stored in a textfile called "Couette.py", the program can be run
by typing "python Couette.py" on the command line of a bash shell in the same folder as the file is
stored. Alternatively one can enter an environment like Python or IPython (recommended: install
with "sudo apt-get install ipython") and execute the script there with "run Couette".
[....] ipython
In [1] run Couette

/* start ipython in a regular bash shell */


/* execute script in ipython shell */

A more thorough tutorial for the Poisson equation is given in [2]. Here we will repeat only the
most necessary steps. The first thing we need to do is to import all basic FEniCS functionality
into the python environment
from dolfin import *

"""
Couette flow
"""
from dolfin import *
h = 1.
N = 10
mesh = IntervalMesh (N , -h , h )
V = FunctionSpace ( mesh , CG , 1 )
u = TrialFunction ( V )
v = TestFunction ( V )
def bottom (x , on_boundary ) :
return near ( x [ 0 ] , -h ) and on_boundary
def top (x , on_boundary ) :
return near ( x [ 0 ] , h ) and on_boundary
U = 1.
bcs = [ DirichletBC (V , 0 , bottom ) ,
DirichletBC (V , U , top ) ]
u_ = Function ( V )
solve ( - inner ( grad ( u ) , grad ( v ) ) * dx == Constant ( 0 ) * v * dx , u_ , bcs = bcs )
u_exact = project ( Expression ( " U / 2 *( 1 + x [ 0 ]/ h ) " , U =U , h = h ) , V )
plot ( u_ , title = " Couette flow " )
plot ( u_ - u_exact , title = " Error couette flow " )

Code Listing 1: Couette.py

This is typically the first line of most FEniCS scripts as it imports all necessary functionality
like Interval,FunctionSpace,Function,DirichletBC,UnitSquare and much, much more. A
computational mesh is then generated by dividing the computational domain ( = [h, h]) into N
equally sized intervals, each of size 2h/N
h = 1.
N = 10
mesh = Interval (N , -h , h )

We now choose a piecewise linear solution by defining a function space over the mesh
V = FunctionSpace ( mesh , " CG " , 1 )
u = TrialFunction ( V )
v = TestFunction ( V )

Second order polynomials or higher may be chosen by using a higher number here, but for the
current problem this will not enhance the accuracy since the analytical solution is linear. The
trial and test functions u and v are then declared, just as described leading up to Eq. (20).
The current problem assigns a value for u on both boundaries, which is mathematically termed
Dirichlet boundary conditions. To implement these Dirichlet conditions we first need to specify
where the boundaries are using two python functions
def bottom (x , on_boundary ) :
return near ( x [ 0 ] , -h ) and on_boundary
def top (x , on_boundary ) :
return near ( x [ 0 ] , h ) and on_boundary

Here x is an array representing position. It is an array of length equal to the number of spatial
dimensions of the mesh. In our case it is an array of length 1. The boundary conditions are
created using the FEniCS function DirichletBC.
U = 1.

Figure 2: Numerical solution of the Couette flow.

bcs = [ DirichletBC (V , 0 , bottom ) ,


DirichletBC (V , U , top ) ]

Note that by using brackets [ ] the two boundary conditions are placed in a python list named bcs.
The variational problem is solved by creating a Function to hold the solution and then calling
the function solve.
u_ = Function ( V )
solve ( - inner ( grad ( u ) , grad ( v ) ) * dx == Constant ( 0 ) * v * dx , u_ , bcs = bcs )

The u Function has N + 1 unknowns, which are the solutions at the N + 1 nodes of the mesh.
However, it is important to remember that the finite element solution is not restricted to the nodes
of the mesh. The finite element solution is the piecewise continuous linear profiles, well defined
over the entire elements. You can look at the discrete solution at the nodes on the command line
as a numpy array using
w = u_ . vector () . array ()
print w

or plot the piecewise linear solution using


plot ( u_ , title = " Couette " , interactive = True )

The numerical result is shown in Fig. 2. The exact solution is given in Eq. (13). We can put the
exact solution in a FEniCS Function by projecting an Expression onto the same function space
as the numerical solution:
u_exact = project ( Expression ( " U / 2 *( 1 + x [ 0 ]/ h ) " , U =U , h = h ) , V )

The Functionu_exact will now contain N + 1 values, just like u , and if we have computed
correctly these values should be more or less the same as in u . A plot of the numerical solution
minus the exact solution shows that the computed solution is exact down to machine precision
1016 . This is to be expected since the solution is linear and we are assuming a piecewise linear
finite element solution.

Couette flow between axially moving concentric cylinders


The next example in Chapter 3-2.2 is the flow between axially moving concentric cylinders.
The equation is the same as for the regular Couette flow in 3-2.1, but the coordinate system is
cylindrical. There is no applied pressure gradient and the flow is described by the Poisson equation
with no source.

1
r r

2 u = 0,

u
r
= 0.
r

(21)
(22)

The two cylinders have diameters r0 and r1 , where r0 < r1 . The Dirichlet boundary conditions are
u(r = r0 ) = u0 and u(r = r1 ) = u1 . The solution to Eq. (22) can be found by integrating twice
u(r) = C1 ln(r) + C2 ,

(23)

where the two integration constants are found using the boundary conditions leading to
U1 U0
ln(r1 /r0 )
ln(r1 )
ln(r0 )
C2 = U0
U1
ln(r1 /r0 )
ln(r1 /r0 )

C1 =

which inserted into Eq. (23) gives


u(r) = U0

ln(r1 /r)
ln(r/r0 )
+ U1
.
ln(r1 /r0 )
ln(r1 /r0 )

(24)

Equation (24) is exactly the sum of Eqs. (3-18) and (3-19), which is a result of the governing
equation being linear.
The variational formulation of the problem reads
Z
Z

u v dx =
f v dx ,
(25)

but in Cylindrical coordinates the volume integral needs to be transformed (dx = rdr2L,
assuming the cylinder has length L) and the variational problem becomes
Z
Z

u v rdr =
f vr dr .
(26)

Note that the gradient requires no special treatment since the gradient component in the r-direction
is unchanged in cylindrical coordinates (see Eq. (3)).
A FEniCS implementation for axially moving concentric cylinders is shown in Listing 2.

Suggested assignments
Written assignments Problems 3-1, 3-2 and 3-3 in White [7].
Computer exercise Validate the analytical results (3-22) and (3-23) in Chapter 3-2.3 of White
[7], for flow between rotating concentric cylinders. Can you reproduce Eq. (3-23)? Suggested
solution is given in Listing 3.

"""
Couette flow between two axially moving cylinders
"""
from dolfin import *
import pylab
parameters [ r e o r d e r _ d o f s _ s e r i a l ] = False
r0 = 0 . 2
r1 = 1 .
u0 = Constant ( 1 )
u1 = Constant ( 1 )
mesh = IntervalMesh ( 1000 , r0 , r1 )
V = FunctionSpace ( mesh , " CG " , 1 )
u = TrialFunction ( V )
v = TestFunction ( V )
def inner _boundar y (x , on_boundary ) :
return near ( x [ 0 ] , r0 ) and on_boundary
def outer _boundar y (x , on_boundary ) :
return near ( x [ 0 ] , r1 ) and on_boundary
bc0 = DirichletBC (V , u0 , inner _boundar y )
bc1 = DirichletBC (V , u1 , outer _boundar y )
r = Expression ( " x [ 0 ] " )
F = inner ( grad ( v ) , grad ( u ) ) * r * dx == Constant ( 0 ) * v * r * dx
u_ = Function ( V )
# Compute all three s u b p r o b l e m s (3 - 2 ) and plot in the same figure
pylab . figure ( figsize =( 8 , 4 ) )
for u00 , u11 in zip ([ 1 , 1 , 1 ] ,[1 , -1 , 2 ]) :
u0 . assign ( u00 )
u1 . assign ( u11 )
solve (F , u_ , bcs =[ bc0 , bc1 ])
pylab . plot ( u_ . vector () . array () , mesh . coordinates () )
pylab . legend ([ " ( a ) " , " ( b ) " , " ( c ) " ] , loc = " lower left " )
pylab . xlabel ( " Velocity " )
pylab . ylabel ( " r " )
pylab . savefig ( " problem3 - 2 . pdf " )
u_exact = ( u1 - u0 ) * ln ( r ) / ln ( r1 / r0 ) + u0 - ( u1 - u0 ) * ln ( r0 ) / ln ( r1 / r0 )
u_exact = project ( u_exact , V )

Code Listing 2: AxiallyMovingCyl.py

"""
Flow between rotating concentric cylinders
"""
from dolfin import *
r0 = 0 . 2 ; r1 = 1
mesh = IntervalMesh ( 100 , r0 , r1 )
V = FunctionSpace ( mesh , CG , 1 )
u = TrialFunction ( V )
v = TestFunction ( V )
x = Expression ( " x [ 0 ] " )
w0 = Constant ( 1 .) ; w1 = Constant ( 0 . 1 )
T0 = Constant ( 8 ) ; T1 = Constant ( 10 )
mu = Constant ( 0 . 25 ) ; k = Constant ( 0 . 001 )
u_ = Function ( V )
T_ = Function ( V )
F = inner ( grad ( v ) , grad ( u ) ) * x * dx + u * v / x * dx
FT = inner ( grad ( v ) , grad ( u ) ) * x * dx - mu / k * v * x *( u_ . dx ( 0 ) - u_ / x ) ** 2 * dx
def inner_bnd (x , on_bnd ) :
return on_bnd and x [ 0 ] < r0 + DOLFIN_EPS
def outer_bnd (x , on_bnd ) :
return on_bnd and x [ 0 ] > 1 - DOLFIN_EPS
bci = DirichletBC (V , r0 * w0 ( 0 ) , " std :: abs ( x [ 0 ] - 0 . 2 ) < 1 .e - 12 " )
bco = DirichletBC (V , r1 * w1 , outer_bnd )
bcTi = DirichletBC (V , T0 , inner_bnd )
bcTo = DirichletBC (V , T1 , outer_bnd )
solve ( lhs ( F ) == rhs ( F ) , u_ , bcs =[ bci , bco ])
solve ( lhs ( FT ) == rhs ( FT ) , T_ , bcs =[ bcTi , bcTo ])
# Compute exact s o l u t i o n given in ( 3 . 22 )
ue = project ( r0 * w0 *( r1 /x - x / r1 ) / ( r1 / r0 - r0 / r1 ) +
r1 * w1 *( x / r0 - r0 / x ) / ( r1 / r0 - r0 / r1 ) , V )
# Compute exact s o l u t i o n given in ( 3 . 23 )
Tn = project (( T_ - T0 ) / ( T1 - T0 ) , V )
PrEc = mu * r0 ** 2 * w0 ** 2 / k / ( T1 - T0 )
Te = PrEc * r1 ** 4 / ( r1 ** 2 - r0 ** 2 ) ** 2 *(( 1 - r0 ** 2 / x ** 2 ) (1 - r0 ** 2 / r1 ** 2 ) * ln ( x / r0 ) / ln ( r1 / r0 ) ) + ln ( x / r0 ) / ln ( r1 / r0 )
Te = project ( Te , V )
print " \ nError velocity
= " , errornorm ( u_ , ue , degree_rise = 0 )
print " Error temperature = " , errornorm ( Tn , Te , degree_rise = 0 )
print " ??? Should be close to zero .\ n "
plot ( u_ ,
plot ( ue ,
plot ( Tn ,
plot ( Te ,

title = " Computed angular velocity " )


title = " Exact angular velocity ( 3 . 22 ) " )
title = " Computed temperature " )
title = " Exact temperature ( 3 . 23 ) " )

# Since I cannot r e p r o d u c e the t e m p e r a t u r e I have r e c o m p u t e d


# ( 3 . 23 ) a n a l y t i c a l l y . I plot that result here
C1 = w0 - r1 ** 2 *( w1 - w0 ) / ( r0 ** 2 - r1 ** 2 )
C2 = r1 ** 2 *( w1 - w0 ) / (1 - r1 ** 2 / r0 ** 2 )
C3 = ( T1 - T0 + C2 ** 2 * mu / k *( 1 / r1 ** 2 - 1 / r0 ** 2 ) ) / ln ( r1 / r0 )
C4 = T0 + C2 ** 2 * mu / k / r0 ** 2 - C3 * ln ( r0 )
Tee = project (( - C2 ** 2 * mu / k / x ** 2 + C3 * ln ( x ) + C4 - T0 ) / ( T1 - T0 ) , V )
plot ( C1 * x + C2 /x , mesh = mesh , title = " Recomputed velocity " )
plot ( Tee , mesh = mesh , title = " Recomputed temperature " )
print " \ nError recomputed temperature = " , errornorm ( Tn , Tee )
print " Which is a strong indication that ( 3 . 23 ) is wrong !! "

Code Listing 3: RotatingCylinders.py

Poiseuille flows
Poiseuille flows are driven by pumps that forces the fluid to flow by modifying the pressure. Fluids
flow naturally from regions of high pressure to regions of low pressure. Typical examples are
cylindrical pipe flow and other duct flows. Figure 1 illustrates a fully developed plane channel
flow. Fully developed Poiseuille flows exists only far from the entrances and exits of the ducts,
where the flow is aligned parallel to the duct walls. If we assume the flow is in the x-direction, as
shown in Fig. 3-6 of [7], then the velocity vector is u(y, z, t) = (u(y, z, t), 0, 0) and Navier-Stokes
equations can be simplified to
u
1 dp
= 2 u
,
t
dx
u
= 0,
x

(27)
(28)

The equations are still linear because the flow is aligned in one direction and convection is thus
zero. The only difference from Couette flow is that there is a non-zero source term in the pressure
gradient. The transient term on the left hand side is zero for stationary flows.
The total volume flow, Q, through any duct is found by integrating the velocity over the entire
cross section, C, of the duct
Z
Q=

udA.

(29)

Using Eq. (38) it is also possible to define an average velocity, u, through the duct
u=

Q
.
A

(30)

The average velocity is subsequently used to define the Reynolds number and certain friction
factors - engineering tools used to classify duct flow.
The circular pipe
For a steady cylindrical pipe flow with radius r0 the solution to Eq. (36) is found simply by
integrating twice and applying boundary conditions:


d
du
1 dp
r
=
,
(31)
r dr
dr
dx


d
du
r dp
r
=
,
(32)
dr
dr
dx
du
r2 dp
r
=
+ C1 ,
(33)
dr
2 dx
du
r dp C1
=
+
,
(34)
dr
2 dx
r
r2 dp
u(r) =
+ C1 ln(r) + C2 ,
(35)
4 dx
where C1 and C2 are integration constants. The constant C1 must be zero for the flow at the
center of the pipe to remain finite. The condition at the wall u(r0 ) = 0 gives
C2 =

r02 p
,
4 x

(36)

which leads to the final expression for the pipe flow


u(r) =


1 p 2
r0 r2
4 x
10

(37)

Combined Couette and Poiseuille flow


It is possible to combine an applied pressure gradient with moving walls. Such flows are termed
combined Couette-Poiseuille flows and they are governed by the Poiseuille Eq. (36). The solution
to a combined Couette-Poiseuille flow can be found as the sum of a Couette solution uc using
zero pressure gradient and a homogeneous Poiseuille solution up using zero velocity on walls. For
a plane channel with u(h) = U and u(h) = 0 the solution is thus found by solving the two
problems
2 uc = 0, uc (h) = U, uc (h) = 0,
1 dp
2 up =
, up (h) = 0.
dx

(38)
(39)

The combined solution u = uc + up is the solution to the original problem. This can be seen
by summing Eq. (47) and Eq. (48) and also evidently u(h) = uc (h) + up (h) = U and similarily
for y = h. The superposition is possible simply because the governing equation is linear. The
principle is used also for transient flows in both Chapters (3-4) and (3-5).
Noncircular ducts
For steady and fully developed duct flows the governing equation is simply the Poisson equation
2 u =

1 dp
.
dx

(40)

The equation is linear and very easy to solve numerically for any shape of the duct. There is
also a great number of analytical solutions available for noncircular duct flows, solutions that can
be used to verify the quality of the numerical software. The duct solutions are often used for
specifying inlet profiles to much more complicating geometries, where the flow enters the geometry
through a duct.
In Listing 4 we show a FEniCS code used to solve Eq. (49) for a rectangular duct spanned
as a 6 y 6 a and b 6 z 6 b . Of interest here is the computation of the very complicated
analytical expression for the velocity given as
16a2
u(z, y) =
3

dp

dx

(1)

i1
2

i=1,3,5,...



cosh(iz)/2a
cos(iy)/2a
1
.

cosh(ib)/2a
i3

(41)

The FEniCS implementation of this exact solution overloads the Expression class and you should
recognize Eq. (50) in the overloaded eval method. Here x is an array of the coordinates and x[0]
and x[1] represent y and z respectively. Unfortunately, the Python Expression u_exact is quite
slow to interpolate due to the non-vectorized for-loop. For this reason, a C++ version of the same
Expression is implemented instead, which speeds up the program with a factor of 45.
Analysing the error. In Listing 4 we compute the errornorm that compares the computed
finite element solution with the exact solution. This error will depend on the mesh size and the
order of the polynomial approximation. The error should disappear in the limit of a highly resolved
mesh or for very high order polynomials. Given the polynomial order, the rate at which the error
disappears can be computed by performing experiments with meshes of different resolution. We
assume that the error for a mesh of element size hi can be written as Ei = Chri , where C is a
constant. We now want to find the order r of which the error disappears with mesh refinement.
The order r can be found by computing Ei for two different hi s, i.e., Ei = hri and Ei1 = hri1 ,
and then isolate r:
ln(Ei /Ei1 )
r=
.
(42)
ln(hi /hi1 )
Running Listing 4 the rectangle problem is solved for a range of meshes and the output is
11

from dolfin import *


from numpy import cosh , cos
set_l og_activ e ( False )
dpdx = Constant ( - 0 . 01 )
mu = Constant ( 0 . 01 )
a = 2
b = 1
factor = 16 .* a * a / mu ( 0 ) / pi ** 3 *( - dpdx ( 0 ) )
class u_exact ( Expression ) :
def eval ( self , value , x ) :
u = 0
for i in range (1 , 500 , 2 ) :
u += (( - 1 ) **(( i - 1 ) / 2 ) *( 1 - cosh ( i * pi * x [ 1 ] / 2 . / a ) /
cosh ( i * pi * b / 2 / a ) ) * cos ( i * pi * x [ 0 ] / 2 . / a ) / i ** 3 )
value [ 0 ] = u * factor
# Much faster C ++ version
ue_code =
class U : public Expression
{
public :
double a , b , mu , dpdx ;
void eval ( Array < double > & values , const Array < double > & x ) const
{
double u = 0 .;
double factor = 16 .* a * a / mu / pow ( DOLFIN_PI , 3 ) *( - dpdx ) ;
for ( std :: size_t i = 1 ; i < 600 ; i = i + 2 )
u += pow ( -1 , (i - 1 ) / 2 % 2 ) *( 1 . - cosh ( i * DOLFIN_PI * x [ 1 ]/ 2 ./ a ) /
cosh ( i * DOLFIN_PI * b / 2 ./ a ) ) * cos ( i * DOLFIN_PI * x [ 0 ]/ 2 ./ a ) / pow (i , 3 ) ;
values [ 0 ] = u * factor ;
}
} ;
u_c = Expression ( ue_code )
u_c . a = float ( a ) ; u_c . b = float ( b )
u_c . mu = float ( mu ( 0 ) ) ; u_c . dpdx = float ( dpdx ( 0 ) )
def main (N , degree = 1 ) :
mesh = RectangleMesh ( -a , -b , a , b , N , N )
V = FunctionSpace ( mesh , CG , degree )
u = TrialFunction ( V )
v = TestFunction ( V )
F = inner ( grad ( u ) , grad ( v ) ) * dx + 1 / mu * dpdx * v * dx
bc = DirichletBC (V , Constant ( 0 ) , Do mainBoun dary () )
u_ = Function ( V )
solve ( lhs ( F ) == rhs ( F ) , u_ , bcs = bc )
# u_e = i n t e r p o l a t e ( u_exact () , V )
u_e = interpolate ( u_c , V )
bc . apply ( u_e . vector () )
u_error = errornorm ( u_e , u_ , degree_rise = 0 )
return u_error , mesh . hmin ()
E = []; h = []; degree = 1
for n in [5 , 10 , 20 , 40 , 80 ]:
ei , hi = main (n , degree = degree )
E . append ( ei )
h . append ( hi )
from math import log as ln
for i in range (1 , len ( E ) ) :
r = ln ( E [ i ] / E [i - 1 ]) / ln ( h [ i ] / h [i - 1 ])
print " h = % 2 . 2E E = % 2 . 2E r = % . 2f " % ( h [ i ] , E [ i ] , r )

Code Listing 4: RectangleDuct.py


12

h=4.47E-01
h=2.24E-01
h=1.12E-01
h=5.59E-02

E=6.40E-03
E=1.69E-03
E=4.29E-04
E=1.08E-04

r=1.76
r=1.92
r=1.98
r=1.99

showing the second order accuracy that is to be expected from using piecewise linear elements.
Changing the degree in the FunctionSpace to 2 the order should be three and the output quite
correctly reads:
h=4.47E-01
h=2.24E-01
h=1.12E-01
h=5.59E-02

E=2.14E-04
E=2.63E-05
E=3.27E-06
E=4.04E-07

r=3.13
r=3.03
r=3.01
r=3.02

Suggested assignments
Written assignments Problems 3-4 and 3-5 in White [7].
Computer exercise In White [7] Chap. 3-3.3 there are 6 analytical solutions provided for 6
different types of ducts. In this weeks computer assignment you are asked to verify the analytical
solutions (3-47), (3-49) and (3-52). Experiment with higher order "CG" elements (the solution is
then higher order continuous piecewise polynomials) and compute the errornorm. Does the error
vanish for higher order polynomials for all ducts or does it remain constant?

Unsteady duct flows


Unsteady plane shear flows are experienced by fluids where the driving forces are suddenly or
continuously changed. A fluid initially at rest will for example respond to a sudden increase in
the pressure gradient (we suddenly start the pump) and the volume flow through the duct will
then increase monotonically until steady state is reached. The applied pressure gradient may also
vary in time. Another scenario is that a wall is suddenly or continuously set in motion, dragging
with it the fluid initially at rest. Common for these flows is that the transient term in Eq. (36)
cannot be neglected.
Starting flow in a cylindrical pipe
When a fluid initially at rest suddenly is exposed to a constant pressure gradient, the fluid will
start to move as a response to the applied forces and the flow will increase for some time until
the steady state Poiseuille flow profile (46) is reached. For convenience we modify this equation
slightly here and write it for the steady velocity us as

us = um 1 r2 ,
(43)
where
um =

r02 p
4 x

(44)

and r = r/r0 . We use the superposition principle and split the equation into two contributions
u(r, t) = v(r, t) + us (r),

(45)

where u(r, t) is the complete solution and v(r, t) is the solution to the homogeneous Eq. (36) in
cylinder coordinates:
 2

v
v 1 v
=
,
(46)
+
t
r2
r r

13

subject to boundary condition v(r0 , t) = 0 and initial condition v(r, 0) = us (r). The equation
can be non-dimensionalized by multiplying with r02 / and using t = t/r02 and r = r/r0
v
2 v 1 v
= 2 +
.
r
r r
t

(47)

Equation (60) can be solved using a separation of variables v(


r, t) = V (
r)T (t). Inserted into
Eq. (60) we obtain
 2

dT
d V
1 dV
+
,
(48)
V
=T
d
r2
r d
r
dt


00
1 0
V T = T V + V ,
(49)
r
00
0
V + 1r V
T
=
,
(50)
T
V
where the dot and apostrophe represent ordinary derivatives with respect to t and r respectively.
Since the left hand side depends only on t and the right hand side only on r, both sides must be
equal to a constant. It turns out that the constant must be negative to satisfy the appropriate
boundary conditions. We call the new constant 2 and obtain the two separate ordinary
differential equations
T + 2 T = 0,

(51)

r2 V + rV + 2 r2 V = 0.

(52)

00

The first equation has solution


2

T (t) = e t .

(53)

The second equation can be rewritten using x = r and chain rule differentiation leading to
00

x2 V + xV + x2 V = 0,

(54)

with the apostrophe here being a derivative with respect to x. Equation (67) is Bessels differential
equation of zero order. The solution to Bessels equation is the Bessel function of the first kind of
order zero
J0 (x).
(55)
A solution to V becomes
V (
r) = AJ0 (
r),

(56)

where A is a constant. We now need to make sure that the boundary and initial conditions are
satisfied. The boundary condition requires V (1) = J0 () = 0. Figure 4 shows how the Bessel
function behaves. Apparently it looks somewhat like a damped cosine function with multiple
roots that we call k . The first four roots are located at x = 2.4048, 5.5201, 8.6537, 11.7915
corresponding to 1 , 2 , 3 , 4 . One general solution is thus
V (
r) = Ak J0 (k r)
with a total solution

(57)
2

v(
r, t) = Ak J0 (k r)ek t .

(58)

Since the equations are linear we can use superposition and obtain a total solution simply by
summing over multiple possible solutions
v(
r, t) =

Ak J0 (k r)ek t .

k=1

14

(59)

Figure 3: Plot of the Bessel function of first kind of zero order.


We now have a solution consisting of many constants that satisfy the boundary condition. It
remains to close these constants using the initial condition v(
r, 0) = um (1 r2 ).
We have

X
Ak J0 (k r) = um (1 r2 )
(60)
k=1

and we want to find Ak . To this end we use orthogonality


Z 1
xJn (k x)Jn (m x)dx = 0 for k 6= m

(61)

and orthonormality
1

xJn (k x)Jn (k x)dx =


0

2
Jn+1
(k )
.
2

(62)

If Eq. (73) is multiplied by rJ0 (m r) and integrated from zero to unity we get
Z

rJ0 (m r)
0

um (1 r2 )
rJ0 (m r)d
r.

Ak J0 (k r)d
r=

(63)

k=1

We now use (74) to eliminate all terms on the left hand side where k 6= m and insert for (75). The
result is a closed expression for Ak
Z 1
2
Ak = 2
rJ0 (k r)um (1 r2 )d
r.
(64)
J1 (k ) 0
The integral on the right hand side can be evaluated exactly (details left out for now) leading to
Ak =

4um J2 (k )
8um
= 3
2k J12 (k )
k J1 (k )

(65)

The final solution to starting flow in a cylinder, Eq. (59), becomes


u(
r, t) = um (1 r2 )

X
8um J0 (k r)
k=1

in agreement with Eq. (3-96) in White [7].


15

3k J1 (k )

ek t

(66)

Pipe flow due to an oscillating pressure gradient


Consider now the same problem as in the previous section, but with a pressure gradient that is
oscillating in time
p
= Keit ,
(67)
x

where i = 1 and
eit = cos t + i sin t.
(68)
The governing equation for the cylinder is thus
u
= Keit +
t

2 u 1 u
+
r2
r r


.

(69)

We now want solve Eq. (82) with no-slip boundary conditions on the cylinder walls. We will
neglect the initial condition and look only for a long-term steady oscillatory solution on the form
u(r, t) = eit V (r).

(70)

That is, we look for a solution where all the transient behaviour is governed by an oscillating
pressure gradient proportional to eit .
Inserting for Eq. (83) in Eq. (82) and using the same nomenclature as in the previous section
we obtain


1 0
it
it
it
00



V i
e = K
e + 
e
V + V
r


1
V i = K + V 00 + V 0
r
2
i
Kr
r2 V 00 + rV 0 r2 V =
.

p
Using x = r i/ and chain rule differentiation the equation can be rewritten as
x2 V 00 + xV 0 x2 V =

Kx2
,
i

(71)

where the apostrophe now represents differentiation with respect to x. This equation looks very
much like a modified Bessel equation [3] of zero order. The only difference is the right hand side,
which should be zero. To get rid of the right hand side we use another change of variables
V = V +

K
i

(72)

and insert this in Eq. (84) such that


x2 V 00 + xV 0 x2 V = 0.

(73)

The solution to the modified Bessel equation of zero order is the modified Bessel function of the
first kind (the second kind cannot be used since this function is infinite for x = 0) of zero order,
I0 , so
V (x) = AI0 (x),
(74)
or in terms of the ordinary Bessel function:
V (x) = AJ0 (ix),
where A is a constant. With this result we can now express the total solution as


p
K
it
u(r, t) = e
AI0 (r i/) +
.
i
16

(75)

(76)

The boundary condition requires u(r0 , t) = 0, which determines A:


A=

K
p

iI0 (r0

i/)

(77)

Inserted into Eq. (89) we are left with


!

I0 (r i)
p
1
,
I0 (r0 i/)

(78)

!
p
i/)
p
1
,
J0 (r0 i/)

(79)

Keit
u(r, t) =
i
or
Keit
u(r, t) =
i

J0 (r

in accordance with Eq. 3-98 in White [7].


The Bessel function can be found in the toolbox scipy.special. The solution is computed in
Listing 5 and the result is shown in Fig. 5 for a relatively large normalized
= r02 / = 10. A
smaller value of
will result in velocity profiles closer to the steady Poiseuille profile umax (1 r2 ).
from numpy import *
from pylab import *
from scipy . special import jv
r0 = 1
w = 0.1
K = 1.0
nu = 0 . 01
r = linspace (0 , r0 , 50 )
ws = w * r0 ** 2 / nu
def u ( t ) :
return K / 1j / w * exp ( 1j * w * t ) *( 1 - jv (0 , r * sqrt ( - 1j * w / nu ) ) / jv (0 ,
r0 * sqrt ( - 1j * w / nu ) ) )
figure ( figsize =( 6 , 4 ) )
ll = []
for i in range ( 6 ) :
print 1 / w * i * 2 * pi / 6
plot ( u ( i / ( 6 * w ) * 2 * pi ) , r )
ll += [ r "t = 0 " . format ( i ) ]
legend ( ll )
axis ([ - 15 , 25 , 0 , 1 ])
xlabel ( " Velocity " )
ylabel ( " Radial position " )
show ()

Code Listing 5: plotCylOscillatingGradient.py

Unsteady flows with moving boundaries


In the previous section the driving force for the oscillating flow was the pressure gradient. Transient
behaviour can also be obtained for Couette type flows, where the velocity of the walls are either
(1) Suddenly accelerated to a constant velocity uwall = U0 .
(2) Oscillated as a function of time, i.e., uwall = f (t).
The governing equation for these types of flow is the homogeneous heat equation
u
= 2 u.
t
17

(80)

Figure 4: Velocity profiles in a pipe with an oscillating pressure gradient. The parameter
= 2/w/6, such that an entire period is obtained for t = 6 .
We consider only parallel shear flows in Cartesian coordinates, where the velocity vector is
u = (u(y, t), 0, 0) and the equation is reduced to
2u
u
= 2.
t
y

(81)

There are many different solutions available for this 1D heat equation, depending on the boundary
and initial conditions of the problem. Most solutions make use of the Fourier series, the Fourier
integral or Fourier transforms, see, e.g., Kreyszig [6].
As a first example of flow that is suddenly accelerated to a constant velocity, consider a infinite
plane normal to the y-axis located at y = 0 and initially at rest at t = 0. The plane is then
suddenly accelerated to a constant velocity U0 in the x-direction and remains at this velocity
for all t > 0. Above the plane, for y > 0, the fluid is initially at rest. Friction and the no-slip
boundary condition will make the flow above the plane increase in speed. Far away from the plane
the velocity will be zero, i.e., u(, t) = 0. This means that the velocity will never reach a steady
state, and the boundary layer over the plane will continue to grow for all time.
We can find the solution as before using a separation of variables, but first we normalize the
velocity
u U0
v(y, t) =
,
(82)
U0
such that the boundary condition at y = 0 becomes homogeneous, i.e., v(0, t) = 0 for t > 0. The
PDE for v is still Eq. (94).
Start by separating variables
v(y, t) = T (t)V (y).
(83)
Inserted into Eq. (94) we get
T
V 00
=
= K,
(84)
T
V
where K is a constant. To obtain physically realistic solutions, the constant needs to be negative.
This can be understood looking first at the transient part:
T = KT,

18

(85)

with solution
T (t) = eKt .

(86)

If K is positive, then the velocity will grow without bounds and without energy being added to
the system. For the second equation we have
V 00 KV = 0.

(87)

V (y) = A sinh( Ky) + B cosh( Ky).

(88)

If K is positive, then the solution is

The boundary condition V (0) = 0 requires B = 0. The remaining term A sinh( Ky) grows
without bounds as y , which is not in agreement with v(, t) = 1 and we have to assume
that K is a negative constant that we can write as K = 2 . The solutions to the separated
ordinary differential equations become
2

T (t) = e

(89)

V (y) = A sin(y) + B cos(y).

(90)

The constants need to be found using boundary and initial conditions. The boundary condition
V (0) = 0 leads to B = 0 and as such one solution reads
2

v(y, t) = A sin(y)e

(91)

To satisfy the initial condition we need to use more than one solution and through the superposition
principle we can simply add solutions. A periodic Fourier series for v reads
v(y, t) =

Ak sin(k y)ek t ,

(92)

k=1

where Ak are constants, k = k/L and L is the length of the periodic domain.
However, our domain is not periodic and it is unbounded for y . It turns out that
for infinite domains and non-periodic solution, it is advantageous to work with Fourier integrals
instead. A Fourier integral for our problem reads
Z
2
v(y, t) =
A() sin(y)e t d.
(93)
0

and the "constant" A() is a continuous function of . Since v only contains sinuses it is an odd
function. As such, even though we are only interested in the domain y > 0 we can define an initial
condition for v(y, 0) over the entire < y < as an odd function
Z
v(y, 0) = 1 2H(y) =
A() sin(y)d, for < y < ,
(94)
0

where H(y) is the Heaviside function. This way v(y, 0) = 1 for y < 0, v(y, 0) = 1 for y > 0 and
by symmetry v(0, 0) = 0. Through orthogonality and the initial condition we can find A() as
(see Kreyszig [6])
Z
2
A() =
sin(y 0 )dy 0 .
(95)
0
Inserted into the total solution we get
Z Z
2
2
v(y, t) =
sin(y 0 )dy 0 sin(y)e t d,
0
0

19

(96)

Figure 5: Plot of the initial condition for function v(y, 0) = 1 2H(y).


which can be rewritten by changing the order of integration as
Z Z
2
2
v(y, t) =
sin(y 0 ) sin(y)e t ddy 0 .
0
0

(97)

The inner integral can be transformed using sin(y) sin(y 0 ) = 0.5(cos (y y 0 ) cos (y + y 0 ))
Z Z
2 2 t 1
e
(cos (y y 0 ) cos (y + y 0 )) ddy 0 .
(98)
v(y, t) =
0
2
0
The inner integrals can then be computed exactly since
r
Z
2

e t cos (y y 0 )d =
e
4t
0
and
Z

cos (y + y 0 )d =


e
4t

yy 0

2 t

2

y+y 0

2 t

2

(99)

(100)

dy 0 .

(101)

The solution now reads


r
v(y, t) =

1
4t

yy 0

2 t

2

y+y 0

2 t

2 

Using integration by substitution, the integrals can be reorganized into error functions
Z z
2
2

erf(z) =
eu du,
0

(102)

if we simply use a change of variables


y y0
,
2 t
y + y0
u0 = ,
2 t
u=

du
1
=
dy 0
2 t
du
1
=
dy 0
2 t

(103)
(104)

The integrals become


Z

yy 0

2 t

2

Z
dy 0 = 2 t

eu du,

(105)

2 t





= t 1 erf
2 t
20

(106)

Figure 6: Velocity profiles for flow over a plane that is suddenly accelerated from zero to U0 .
and
Z

y+y 0

2 t

2

Z
dy 0 = 2 t

eu du,

(107)

2 t




y

t 1 erf
.
2 t

Putting it all together we finally obtain


r


1 
v(y, t) =
t (2)erf
4t


y

.
= erf
2 t

2 t

(108)


,

(109)
(110)

The original unnormalized velocity becomes





y

u(y, t) = U0 1 erf
,
2 t

(111)

in agreement with Eq. 3-107 in White [7]. Profiles for the velocity above the plane is shown in
Fig. 7.

Suggested assignments
Written assignments
conditions

Consider the homogeneous heat equation with inhomogeneous boundary


u
2u
2 = 0, for
t
y
u(y, 0) = (y),

0yL

u(0, t) = g,
u(L, t) = h
where g and h are constants. Find the general solution u(y, t). Hint: use a function U (y) =
1/L[(L y)g + yh] and find the solution of v(y, t) = u(y, t) U (y). The equation for v(y, t) is the
same as for u(y, t), but now with homogeneous boundary conditions.
Optional (difficult), find the general solution if g and h are functions of time. Two hints to the
optional assignment are
21

Figure 7: Velocity profiles for flow over a plane that is suddenly accelerated from zero to U0 . Plot
of the entire solution including the unphysical domain.
Computer assignment Choose suitable g and h and compare the analytical solution from the
written assignment with a numerical implementation.
Transient problems Transient problems are usually solved in FEniCS using a finite difference
approximation of the time derivative. The time dimension can be discretized using constant discrete
time intervals of length 4t, and we look for solutions at the discrete times t = [0, 4t, 24t, ..., T
4t, T ] = k4t, for k = 0, 1, 2, ..., N 1, N , 4t = T /N . The solutions at the N + 1 different
timesteps are similarly written as uk . Using finite differences for the time derivative, a variational
form of the heat equation reads
Z k
Z
1
u uk1
vdx =
uk 2 vdx,
(112)
4t

where the right hand side is computed at the midpoint between timesteps k and k 1 using
1
notation uk 2 = (uk + uk1 )/2. Note that when the solution is computed, we start at the initial
condition at k = 0, where the initial condition u0 is known and u1 is unknown. When u1 is
subsequently computed and known, we are ready to move on to the next solution u2 and so on.
In other words, uk is always the unknown we are trying to compute and uk1 , uk2 , ... are all
considered to be known. In FEniCS the unknown uk is represented in Forms as a TrialFunction,
whereas all knowns are represented as Functions. A variational form for the heat equation in
FEniCS may look like:
u = TrialFunction ( V )
v = TestFunction ( V )
u_ = Function ( V )
# Known s o l u t i o n at k
u_1 = Function ( V )
# Known s o l u t i o n at k - 1
dt = Constant ( 0 . 1 )
nu = 0 . 01
U = 0 . 5 *( u + u_1 )
F = inner ( u - u_1 , v ) * dx + dt * nu * inner ( grad ( U ) , grad ( v ) ) * dx

The solution of the form must be placed inside a loop, advancing the solution forward in time,
something like:
t = 0
while t < T :
t += dt
solve ( lhs ( F ) == rhs ( F ) , u_ , bcs )

22

# Advance s o l u t i o n to next t i m e s t e p :
u_1 . vector () [:] = u_ . vector () [:]

The python functions lhs and rhs are used to extract bilinear (terms containing both trialand testfunctions) and linear (terms containing only testfunction and no trialfunction) forms
respectively. The last line of code copies all the values from u_ to u_1. Note that uk is the
unknown we look for at timestep k. In the variational form uk is represented as an unknown
TrialFunction. However, when the variational form has been solved, the known solution can be
found in the Function u_ and we are then finished with timestep k. When we now move on to
the next timestep, the solution we just found becomes the solution at the previous timestep, i.e.,
at k 1. This is why we copy all values from u_ to u_1 as our final task in the time loop.
Suggested solution to computer assignment is given in Listing 6.
Fluid oscillation above an infinite plate
An infinite plate oscillates with a velocity u(0, t) = U0 cos(t), which is the boundary condition to
the fluid flow set in motion above the plate. We look for a "steady state" solution u = (u(y), 0, 0),
meaning that we look for a solution independent of initial conditions. This problem is also referred
to as Stokes second problem.
Since the plate oscillates with frequency cos(t) a justified guessed solution is
u(y, t) = f (y)eit .
Inserted into the unsteady 1D heat equation we obtain
 f 00
 = 0,
f i
eit
eit
00
i
f f =0

A general solution to this problem is


f (y) = Ae

+ Be

where only the first leads to physically realistic real solutions for y , such that B = 0. The
boundary condition at y = 0 leads to
u(0, t) = f (0)eit = Aeit ,
where the real part then requires A = U0 and as such
i
u(y, t) = U0 e y+it
Unsteady flow between two infinite plates
Consider two infinite plates separated by a distance h containing fluid initially at rest at t = 0. At
t = 0 the velocity of the lower plate at y = 0 is suddenly accelerated to a velocity of U0 and the
fluid above the plate starts to move due to friction and the no-slip boundary condition. The flow
will approximate the steady linear Couette solution U0 (1 y/h) as t . Find the velocity
between the plates as a function of time and space.
The velocity, u = (u(y), 0, 0), is parallel to the walls and described by the 1D heat equation
u
2u
2 = 0,
t
y
u(y, 0) = 0,
u(0, t) = U0 ,
u(h, t) = 0
23

for

0yh

0<y<h

from dolfin import *


import numpy
U0 = 1 .
L = 1.
nu = 0 . 01
w = 0.1
mesh = IntervalMesh ( 40 , 0 , L )
V = FunctionSpace ( mesh , CG , 1 )
u = TrialFunction ( V )
v = TestFunction ( V )
T = 100 .
N = 200
dt = T / N
t = 0.
g = Constant ( U0 * numpy . cos ( w * t ) )
h = 0
bc0 = DirichletBC (V , g , " std :: abs ( x [ 0 ]) < 1e - 12 " )
bcL = DirichletBC (V , h , " std :: abs ( x [ 0 ] - { } ) < 1e - 12 " . format ( L ) )
u_ = interpolate ( Expression ( " U0 *( 1 - x [ 0 ]/ L ) " , U0 = U0 , L = L ) , V )
u_1 = Function ( V )
u_1 . vector () [:] = u_ . vector () [:]
class u_exact ( Expression ) :
def eval ( self , value , x ) :
value [ 0 ] = U0 *( 1 - x [ 0 ] / L ) * cos ( w * t )
f = 0
for i in range (1 , 20 ) :
Ln = i * pi / L
df = sin ( Ln * x [ 0 ]) / Ln *(( - w * cos ( w * t ) + Ln ** 2 * nu * sin ( w * t )
+ w * exp ( - Ln ** 2 * nu * t ) ) / ( w ** 2 + Ln ** 4 * nu ** 2 ) )
f += df
value [ 0 ] += f * 2 * U0 * w / L
F = inner (u - u_1 , v ) * dx + dt * nu * inner ( v . dx ( 0 ) , 0 . 5 *( u . dx ( 0 ) + u_1 . dx ( 0 ) ) ) * dx
equation = lhs ( F ) == rhs ( F )
ue = Function ( V )
uex = u_exact ()
for t in numpy . linspace ( dt , T , N ) :
g . assign ( U0 * numpy . cos ( w * t ) )
solve ( equation , u_ , bcs =[ bc0 , bcL ])
u_1 . vector () [:] = u_ . vector () [:]
plot ( u_ , title = " Velocity " )
ue . vector () [:] = interpolate ( uex , V ) . vector () [:]
plot ( ue , title = " Exact U " )
print " Errornorm = " , errornorm ( u_ , ue , degree_rise = 0 )
interactive ()

Code Listing 6: HeatInhomogenBC.py

24

Through a shift of variables and using the steady Couette solution v(y, t) = u(y, t) U0 (1 y/h),
the problem can be redefined with homogeneous boundary conditions
v
2v
2 = 0, for 0 y h
t
y
v(y, 0) = U0 (1 y/h), 0 < y < h
v(0, t) = 0,
v(h, t) = 0
We can solve this problem easily using separation of variables v(y, t) = T (t)V (y). Inserted into
the heat equation we obtain as before
V 00
T
=
= 2
T
V
and two ordinary differential equations for T and V
2

T (t) = e

V (y) = A sin(y) + B cos(y).


The boundary conditions give us B = 0 and = n = n/h for n = 1, 2, . . .. Using superposition
we get the total solution for v(y, t):
v(y, t) =

An sin(n y)en t ,

n=1

where the coefficients are found using the initial condition and orthogonality. That is, multiply
v(y, 0) by sin(m ), integrate from 0 to h and isolate An :
Z
2U0 h
An =
sin(n y)(1 y/h)dy
h 0
2U0
An =
n
The total solution is then
u(y, t) = U0 (1 y/h)

2U0 X sin(n y) 2n t
e
.
n=1
n

Similarity solutions
Similarity solutions are obtained when the number of independent variables describing a problem
is reduced by at least one. We will first illustrate this by revisiting Stokes first problem - A fluid
initially at rest in an infinite domain (y ) is suddenly set in motion by an infinite flat plate
located at y = 0. We have already found the solution to this problem using Fourier integrals. The
solution is given in Eq. (124) and repeated here



y

u(y, t) = U0 1 erf
.
2 t
We will now look at this problem again and try to find a solution using a similarity approach.
First define a similarity variable
y
= ,
2 t
and observe that the solution can be written in terms of merely one variable
u() = U0 (1 erf()) .
25

Usually we dont know the solution and have to guess a similarity variable. Having defined , the
heat equation can be rewritten using chain rule differentiation
!
 2
du 2
du
d2 u
+

= 0.
d t
d 2 y
d y 2
The partial derivatives of are

= ,
t
2t

1
= ,
y
2 t
2
= 0.
y 2
Inserting this into the above leads to and ordinary differential equation for u(), which is exactly
what we were hoping to achieve
du d2 u
2
+ 2 = 0.
d
d
This ordinary differential equation must be solved using boundary conditions u(0) = U0 and
u() = 0. Define first h() = du/d and rewrite the ODE as
2h +

dh
= 0.
d

Separate variables and integrate to obtain


2
du
= Ae .
d

Integrate one more time to obtain


u() = Aerf() + B
Inserting for the boundary conditions we finally get the original solution derived with much more
effort in Eq. (124).

Suggested assignments
Written assignments Problem 3-15, 3-16, 3-17 from White [7].
Plane stagnation flow
Another well known and much used similarity solution is the streamfunction (x, t), that is most
often used for two-dimensional flows, where it is defined through
u=

,
y

v=

.
x

(113)

In 2D the only non-zero component of the vorticity vector, z , is computed as


z =

v
u

,
x y

(114)

If this definition is combined with Eq. (137) we obtain a Poisson equation for the streamfunction
2 = z .
26

(115)

The streamfunction is much used for inviscid irrotational flows, where the vorticity component
z = 0. However, the definition of the streamfunction is equally valid for viscous flows.
An illustration of plane stagnation flow is given in Fig. (3-24) of [7]. For inviscid flows the
solution is trivially obtained as
= Bxy,

u = Bx,

v = By,

(116)

where B is a positive constant. Make sure to check that the solution satisfies both Eq. (139) (with
zero right hand side) and the continuity equation
u v
+
= 0.
x y

(117)

For viscous flows it is somewhat more complicated, since the right hand side of Eq. (139) is
nonzero. To find the solution for viscous flows we also need to consider the momentum equations
in two dimensions

 2
u
u
1 p
u 2u
+v
u
+
,
=
+
x
y
x
x2
y 2

 2
2v
v
v
1 p
v
+
.
(118)
u
+v
=
+
x
y
y
x2
y 2
These equations are nonlinear due to the two underlined terms and coupled through the continuity
equation. Note that there are three equations for the three unknowns u, v, p, so the equations are
closed. We will now look for a similarity solution through a modification of the streamfunction of
the form

df

= Bxf (y), u =
= Bx , v =
= Bf.
(119)
y
dy
x
Using an apostrophe for the derivative of f with respect to y one has immediately
0
u
= Bf ,
x
v
= 0,
x

00
u
= Bxf ,
y
0
v
= Bf ,
y

2u
= 0,
x2
2v
= 0,
x2

000
2u
= Bxf ,
y 2
00
2v
= Bf .
y 2

We immediately see that the continuity equation is satisfied. Inserting for the streamfunction in
Eq. (142) we obtain
0

1 p
,
x
0
00
1 p
B 2 f f + Bf =
y
00

B 2 x(f )2 B 2 xf f Bxf

000

The last equation here states that p/y is only a function of y and thus
2p
= 0.
xy
The momentum equation in the x-direction can be simplified by dividing through by Bx
f

000


0
B  00
1 p
f f (f )2 =

Bx x

The left hand side is only a function of y and the right hand side only of x. Treating the right hand
0
00
000
side as a constant we can compute its value using the boundary conditions f = 1, f = f = 0

27

for y (the first follows from freestream condition uviscous = uinviscid ). Inserted for the
boundary conditions we obtain finally
f

000


0
B
B  00
f f (f )2 = .

(120)

Note that Eq. (144) is an exact equation for stagnation flow, since no terms have been eliminated in its derivation. The equation is nonlinear, which calls for iterative numerical
p solution
techniques.
The
equation
can
be
nondimensionalized
using
lengthand
velocityscales
/B and

B respectively, and the dimensionless variables


r

B
, = xF () B.
(121)
=y

We can now easily obtain


r

,
B
r r
r
0
0
0
dF d
B
f =
=F
=F ,
d dy B
B
r
0
00
00
B
dF d
=F
,
f =
d dy

f (y) = F

00

000

000 B
dF d
=F
.
d dy

Inserted into Eq. (144) we obtain the dimensionless equation


F

000

00

+ F F + 1 (F )2 = 0,
0

(122)
0

that can be solved using boundary conditions F (0) = F (0) = 0 and F () = 1.


Axisymmetric stagnation flow
The plane stagnation flow discussed in the previous section is stagnant for a line in the z-plane
located at x = 0. Axisymmetric stagnation flow is similar in form, but only stagnant in a single
point located at x = y = z = 0. This axisymmetric flow is what you obtain by pointing a garden
hose directly towards a plane wall (neglecting gravity). The equations are similar to the plane flow,
but may be simplified using cylindrical coordinates. A streamfunction in cylindrical coordinates
can be defined through
1
1
, uz =
(123)
ur =
r z
r r
For axisymmetric flows with u = 0 the continuity equation reads
1 rur
uz
+
= 0.
r r
z
Inserting for Eq. (147) it is easily verified that continuity is satisfied.
The streamfunction for axisymmetric inviscid flow towards a stagnation point is given as
= Br2 z
which leads to velocity components
ur = Br,

uz = 2Bz

28

For viscous flows one may obtain a dimensionless similarity solution using
r

B
2
= r F () B, = z
.

Inserting into the momentum equation for ur the mathematics are very much like in the previous
section leading to
000
00
0
F + 2F F + 1 (F )2 = 0.
(124)
This differs from plane stagnation flow only by the factor 2.

Numerical solution of nonlinear equations


Equation (146) and Eq. (148) are nonlinear and no analytical solutions are known. Very few
techniques are actually available for solving nonlinear equations analytically and as such we usually
have to rely on numerical methods to obtain solutions for real fluid flows. Reynolds Averaged
Navier-Stokes equations, that will be discussed thoroughly in chapter 6 of White [7], are basically
Navier-Stokes equations with a nonlinear viscosity coefficient. In this section we will consider two
of the most important techniques for iteratively solving nonlinear equations: Picard and Newton
iterations.
The general procedure for obtaining solutions to nonlinear equations is to guess an initial
solution and then successively recompute new and hopefully better approximations to the solution.
This is illustrated nicely with Newtons method (also called Newton-Raphsons method). Consider
a nonlinear function f (x) of one variable x (e.g., f (x) = x2 1 or f (x) = x sin(x) 1), where one
is interested in finding the roots x such that f (x) = 0. Newtons method boils down to making an
initial guess x0 that does not satisfy our equation (i.e., f (x0 ) 6= 0) and from this initial guess we
successively compute better approximations to the final root:
Guess x0 ,

n=0

while not f (xn ) 0 do


xn+1 = xn

f (xn )
f 0 (xn )

n=n+1
That is, compute x1 from x0 and check if the solution is close enough to the root. If not, compute
x2 using x1 as initial condition. Repeat until f (xn ) 0.
When PDEs are solved numerically we obtain through discretization a system of many equations
for many variables. Newtons method extends easily to systems of equations as well. Consider 2
equations with two unknowns written compactly as F (x)
(
x2 + 2xy = 0,
F (x) =
(125)
x + 4y 2
= 0,
where x = (x, y)T . The vector F has two components (the two equations) and there are two
unknowns. We can compute the derivative of F with respect to x


Fi
2x + 2y 2x
=
.
(126)
Jij =
1
8y
xj
The derivative is often called the Jacobian. Newtons method for these two equations (or any
system of equations) is simply
J(xk )(xk+1 xk ) = F (xk ),

(127)

or with index notation for equation i


k
Jij
(xk+1
xkj ) = Fik ,
j

29

(128)

where the k index signals that both J and F are computed using the solution at iteration step k.
There is no summation on repeated ks.
A discrete finite element solution of the function u can be written as
u(x) =

N
X

ui vi (x),

(129)

i=0

where vi are the testfunctions. The solution has N + 1 unknowns ui , or "degrees of freedom", that
for a linear Lagrange element are the values at the vertices of the mesh. When a PDE containing
both trial- and testfunctions is assembled in FEniCS a set of N + 1 linear equations arise for these
unknowns. We will now see how nonlinear equations can be handled by FEniCS.
Nonlinear Poisson equation
Consider the nonlinear Poisson equation
(q(u)u) = f (u),

(130)

where q and f may be nonlinear functions of u. Using testfunction v as in Eq. (18) and neglecting
the boundary term the variational form reads
Z
Z
q(u)u vdx =
f (u)vdx.
(131)

This is a nonlinear variational form and we need to solve it iteratively.


Newtons method Consider first Newtons method for solving the nonlinear Poisson equation.
We use the notation uk for the known solution at iteration step k and u the unknown trialfunction
as before in Eq. (19). For Newtons method we write the variational form solely in terms of known
functions
Z
Z
F (uk ; v) =
q(uk )uk vdx
f (uk )vdx.
(132)

F (u ; v) is a linear form in that it does not contain the unknown u, only the testfunction v. It is a
nonlinear form in terms of the known Function uk though. The Jacobian of F (uk ; v) is computed
is FEniCS as
u_ = Function ( V )
v = TrialFunction ( V )
F = inner ( q ( u_ ) * grad ( u_ ) , grad ( v ) ) * dx - inner ( f ( u_ ) , v ) * dx
J = derivative (F , u_ , u )

where q(u_) and f(u_) are some python functions returning the coefficient of the equation and
the source respectively. The function q might for example be coded like
def q ( u ) :
return 1 + u

which of course must appear in the script before creating the form F. A complete implementation
that solves the nonlinear Poisson equation on the unit interval x=[0, 1] is shown in Listing 7.
Note that everything below the line with solve(F == 0, u_, [bc0, bc1]) actually can be replaced
simply by using this very compact call. The part from J = derivative(F,u_, u) and out is
included here simply to illustrate how Newtons method works in practise.
Picard iterations
For Picard iterations we have to linearize the variational form in Eq. (155) ourself. Let us first
linearize such that the coefficient is known:
Z
Z
k
F (u; v) =
q(u )u vdx
f (uk , u)vdx
(133)

30

from dolfin import *


mesh = U n i t I n t e r v a l Me s h ( 10 )
V = FunctionSpace ( mesh , CG , 1 )
u = TrialFunction ( V )
v = TestFunction ( V )
bc0 = DirichletBC (V , Constant ( 0 ) , " std :: abs ( x [ 0 ]) < 1e - 10 " )
bc1 = DirichletBC (V , Constant ( 1 ) , " std :: abs ( x [ 0 ] - 1 ) < 1e - 10 " )
def q ( u ) :
return 1 + u ** 4
u_ = interpolate ( Expression ( " x [ 0 ] " ) , V )
F = inner ( grad ( v ) , q ( u_ ) * grad ( u_ ) ) * dx
# # solve ( F == 0 , u_ , [ bc0 , bc1 ])
J = derivative (F , u_ , u )
du = Function ( V )
error = 1 ; k = 0
while k < 100 and error > 1e - 12 :
A = assemble ( J )
b = assemble ( - F )
[ bc . apply (A , b , u_ . vector () ) for bc in [ bc0 , bc1 ]]
solve (A , du . vector () , b )
u_ . vector () . axpy ( 1 . , du . vector () )
error = norm ( du . vector () )
print " Error = " , error
k += 1

Code Listing 7: nonlinearNewton.py

The first term on the rhs of F (u; v) is bilinear in that it contains both trial- and testfunctions u
and v. The equation is also linear in u, which is necessary for FEniCS to accept it. Note that the
function f could be linear in u as well. For example, if f (u) = u2 , then we can linearize it like
f (u) = u uk . Picard iterations are implemented as Newton up to the point where the form is
created. The remaining part of the Picard code reads:
F = inner ( grad ( v ) , q ( u_ ) * grad ( u ) ) * dx
k = 0
u_1 = Function ( V )
while k < 100 and error > 1e - 12 :
solve ( F == Constant ( 0 ) * v * dx , u_ , [ bc0 , bc1 ])
error = errornorm ( u_ , u_1 )
u_1 . assign ( u_ )
print " Error = " , k , error
k += 1

The Function u_1 holds the previous solution and u_1.assign(u_) copies all values from the
newly computed u_ to u_1.
On my laptop computer Newtons method requires 4 iterations to converge, whereas Picard
requires 12. This is quite typical. Newtons method is known to be very efficient when it actually
finds the solution, but it often diverges if the initial guess is not close enough to the final solution.
Picard is known to approach the solution more slowly, but in return it is usually more robust in
that it finds the solution from a broader range of initial conditions.

Stokes flow
Flows at very low Reynolds numbers are often called Stokes flow. If the Navier-Stokes equations
are nondimensionalized using the characteristic velocity U and length scale L, the equations can

31

be simplified as

Re


u

p +
2u
+ (
u )
u =
,
t
u

= 0,

(134)
(135)

= x/L, p = p/(U/L) and Re = U L/. The spatial derivative


where u
= u/U , t = tU/L, x
which explains the tilde on the nabla operator. The assumption for
is taken with respect to x,
Stokes flow is that the Reynolds number is very small Re << 1, such that the acceleration term
on the left hand side of Navier-Stokes can be neglected. Stokes flow is therefore governed, on
dimensional form, by
2 u = p,

(136)

u = 0.

(137)

Conveniently there is a FEniCS demo available for solving the Stokes equations in a threedimensional cubic domain. In this demo the velocity and pressure are solved using a coupled
system of equations. That is, both Eq. (160) and Eq. (161) are solved simultaneously as opposed
to in a segregated, sequential manner. Since Eq. (160) is a vector equation, this means that we
are actually solving 4 equations (if the domain is 3D) simultaneously. Both u and p are treated as
unknowns (TriaFunctions) using a MixedFunctionSpace:
V = V e c t o r F u n c t i o n S p a c e ( mesh , CG , 2 )
Q = FunctionSpace ( mesh , CG , 1 )
VQ = V * Q # The Mixed space , a l t e r n a t i v e writing :
# VQ = M i x e d F u n c t i o n S p a c e ([ V , Q ])
u , p = Tria lFunctio ns ( VQ )
v , q = TestFunctions ( VQ )

Notice that the velocity functionspace has higher degree than the pressure functionspace. This
distinction is necessary in order to solve the Stokes flow using a mixed formulation. A mixed
Lagrange functionspace where V and Q are of the same order is unstable. Make sure to try this
out and observe the pressure.
The variational formulation for the Stokes equations is found by multiplying Eq. (160) with
TestFunction v and Eq. (161) with TestFunction q and then integrating over the domain
Z
Z

v 2 u dx =
v p dx,

Z
q u dx = 0.

Both the Laplacian and pressure gradient are integrated by parts


Z
Z
Z
Z
v (u n) ds
v : u dx =
v pn ds
p v dx,

Z
q u dx = 0,

where n is the normal vector out of the domain and the colon represents an inner product
(contraction) of two second order tensors. The boundary integral can be written as
Z
v (pI u) n ds

and you should recognize (pI u) n as part of the total stress = pI + (u + uT )


acting on the surface with normal vector n. In finite element communities the boundary condition
(pI u) n = 0 is called pseudo-traction or a do-nothing boundary condition. It is often used
on outlets where we are simply interested in letting the fluid escape with as little interference of
32

boundary conditions as possible. It is called do-noting because you dont have to do anything to
enforce it, just simply omit the boundary terms and solve the two equations
Z
Z

v : u dx
p v dx = 0,

Z
q u dx = 0.

In FEniCS we may solve these two equations (one vector and one scalar equation) coupled with
the Form
F = mu * inner ( grad ( v ) , grad ( u ) ) * dx - inner ( div ( v ) , p ) * dx - inner (q , div ( u ) ) * dx

Note that terms involving TestFunction v end up in the vector equation, whereas terms containing
TestFunction q end up in the scalar equation. All terms defined in F are bilinear, in that they
all contain one TestFunction and one TrialFunction. The sign of the velocity divergence has
been set to negative, because this leads to a symmetric coefficient matrix, which is favourable for
iterative solvers.
To solve the equations we need to create a Function in the mixed functionspace to hold the
solution, for example like this:
up_ = Function ( VQ )
solve ( lhs ( F ) == rhs ( F ) , up_ , bcs )
u_ , p_ = up_ . split ()
plot ( u_ )

The boundary conditions will of course depend on the problem being solved. Note that you cannot
set Dirichlet boundary conditions for both velocity and pressure simultaneously, since that would
be an over specification. A no-slip boundary condition on a solid wall located at y = 0 for a
two-dimensional problem can be set like
bc = DirichletBC ( VQ . sub ( 0 ) , Constant (( 0 , 0 ) ) , " std :: abs ( x [ 1 ]) <1e - 12 " )

Likewise, a Dirichlet boundary condition on pressure can be set using VQ.sub(1).


In the mandatory assignments we will compute Stokes flow and make use of the stream function
(x, t) defined in Eq. (137). The Poisson equation for the streamfunction Eq. (139), can be
transformed to a variational form by multiplying with a TestFunction v and then integrating
over the domain using integration by parts
Z
Z
2
v dx =
v z dx,
Z
Z
Z

(v ) ()dx + v nds =
v z dx.
(138)

Here n is the normal vector pointing outwards from the external boundary. The normal can be
used directly in FEniCS forms through, e.g., n=FacetNormal(mesh).
By taking the curl of Eq. (160) and using that the curl of a gradient is always zero, an equation
for the vorticity vector is obtained
2 = 0.
Likewise, by taking the divergence (not gradient as it says in White [7]) of Eq. (160) we obtain an
equation for the pressure
2 p = 0,
which follows since 2 u = 2 ( u) = 0. For Stokes flow both the pressure and the vorticity
are governed by homogeneous Laplace equations. For 2D flows we also know the equation for the
streamfunction 2 = z . Inserting this into the Laplace equation for z we obtain
4 = 0,

33

(139)

which is a biharmonic equation for the streamfunction. Obviously, if is a solution to 4 = 0,


then is a solution as well. In other words, the direction of flow along a streamline is arbitrary
and only fixed due to boundary conditions. Reversing the direction of the flow (like we do in the
mandatory assignment) will not change the streamlines, but the values will get the opposite sign.
Stokes paradox states that it is not possible to obtain steady solutions to 4 = 0 for 2D
flows with both free stream and no-slip boundary conditions. Stokes paradox is, like dAlemberts
paradox, really only a paradox because the equations do not represent real physical flow, just
approximations in the limit. It follows from Stokes paradox that inertia can never be neglected
for 2D flows with both free stream and no-slip boundary conditions.
Creeping flow past a sphere
Stokes flow past a sphere of radius a is a 3D flow and thus solutions to 4 = 0 may be found even
though there is no-slip on the sphere wall and free stream far away. In spherical polar coordinates
the stream function, , is defined through
ur =

1
,
r2 sin

u =

1
.
r sin r

(140)

The streamfunction equation becomes for spherical coordinates




1 2
cot
2
+
2
2
2
r
r
r

2
= 0,

(141)

with boundary conditions

=
= 0, for r = a,
r

1
= U r2 sin2 + const, for r .
2
Using separation of variables White reports that the solution to this problem reads


1
a 3r 2r2
= U a2 sin2

+ 2 ,
4
r
a
a
and thus we obtain the velocity components from Eq. (164)


a3
3a
ur = U cos 1 + 3
,
2r
2r


a3
3a
u = U sin 1 + 3 +
4r
4r
A few important notes
The velocity is independent of and , which is actually true for all creeping flows.
There is perfect symmetry of the streamlines past the sphere. No wake and no separation.
The velocity is everywhere smaller than the free stream. This is contrary to inviscid flows
where the velocity is maximum at the top and bottom of the sphere. For Stokes flow the
velocity will here be zero due to no-slip.
The effect of the sphere can be observed at enormous distances away from the sphere. At
r = 10a the velocity is still 10% lower than the free stream.
34

The pressure can be computed from the momentum equations in radial and -direction


p
2 u
2ur
2u cot
2
,
= ur 2 2

r
r
r
r2


p
u
2 ur
= r 2 u + 2
2 2

r
r sin
Insert for ur and u and integrate both equations, using boundary conditions, to obtain
p(r, ) = p

3aU
cos ,
2r2

(142)

where p is the pressure in the free stream. From Eq. (166) it is evident that the pressure is
highest at the front (left hand side) of the sphere where = , and lowest at the rear where = 0.
The pressure difference sets up a force acting on the sphere in the streamwise direction. The total
force acting on the sphere is a vector that can be computed as
Z
F =
n dA,

where as before the total stress is composed of pressure and friction through the stress tensor
= pI + (u + uT ). The normal to the surface of the sphere is everywhere aligned with the
r-direction such that we can write
Z

Fp + F =
pI + (u + uT ) n dA,
Z
=
(rr + r )2a2 sin d,
0

where rr and r are the pressure and friction stresses respectively. This follows since the pressure
force is always acting normal to the plane and shear acts in the tangent plane. Remember that
ij is a force acting in the j-direction on a plane having i as the normal direction.
The pressure has already been computed. The remaining shear stress can be computed in
spherical coordinates as


1 ur
u
u
+

r =
,
r
r
r
U sin 3a3
=
.
r
2r3
The total force acting in the streamwise direction is computed by inserting for rr and r leading
to two simple integral as
Fx = |Fp | cos + |F | sin


2 4
= 3U a
+
,
3 3
= 6U a.
In other words, the drag force consists of 2/3 friction and 1/3 pressure.

Mandatory assignments due 11/3 2014 kl. 12.00


Mandatory assignment (i) Verify the analytical solutions (3-47), (3-49) and (3-52) in White
[7]. Experiment with higher order "CG" elements (the solution is then higher order continuous
piecewise polynomials) and compute the errornorm. Report tables of the error vs mesh size
(mesh.hmin()) and comment on the order of accuracy. See Listing (4) for how to compute the
errors.
35

Mandatory assignment (ii) Solve Eq. (146) and Eq. (148) using both Picard and Newton
iterations. Hint: Define a new variable H = F 0 and solve a coupled system of equations for H
and F . Start for example like this:
from dolfin import *
L = 4
mesh = IntervalMesh ( 50 , 0 , L )
V = FunctionSpace ( mesh , CG , 1 )
VV = V * V
# Mixed space for H and F
fh = TrialFunction ( VV ) # T r i a l F u n c t i o n for the Mixed space
f , h = split ( fh )
# split into c o m p o n e n t s in the space
vf , vh = TestFunctions ( VV )

Mandatory assignment (iii) Assume low Reynolds number and use FEniCS to compute a
numerical solution of Stokes flow for a driven cavity. The domain of the cavity is [0, 1] [0, 1] and
the dynamic viscosity = 100. The domain consists of 4 solid walls, where the top lid (y = 1 and
0 < x < 1) is moving at speed u = (1, 0). The remaining 3 walls are not moving. Compute the
streamfunction and find the center of the vortex, i.e., the point where the streamfunction goes
through a minimum. For the driven cavity the value of the streamfunction can be set to zero on
the entire exterior domain.
Note that the boundary condition on follows from the very definition of the streamfunction
Eq. (137), where it should be understood that the variable will only need to be known up to an
arbitrary constant. If is a solution, then + C gives exactly the same velocity field since the
partial derivative of a constant (here C) is zero. As such we can put an "anchor" on the solution
by specifying that = 0 at the corner where x = 0, y = 0. It then follows that will be zero on
the entire domain. Along the left hand border, where x = 0 and 0 y 1, we have the boundary
condition on velocity stating that u = /y = 0. Since the gradient of is 0 along the border
it follows that = 0 along this border. Similarly, for the top lid v = /x = 0, and thus
must be equal to 0 for the entire top lid. The same procedure applies to the last two borders
and consequently = 0 for the entire border. Note that the value does not have to be zero, any
constant value may be chosen.
Mandatory assignment (iv) Assume low Reynolds number and use FEniCS to compute a
numerical solution of Stokes flow creeping past a step (see Fig. 3-37 in [7]). A mesh for the
geometry is shown in Fig. 9. The height of the step is 0.1L. The height and width of the
rectangular geometry is 0.5L and L respectively. Use Re = U L/ = 0.01 (setting density to
unity) as in Fig. 3-37 in [7]. Set the velocity of the top (at y = 0.5L) to constant u = (1, 0). Use
pseudo-traction for the inlet located at x = 0 and the outlet located at x = L. No-slip for the
bottom wall.
Create a suitable mesh using for example Gmsh, Triangle. If you have the latest version of
FEniCS installed it is also possible to create this mesh directly by subtracting rectangles (see
demo) or by creating a SubMesh of a RectangleMesh. However, a tool like Gmsh is more flexible
and it is easy to generate meshes that have higher density near corners, as shown in Fig. 9. Once,
e.g., a Gmsh mesh MyGmshMesh.msh has been created it can be converted to a dolfin mesh
MyDolfinMesh.xml using the dolfin-convert tool. The command "dolfin-convert -h" presents a list
of formats that can be converted to dolfin mesh through the dolfin-convert tool.
[....] dolfin - convert MyGmshMesh . msh MyDolfinMesh . xml

(a) Compute the streamfunction and find the center location of the standing vortex. Report the
result (e.g., in a table) as a function of mesh density. Hint: solve problem by enforcing boundary
conditions weakly. Use definition in Eq. (137) and n=FacetNormal(mesh) to implement the weak
boundary form (second term on left of Eq. (162)).
(b) Make a contour plot, similar to Fig. 3-27 in [7], of the streamfunction. Hint: Dump result
to VTK-format and plot contours using paraview. To create a VTK-file for the streamfunction
36

Figure 8: Mesh for a backwards facing step.


solution Function psi:
f = File ( " psi . pvd " )
f < < psi

(c) Compute the velocity flux in and out of the domain. Is mass being conserved? Hint: to
compute the flow through left and right domains we need to integrate the solution over these
domains only
Z
u=

udA.

Surface integrals like this can be computed in FEniCS by making use of SubDomains and a
FacetFunction:
def left (x , on_boundary ) :
return x [ 0 ] < 1e - 12 and on_boundary
Left = AutoSubDomain ( left )
mf = FacetFunction ( " size_t " , mesh )
mf . set_all ( 0 )
Left . mark ( mf , 1 )

Briefly, this code creates a FacetFunction that has an integer value on all facets (in 2D that
means all the edges) in the mesh ("size_t" may have to be replaced by "uint" depending on
your version of dolfin). The SubDomain Left is created by feeding an inside function (left) to the
AutoSubDomain function. Left.mark(mf,1) sets the value of all facets on the left boundary to
1. Using these tools we can now integrate over the left boundary exclusively. For example, to
compute the area of the inlet do
A = assemble ( Constant ( 1 ) * ds ( 1 ) , e x t e r i o r _ f a c e t _ d o m a i n s = mf ,
mesh = mesh )

(d) Reverse the direction of the flow using u = (1, 0) for the top boundary. Does this change the
location of the vortex? Explain the result.
(e) Compute the normal stress on the bottom wall. Is there any difference depending on the

37

direction of the flow? Is this realistic for real flows of moderate Reynolds numbers?
The normal stress on the wall is computed as
Z
( n) n ds,

(143)

where the stress tensor = pI + (u + uT ).

Suggested assignments
Written assignments

Problems 4-1 and 4-3 in White [7].

Chapter 4 - Laminar boundary layers


Important topics of Chapter 4.
Displacement thickness
Momentum thickness
Flat plate integral analysis
Boundary layer equations
Flow separation
Blasius solution
Falkner-Skan solution

Suggested assignments
Written assignments
Derive the boundary layer equations (Eq. (4-32) in [7]) starting from the Navier-Stokes
equations.
Derive the Blasius equation.
Derive the Falkner-Skan equation.
Computer assignments Implement a nonlinear solver for the Blasius equation. Do the same
for the Falkner-Skan equation and vary the parameter as shown in Fig. 4-11 in White [7].
What happens at = 0.19884? At 0.19884 0 there are according to White at least two
possible solutions. One solution is shown in Fig. 4-11a in White. Another solution shows negative
00
values for f (0), thus indicating backflow close to the wall. Using different initial guesses for the
solution it should be possible to obtain both solutions.

Suggested assignments
Computer assignment Compute the flow past a rotating cylinder. Use a rectangular domain
= [0, 6] [1, 1] and place the cylinder at (x, y) = (1, 0) with a radius of 0.25. Assume at first
steady creeping flow, walls at y = 1 and set the velocity on the left hand side (x = 0) to 1 y 2 .
Set the cylinder to rotate against the clock at a constant speed of 1. Compute lift and drag forces
on the cylinder. Reverse the direction of the rotation and recompute lift and drag. Now include
convection and solve the Steady (nonlinear) Navier-Stokes equations for the same problem.
Set the rotation to oscillate with an angular speed of sin t and compute the unsteady creeping
flow past the cylinder. Do the same for unsteady Navier-Stokes and attempt to find the von
Krmn street for a steady cylinder.
38

Chapter 6 - Incompressible turbulent mean flow


Turbulent flows are governed by the Navier-Stokes equations. However,
there are no simplifications possible by dimensional analysis or through similarity solutions,
no exact definition is known for turbulence,
turbulent flows are not very well understood.
Turbulent flows are usually "defined" by listing their most characteristic properties. Here is
what we know
Turbulence is a flow property and not a fluid property.
Turbulence is always three-dimensional in space and transient. There is no such thing as
two-dimensional turbulence.
Turbulence is irregular, with seemingly random and chaotic motion. However, there is
order to the chaos. The flow satisfies the Navier-Stokes equations, so it is apparently
deterministic. Still, N-S are extremely sensitive to initial and boundary conditions (the
butterfly-effect). The slightest perturbations in initial or boundary conditions leads to a
completely different solution. Thus, turbulence is stochastic even though the Navier-Stokes
equations are deterministic.
Turbulent flows consist to a great deal of vortices and vorticity. Vortex stretching and
tilting are 3-dimensional phenomena that characterize turbulent flows and these processes
can not happen in 2D. If a vortex tube is stretched it must increase its angular velocity to
conserve angular momentum. This can only happen in 3D. In 2D vorticity is (unphysically)
a conserved quantity.
The vortices come in a range of scales. The size of the largest vortices (the largest scales)
is determined by the geometry of the flow, whereas the size of the smallest vortices (the
smallest scales) is determined by viscosity.
The energy cascade. Energy is introduced into the flow on the largest scales and dissipated
on the smallest. Dissipation of kinetic energy is defined as

= s : s, where strain s = 0.5 u + uT
The strain increases dramatically towards the center of a vortex tube leading to higher
dissipation rates in this region.
Turbulence occur at high Reynolds numbers. The normalized momentum equation reads
u
1 2
+ (u )u = p +
u + f.
t
Re
Diffusion is stabilizing as it tends to smear out all gradients. Briefly, perturbations (disturbances) to the flow are amplified by convection and dampened by viscosity. If the Reynolds
number is large, then diffusion is small and convection dominates, leading to unstable
turbulent flows. If the Reynolds number is small then viscosity dominates and perturbations
are killed before they can trigger turbulence.
Engineers need to be able to predict the behaviour of turbulent flows. However, in a turbulent
flow the velocity u(x, t) and pressure p(x, t) should really be considered as random variables. In
other words, at any point in space and time we will not be able to predict the exact value of
velocity or pressure. We can, however, predict the statistical properties of these random variables.
This is usually accomplished using ensamble averages or Reynolds averaging.
39

Figure 9: Measurements of turbulent velocity.


Consider first a turbulent flow that is statistically steady, i.e., the statistical properties of the
flow are independent of time. This happens, e.g., for a plane channel flow or a straight pipe flow
where the applied pressure gradient (the driving force) is held constant. As previously stated, in a
turbulent flow the velocity vector u(x, t) can be considered a random variable. If you stand in the
same spot inside the statistically steady turbulent flow and measure one velocity component, then
the signal might very well look something like shown in Fig. 10, where 1000 samples have been
taken. The arithmetic mean of the velocity over these samples can computed as
hui (x) =

N
1 X
u(x, ti )
N i=1

where u(x, ti ) is the velocity at time ti and N = 1000 for the series shown in Fig. 10. If the
sampling is done in discrete intervals of time 4t, then ti = i4t. Furthermore, if the samples are
taken at sufficiently long time intervals such that u(x, ti ) is uncorrelated with u(x, ti + 4t) then
we talk about an ensamble average as
N
1 X
u(x, ti ).
u(x) = lim
N N
i=1

40

By multiplying through by 4t in both numerator and denominator the ensamble average can also
be rewritten as
N

1 X
u(x, ti )4t,
N N 4t
i=1
Z
1 T

u(x, t)dt,
T 0

u(x) = lim

where T = N 4t is the total sampling time, which typically needs to be larger than the largest
timescales of the flow. It can be seen that for a statistically steady flow the ensamble average
corresponds to the time average.
For a more general turbulent flow where the statistics can change in time more care needs
to be taken in defining the ensamble average because the random variable u(x, t) will in general
be statistically different from the random variable u(x, t + 4t) (e.g., u(x, t) 6= u(x, t + 4t)). To
resolve this, consider flipping a coin. If is the random variable where head gives = 1 and tail
= 0, then the arithmetic average obviously become
N
1 X (i)
hi =

N i=1

where (i) is the result of flip i and as N we should get hi = 0.5. Now, if the coins are
identical then the arithmetic average is obviously the same if one person flips a coin N times or N
persons flip one coin one time. This principle is used in defining an ensamble average for turbulent
flows. If, instead of sampling the random variable u(x, t) at N different time intervals, we run N
identical experiments and sample u(x, t) at the same time and place in all experiments, then the
definition of the ensamble average will be
N
1 X (i)
u (x, t).
N N
i=1

u(x, t) = lim

For a statistically steady flow this will be identical to the time average and the left hand side will
not be dependent on time.
By using the ensamble average the instantaneous velocity and pressure may be decomposed
into a mean and fluctuating component
u(x, t) = u(x, t) + u0 (x, t),
p(x, t) = p(x, t) + p0 (x, t).

(144)
0

Note that both the instantaneous velocity u(x, t) and the fluctuating velocity u (x, t) should be
considered as random variables, whereas the mean velocity u(x, t) is deterministic. Consider any
random variable decomposed as = + 0 . By definition we have 0 = 0. This follows since we
can take the average of both sides of Eq. (169) leading to
= + 0 ,
= + 0 ,
= + 0 ,
that can only be true if 0 = 0. (Note that the average of an average is still the average.) Some
other useful averaging rules are
0 = 0 = 0,
= ,
2

= ( + 0 )( + 0 ) = + 0 0 ,

=
.
s
s
41

The last rule follows since the two operations differentiation and averaging commute, i.e., the
derivative of an average is the same as the average of a derivative.
Having defined the average velocity and pressure we are now in a need of equations that
can be used to predict them. Equations for any statistical measure can be derived directly
by manipulating the Navier-Stokes equations. The equations for u and p are found simply by
averaging NS and introducing Eq. (169). Averaging the continuity equation leads to
u=u=0
simply because averaging and differentiation commutes. The average of the momentum equation
can be written
1
u
+ (u )u = p + 2 u + f
t

The density and viscosity are assumed constant. The first term on the left and all terms on the
right are averaged by using commutation
u
u
=
,
t
t
1
1
p = p,

2 u = 2 u.
This leaves the nonlinear convection term. Using index notation we can take two fast steps using
continuity and commutation
uj

ui uj
ui
uj
=
ui
xj
xj
xj
ui uj
=
.
xj

Inserting now for Eq. (169) we have


ui uj = (ui + u0i )(uj + u0j ) = ui uj + u0i u0j
and thus
uj

ui uj + u0i u0j
ui
=
xj
xj
= uj

u0i u0j
ui
+
xj
xj

Putting it all together we obtain the Reynolds averaged Navier-Stokes equations


u0i u0j
u
1
+ (u )u = p + 2 u
+ f,
t

xj
u=0

(145)
(146)

Mandatory assignments due 6/5 2014


Mandatory assignment (i) Implement a nonlinear solver for the Falkner-Skan Eq. (168).
(a) Vary the parameter and reproduce Fig. 4-11 (a) and (b) in White [7].
(b) What happens at = 0.19884?. At 0.19884 0 there are according to White at
least two possible solutions. One solution is shown in Fig. 4-11a in White. Another solution
00
shows negative values for f (0), thus indicating backflow close to the wall. Using different
initial guesses for the solution it should be possible to obtain both solutions. Show these in
a plot for = 0.1.
42

Mandatory assignment (ii) Perform benchmarks 2.2 a) and 2.2 b) of Schaefer and Turek,
1996 and report your results comparing with Table 3 and 4 of the benchmark.
Mandatory assignmentp(iii) Consider a fully developed turbulent plane channel flow. The
wall friction velocity v = u/y wall = 0.05 and the turbulent Reynolds number Re = v / =
1000.
(a) Use the Mixing length model and implement a solver for a plane turbulent channel flow.
2 u 1 p u0 v 0

,
y 2
x
y
u
u0 v 0 = T
,
y
u
t = l2 | |,
y

 + 
y
l = y 1 exp
,
A
yv
y+ =
.

0=

The constants = 0.41 and A = 26.


Hint 1: the pressure gradient is constant and can be computed from v by integrating the
momentum equation across the channel.
Hint 2: use a mesh skewed towards the walls. You should resolve the solution up to at least
y + = 1 (or y /v for the first inner node of the computational mesh). To compute a
skewed mesh you could for example do something like this
from numpy import arctan
mesh = IntervalMesh ( 100 , 0 , 1 )
x = mesh . coordinates ()
x [: , 0 ] = arctan ( pi *( x [: , 0 ]) ) / arctan ( pi )

which gives y + = 2.31 for first internal node and thus is not dense enough! Modify the mesh
and check the location of the first inner node to ensure that its less than /v . How many
nodes do you need to ensure y + < 1 if you use a regularly spaced mesh that is not skewed
towards the wall?
(b) Verify that the solution approximates the theoretical results
y + = u+ for y + < 5,
1
u+ = ln y + + B for y + > 30,

where the "constant" B = 5.5. Can you improve the agreement with the computational
results by modifying the constants? What is the value of the turbulent viscosity T at the
center of the channel? Do you believe this value is reasonable?
Mandatory assignment (iv) Derive from first principles
the Reynolds Averaged Navier Stokes equations (Eq. 6-13 in [7])
the turbulence kinetic energy equation (Eq. 6.17 in [7])
the Reynolds stress equation (Eq. 6-18 in [7])
See, e.g., this book for more details about derivation.
43

Turbulence modelling
Turbulence modelling is all about finding suitable closures, or models, for the Reynolds stress
tensor. The Reynolds stress tensor is symmetrical
u0i u0j = u0j u0i

(147)

and thus contains 6 unknown quantities. The Reynolds stress is not really a stress, but it is
so called because of the way it appears in the mean momentum equation Eq. (170). The mean
momentum equation can alternatively be rewritten as


u

(148)
+ (u )u = + f ,
t
where
ij = pij + 2S ij u0i u0j ,
is a new term that has dimensions of stress and


1 ui
uj
S ij =
+
.
2 xj
xi

(149)

(150)

Mathematically then it appears that the total mean stress tensor has been added a third term
u0i u0j after the regular pressure and viscous stresses. The term is called a Reynolds "stress", but
it is in fact just the contribution of the fluctuating velocities to the mean nonlinear convection.
(Note that is required for the term to have dimensions of stress.) By stress we usually mean the
internal forces that fluid particles exert on each other.
The highest level of RANS modelling is usually considered the second moment closures that
solve transport equations for u0i u0j directly. Second moment closures are outside the scope of this
course.
The by far most commonly used turbulence model is the eddy viscosity (first moment) closure
2
u0i u0j = 2T S ij + kij ,
3

(151)

where T is a turbulent viscosity. Turbulence models are usually classified by the number of
additional PDEs that are used to model the turbulent viscosity.
The turbulent viscosity is a parameter of the flow and not the fluid. As mentioned before, one
of the most important properties of a turbulent flow is its ability to efficiently mix momentum
and scalars, like temperature. Mathematically, the enhanced mixing is manifested through the
Reynolds stress and it is through Eq. (183) sought modelled as a diffusion process using T as
a positive ( 0) mixing rate constant. Inserted into the momentum equation the eddy viscosity
gives rise to the term
 

u0i u0j

ui
uj
2 k
=
t
+
+
,
xj
xj
xj
xi
3 xi
and it can be seen that the first term on the right hand side will lead to enhanced mixing (or
diffusion) of ui as long as T is positive.
Having established an algebraic model for the Reynolds stress (183), we have reduced the
number of unknowns from 6 to 2 (T and k). We will now discuss the most common strategies for
closing the remaining terms.
The turbulent viscosity is by dimensional reasoning the product of a velocityscale u
and a
lengthscale l
T = u
l,
where different interpretations are possible for defining such scales. Remembering that one of the
defining properties of turbulence is that it contains a range of scales, such a classification into one
single velocity- and lengthscale may seem questionable from the very start. Nevertheless, most
44

turbulence models boil down to finding good approximations for these scales, and the modelled
scales are then usually interpreted as the largest scales of turbulence. Many different models exist
(including multiscale models, which is beside the scope for this course) and sometimes a timescale
tk is used instead of u
, but then the two are related through u
= l/tk .
Turbulence models are usually classified by the number of additional PDEs that are required
to establish the proper scales and we will now go through some of the most basic models.
Zero-equation models Zero-equation turbulence models are models that use zero additional
PDEs to model the turbulent viscosity. The Mixing length model was the first such turbulence
model. For a simple plane shear flow where u is the tangential velocity and y is the wall normal
direction the model reads

du
u
= l ,
dy

du
T = l2 .
(152)
dy
For a plane shear flow the model is excellent as one may choose
l y2 ,

for

y + < 5,

l y,

for

30 < y + < 100,

l 1,

for

y + > 100

(153)

where = 0.41 is von Krmans constant and y is the distance to the wall. Further
s
u
v =
,
y
wall

yv
,
y =

are, respectively, the turbulent wall friction velocity and the distance to the wall in normalized
wall units. A Reynolds number based on v , Re = L v / is often used to characterize flow in
turbulent plane shear flows.
Several models exist that merge the three domains in Eq. (185) into one single continuous
function. Van Driest provided a model that merged the first two inner layers using

 + 
y
l = y 1 exp
,
(154)
A
where A is a constant set to 26 for flat plate flow. This model should be merged with l = constant
far enough from the wall. Far enough is often chosen when l from Eq. (186) becomes larger than
a factor of the mixing layer thickness . An often used estimate is when y = 0.09 or y = 0.22.
The Mixing length model is not a good model for other flows than plane boundary layer flows.
For example, in the center of a plane channel the mean velocity gradient is zero due to symmetry
(du/dy = 0). The Mixing length model Eq. (184) thus predicts that the turbulent viscosity should
be zero in the center of the channel. This is contrary to the experimental observation and intuition,
because the turbulent intensity is actually very large in the center.
This flaws of the mixing length model first led to the suggested improvement that the
velocityscale should be proportional to the turbulence intensity and not the mean velocity gradient

u
= const k.
(155)
The problem now is that this model introduces a new unknown k that requires modelling (whereas
the old model used known quantities l and u). Thus one additional PDE is required for closure of
the turbulent viscosity.
45

One-equation models Most one-equation turbulence models solves a transport equation for k,
the turbulent kinetic energy. The equation for k has already been derived in previous assignments
and it is evident that it contains even more unclosed terms. If we start by rewriting the k-equation
as
k
k
Tj
+ uj
=
+ P
t
xj
xj
then the terms on the right hand side are
k
1 0 0
1
p ui ij + u0i u0i u0j
,

2
xj
ui
,
P = u0i u0j
xj

Tj =

u0i u0i
.
xj xj

(156)
(157)
(158)

Here Tj represents turbulent transport, P is production of turbulent kinetic energy and is


pseudo-dissipation of turbulent kinetic energy. The production P is closed since it only contains
known quantities like the Reynolds stress and mean velocity gradients. The first two terms of Tj
and are unknown and require closure. is called pseudo-dissipation since the actual dissipation
of k is really 2s0ij s0ij . The two terms are related through the identity
2s0ij s0ij =

u0i u0i
u0 u0j
+ i
,
xj xj
xj xi

= +

u0i u0j
.
xj xi

Since the last term on the rhs is small relative to the first, dissipation and pseudo-dissipation are
similar for most flows.
The turbulent transport term is usually modelled as gradient diffusion


t
k
Tj = +
,
k xj
where k is a constant in the near vicinity of one. Like the name suggests the model enhances
diffusion of k and serves to smooth out the k field faster than possible simply through regular
diffusion. This corresponds well with our knowledge of turbulence as an efficient mixing process.
The pseudo-dissipation rate scales like

u
3
.
l

Thus we can find a suitable model for simply by inserting for Eq. (187)

(const k)3
=
,
l
k 3/2
= const
,
l

and thus
l = const

46

k 3/2
.

By inserting for the velocity- and lengthscales we get the following model for the turbulent viscosity

T = const kl,
T = const

k2
.

A weakness of the model is that it requires the lengthscale l to be provided from knowledge of the
problem under consideration. For this reason one-equation turbulence models are often referred
to as being incomplete. One-equation models are popular for systems where the mixing length
can be easily specified, like a plane boundary layer or an aeroplane wing.
Two-equation models Two-equation turbulence models introduce an additional PDE for the
missing lengthscale. Since two-equation models do not require any parameter (like l) from previous
knowledge of the system, the two-equation models are often referred to as being complete.
The most popular two-equation turbulence models are variations of the k model and the
k model. k models solve one PDE for k and an additional for . Likewise, k models
solve PDEs for k and , where /k. If k and are known then
l=

k 3/2
,

tk =

k
,

u
=

l
= k
tk

where tk is a turbulent timescale. The turbulent viscosity is as before determined by


T = const u
l = const

k2
.

A transport equation for can be derived exactly from the Navier-Stokes equations. The
resulting equation contains many new unknowns and here we will not go into detail. Instead we
will here simply report the entire and closed k model with its most common model constants



ui
ui

ui
uj
1 p + 23 k
+ uj
=
( + T )
+

,
t
xj
xj
xj
xi
xi



k
k

k
T
+ uj
=
+
+ P ,
t
xj
xj
k xj




T

2
P
+ uj
C2 ,
(159)
=
+
+ C1
t
xj
xj
xj
k
k
ui
= 0,
xi
k2
T = C ,

C = 0.09, C1 = 1.44, C2 = 1.92, = 1.3, k = 1.


Unfortunately the model constants are known to vary from flow to flow and thus often in need of
tuning for optimal performance. Nevertheless, two-equation models are complete and the k
model is very much in use in industry for a wide range of flows.
There is a great number of different RANS turbulence models. Some are listed on the page for
NASAs Turbulence Modelling Resources [4] and the wiki [5] for turbulence modeling.
Boundary conditions The average statistics in a turbulent flow have sharp gradients in the
near vicinity of a wall. To properly resolve all statistics the location of the first inner computational
node needs to be at approximately y + = 1. This restriction is quite demanding in terms of grid
resolution, especially at high Reynolds number. The standard k model, Eq. (191), is not very
accurate close to walls and many modifications exist to handle this problem. Two main approaches
are
47

(1) Do not resolve the flow further than approximately y + = 30 and use wall functions to
prescribe boundary conditions inside the wall instead of at the wall.
(2) Resolve the flow completely (all the way up to y + = 1) and introduce damping functions.
The wall functions are based on the log-law
u+ =

1
ln y + + B,

(160)

which is known to be in close agreement with experiments of regular boundary layers for a range
of Reynolds numbers. If the first inner node (the first node on the inside of the wall) is located at
y p , then the velocity can be computed as
1 y p u
up
= ln
+ B,

(161)

References
[1] http://fenicsproject.org/documentation/tutorial.
[2] http://fenicsproject.org/documentation/tutorial/fundamentals.html#the-poisson-equation.
[3] http://mathworld.wolfram.com/ModifiedBesselDifferentialEquation.html.
[4] http://turbmodels.larc.nasa.gov/ Langley Research Center Turbulence Modeling Resource.
[5] http://www.cfd-online.com/wiki/Turbulence_Modeling.
[6] Erwin Kreyszig. Advanced Engineering mathematics. Wiley, 8 edition, 1999.
[7] Frank M. White. Viscous Fluid Flow. McGraw-Hill, third edition, 2006.

48