Vous êtes sur la page 1sur 13

CFD - Finite Differences 1D

January 28, 2015

1 1-D Linear Convection


The 1-D Linear Convection equation is the simplest, most basic model that can be used to learn something
about CFD. It is surprising that this little equation can teach us so much! Here it is:
∂u ∂u
+c =0
∂t ∂x
With given initial conditions (understood as a wave), the equation represents the propagation of that
initial wave with speed c, without change of shape. Let the initial condition be u(x, 0) = u0 (x). Then the
exact solution of the equation is u(x, t) = u0 (x − ct).
We discretize this equation in both space and time, using the Forward Difference scheme for the time
derivative and the Backward Difference scheme for the space derivative. Consider discretizing the spatial
coordinate x into points that we index from i = 0 to N , and stepping in discrete time intervals of size ∆t.
From the definition of a derivative (and simply removing the limit), we know that:

∂u u(x + ∆x) − u(x)



∂x ∆x
Our discrete equation, then, is:

un+1 − uni un − uni−1


i
+c i =0
∆t ∆x
Where n and n + 1 are two consecutive steps in time, while i − 1 and i are two neighboring points of the
discretized x coordinate. If there are given initial conditions, then the only unknown in this discretization is
un+1
i . We can solve for our unknown to get an equation that allows us to advance in time, as follows:
∆t n
un+1 = uni − c (u − uni−1 )
i
∆x i
Now let’s try implementing this in Python.
We’ll start by importing a few libraries to help us out.

• numpy is a library that provides a bunch of useful matrix operations akin to MATLAB
• matplotlib is a 2D plotting library that we will use to plot our results
• time and sys provide basic timing functions that we’ll use to slow down animations for viewing

In [1]: %pylab inline

import numpy as np #numpy is a library for array operations akin to MATLAB


import matplotlib.pyplot as plt #matplotlib is 2D plotting library

def linearconv(nx):
dx = 2./(nx-1)
time = 20*0.025
dt = .025 #dt is the amount of time each timestep covers (delta t)

1
nt = int(time/dt) #nt is the number of timesteps we want to calculate
c = 1

print dx/dt

u = np.ones(nx) #defining a numpy array which is nx elements long with every value equa
u[.5/dx : 1/dx+1]=2 #setting u = 2 between 0.5 and 1 as per our I.C.s

un = np.ones(nx) #initializing our placeholder array, un, to hold the values we calculate fo

for n in range(nt): #iterate through time


un = u.copy() ##copy the existing values of u into un
for i in range(1,nx):
u[i] = un[i]-c*dt/dx*(un[i]-un[i-1])

plt.plot(np.linspace(0,2,nx),u)

Populating the interactive namespace from numpy and matplotlib

1.1 Convergence and the CFL Condition


Now let’s examine the results of our linear convection problem with an increasingly fine mesh.

In [2]: linearconv(41) #convection using 41 grid points

2.0

This is the same result as our Step 1 calculation, reproduced here for reference.

In [3]: linearconv(61)

1.33333333333

2
Here, there is still numerical diffusion present, but it is less severe.
In [4]: linearconv(71)
1.14285714286

Here the same pattern is present – the wave is more square than in the previous runs.

3
In [5]: linearconv(85)

0.952380952381

This doesn’t look anything like our original hat function.

1.2 What happened?


To answer that question, we have to think a little bit about what we’re actually implementing in code.
In each iteration of our time loop, we use the existing data about our wave to estimate the speed of the
wave in the subsequent time step. Initially, the increase in the number of grid points returned more accurate
answers. There was less numerical diffusion and the square wave looked much more like a square wave than
it did in our first example.
Each iteration of our time loop covers a time-step of length ∆t, which we have been defining as 0.025
During this iteration, we evaluate the speed of the wave at each of the x points we’ve created. In the last
plot, something has clearly gone wrong.
What has happened is that over the time period ∆t, the wave is travelling a distance which is greater
than dx. The length dx of each grid box is related to the number of total points nx, so stability can be
enforced if the ∆t step size is calculated with respect to the size of dx.
u∆t
σ= ≤ σmax
∆x
where u is the speed of the wave; σ is called the Courant number and the value of σmax that will
ensure stability depends on the discretization used.
In a new version of our code, we’ll use the CFL number to calculate the appropriate time-step dt
depending on the size of dx.

In [6]: import numpy as np


import matplotlib.pyplot as plt

def linearconv(nx):

4
dx = 2./(nx-1)
time = 20*0.025
c = 1
sigma = .5
dt = sigma*dx/c #dt is the amount of time each timestep covers (delta t)
nt = int(time/dt) #nt is the number of timesteps we want to calculate

print dx/dt

u = np.ones(nx)
u[.5/dx : 1/dx+1]=2

un = np.ones(nx)

for n in range(nt): #iterate through time


un = u.copy() ##copy the existing values of u into un
for i in range(1,nx):
u[i] = un[i]-c*dt/dx*(un[i]-un[i-1])

plt.plot(np.linspace(0,2,nx),u)

In [7]: linearconv(41)

2.0

In [8]: linearconv(61)

2.0

5
In [9]: linearconv(81)

2.0

In [10]: linearconv(101)

6
2.0

In [11]: linearconv(501)

2.0

7
2 Non-linear Convection
Now we’re going to implement non-linear convection using the same methods as in step 1. The 1D convection
equation is:
∂u ∂u
+u =0
∂t ∂x
Instead of a constant factor c multiplying the second term, now we have the solution u multiplying it.
Thus, the second term of the equation is now non-linear We’re going to use the same discretization as in
Step 1 — forward difference in time and backward difference in space. Here is the discretized equation.

un+1 − uni un − uni−1


i
+ uni i =0
∆t ∆x
Solving for the only unknown term, un+1
i , yields:
∆t n
un+1 = uni − uni (u − uni−1 )
i
∆x i
As before, the Python code starts by loading the necessary libraries. Then, we declare some variables
that determine the discretization in space and time (you should experiment by changing these parameters
to see what happens). Then, we create the initial condition u0 by initializing the array for the solution using
u = 2 @ 0.5 ≤ x ≤ 1 and u = 1 everywhere else in (0, 2) (i.e., a hat function).

In [12]: import numpy as np


import matplotlib.pyplot as plt

def nonlinearconv(nx):
dx = 2./(nx-1)
time = 20*0.025
sigma = .5
dt = sigma*dx #dt is the amount of time each timestep covers (delta t)
nt = int(time/dt) #nt is the number of timesteps we want to calculate
c = 1

print dt/dx

u = np.ones(nx)
u[.5/dx : 1/dx+1]=2

un = np.ones(nx)

for n in range(nt): #iterate through time


un = u.copy() ##copy the existing values of u into un
for i in range(1,nx):
u[i] = un[i]-un[i]*dt/dx*(un[i]-un[i-1])

plt.plot(np.linspace(0,2,nx),u)

In [13]: nonlinearconv(41)

0.5

8
In [14]: nonlinearconv(61)

0.5

In [15]: nonlinearconv(81)

9
0.5

In [16]: nonlinearconv(101)

0.5

10
In [17]: nonlinearconv(501)

0.5

3 Diffusion Equation in 1-D


The one-dimensional diffusion equation is:

∂u ∂2u
=ν 2
∂t ∂x
The first thing you should notice is that —unlike the previous two simple equations we have studied—
this equation has a second-order derivative. We first need to learn what to do with it!

∂2u
3.1 Discretizing ∂x2
The second-order derivative can be represented geometrically as the line tangent to the curve given by the first
derivative. We will discretize the second-order derivative with a Central Difference scheme: a combination
of Forward Difference and Backward Difference of the first derivative. Consider the Taylor expansion of ui+1
and ui−1 around ui :
+ ∆x2 ∂ 2 u2 + ∆x3 ∂ 3 u3 + O(∆x4 )

ui+1 = ui + ∆x ∂u
∂x 2 ∂x 3 ∂x
i i i
∆x2 ∂ 2 u ∆x3 ∂ 3 u

∂u

ui−1 = ui − ∆x ∂x + 2 ∂x2 − 3 ∂x3 + O(∆x4 )
i i i
If we add these two expansions, you can see that the odd-numbered derivative terms will cancel each
other out. If we neglect any terms of O(∆x4 ) or higher (and really, those are very small), then we can
rearrange the sum of these two expansions
to solve for our second-derivative.
2
ui+1 + ui−1 = 2ui + ∆x2 ∂∂xu2 + O(∆x4 )
i

11

∂2u

Then rearrange to solve for ∂x2 and the result is:
i
∂2u ui+1 − 2ui + ui−1
2
= + O(∆x2 )
∂x ∆x2
We can now write the discretized version of the diffusion equation in 1D:

un+1 − uni un − 2uni + uni−1


i
= ν i+1
∆t ∆x2
As before, we notice that once we have an initial condition, the only unknown is un+1
i , so we re-arrange
the equation solving for our unknown:
ν∆t n
un+1 = uni +(u − 2uni + uni−1 )
i
∆x2 i+1
The above discrete equation allows us to write a program to advance a solution in time. But we need
an initial condition. Let’s continue using our favorite: the hat function. So, at t = 0, u = 2 in the interval
0.5 ≤ x ≤ 1 and u = 1 everywhere else.

4 Burgers’ Equation
You can read about Burgers’ Equation on its wikipedia page.
Burgers’ equation in one spatial dimension looks like this:

∂u ∂u ∂2u
+u =ν 2
∂t ∂x ∂x
As you can see, it is a combination of non-linear convection and diffusion. It is surprising how much you
learn from this neat little equation!
We can discretize it using the methods we’ve already detailed in Steps 1 to 3. Using forward difference
for time, backward difference for space and our 2nd-order method for the second derivatives yields:

un+1 − uni un − uni−1 un − 2uni + uni−1


i
+ uni i = ν i+1
∆t ∆x ∆x2
As before, once we have an initial condition, the only unknown is un+1
i . We will step in time as follows:
∆t n ∆t n
un+1 = uni − uni (u − uni−1 ) + ν (u − 2uni + uni−1 )
i
∆x i ∆x2 i+1

4.1 Initial and Boundary Conditions


To examine some interesting properties of Burgers’ equation, it is helpful to use different initial and boundary
conditions than we’ve been using for previous steps.
Our initial condition for this problem is going to be:

2ν ∂φ
u = − +4 (1)
φ ∂x
 2
−(x − 2π)2
 
−x
φ = exp + exp (2)
4ν 4ν
This has an analytical solution, given by:

2ν ∂φ
u = − +4 (3)
φ ∂x
−(x − 4t)2 −(x − 4t − 2π)2
   
φ = exp + exp (4)
4ν(t + 1) 4ν(t + 1)

12
Our boundary condition will be:

u(0) = u(2π)
This is called a periodic boundary condition. Pay attention! This will cause you a bit of headache if you
don’t tread carefully.

4.1.1 Periodic Boundary Conditions


One of the big differences between Step 4 and the previous lessons is the use of periodic boundary conditions.
If you experiment with Steps 1 and 2 and make the simulation run longer (by increasing nt) you will notice
that the wave will keep moving to the right until it no longer even shows up in the plot.
With periodic boundary conditions, when a point gets to the right-hand side of the frame, it wraps around
back to the front of the frame.
Recall the discretization that we worked out at the beginning of this notebook:
∆t n ∆t n
un+1 = uni − uni (ui − uni−1 ) + ν (u − 2uni + uni−1 )
i
∆x ∆x2 i+1
What does uni+1 mean when i is already at the end of the frame?
Think about this for a minute before proceeding.

In [24]: from IPython.core.display import HTML


def css_styling():
styles = open("../styles/custom.css", "r").read()
return HTML(styles)
css_styling()

Out[24]: <IPython.core.display.HTML at 0x106206990>

13

Vous aimerez peut-être aussi