MATH76109/28/2018

Lab05: Finite difference schemes for hyperbolic equations

1Semi-discretization

Semi-discretization of the advection equation

qt+uqx=0

using a centered difference scheme leads to the ODE system

ddt𝑸=-u2h𝐁𝑸

with 𝐁=diag([ -1 0 1 ]). We consider the solution of the above ODE system by:

  1. Forward Euler (FTCS scheme)

    𝑸n+1=(𝑰-ν2𝐁)𝑸n

    with ν=uk/h known as the CFL number.

  2. Midpoint (leap-frog scheme)

    𝑸n+1=𝑸n-1-ν𝐁𝑸n
  3. Lax-Friedrichs

    𝑸n+1=(𝝁-ν2𝐁)𝑸n

    with 𝝁=12(diag([ 1 0 0 ])+diag([ 0 0 1 ])) the averaging operator

  4. Lax-Wendroff

    𝑸n+1=(𝑰-ν2𝐁+ν22𝐃)𝑸n

    with 𝐃=diag([ 1 -2 1 ])

Lab05 continues Lab04 by studying the modified equations associated with each of these schemes. The literate programming implementation of Lab04 is expanded to include analysis techniques.

2Implementation

2.1Global definitions

A module is constructed with global definitions.

SELECTED_REAL_KIND(P,R) is a Fortran intrinsic function that returns the available type closest to the requested precision of P decimal digits and an exponent range R. Two, possibly different, precisions are defined for the dependent variables (q) and the independent variables (space, time).

2.2Time stepping

A common interface to all finite difference schemes:

method: scheme to apply

m: number of interior nodes

nSteps: number of time steps

cfl: CFL number

Q0,Q1: initial conditions

Q: final state after time stepping

Qlft: boundary values at left

Qrgt: boundary values at right

Internal variable declarations

Precomputation of common expresions

Start of SELECT statement

2.2.1FTCS

Carry out time steps.

For u>0, use specified left boundary value, extrapolate at right. For u<0 use specified right boundary value, extrapolate at left.

Qin+1=Qin-ν2(Qi+1n-Qi-1n)

Stability.
Use Von Neumann analysis QjnGneijθ, with θ=ξh.

In[45]:=

Q[n_,j_,theta_] = G[n] Exp[I j theta]

G(n)eijθ

In[46]:=

FTCS = Q[n+1,j,theta] - (Q[n,j,theta] - nu/2 (Q[n,j+1,theta]-Q[n,j-1,theta]))

12ν(G(n)ei(j+1)θ-G(n)ei(j-1)θ)+G(n)(-eijθ)+G(n+1)eijθ

In[47]:=

expr = Expand[FTCS/G[n]] /. G[n+1]/G[n]->A

Aeijθ-12νei(j-1)θ+12νei(j+1)θ-eijθ

In[48]:=

AmpFact[theta_] = Simplify[ComplexExpand[A /. Solve[expr == 0,A][[1,1]]]]

1-iνsin(θ)

In[49]:=

The amplifcation factor is |A|1, hence the FTCS method is always unstable.

Modified equation.

In[10]:=

FTCS = s[t+k,x] - (s[t,x] - nu/2 (s[t,x+h]-s[t,x-h]))

12ν(s(t,h+x)-s(t,x-h))+s(k+t,x)-s(t,x)

In[14]:=

mFTCS = Simplify[Normal[Series[FTCS,{k,0,2},{h,0,2}]]]

hνs(0,1)(t,x)+12k2s(2,0)(t,x)+ks(1,0)(t,x)

From above series expansions find the modified equation

st+usx=-k2stt+𝒪(k2,h2)=-u2k2sxx+𝒪(k2,h2),

an advection-diffusion equation with negative diffusivity, again indicating instability of the FTCS method.

Qin+1=Qin-ν(Qin-Qi-1n) for u>0

Qin+1=Qin-ν(Qi+1n-Qin) for u<0

Stability.
Use Von Neumann analysis QjnGneijθ, with θ=ξh (assume u>0)

In[87]:=

Upwind = Q[n+1,j,theta] - (Q[n,j,theta] - nu (Q[n,j,theta]-Q[n,j-1,theta]))

ν(G(n)eijθ-G(n)ei(j-1)θ)+G(n)(-eijθ)+G(n+1)eijθ

In[88]:=

expr = Expand[Upwind/G[n]] /. G[n+1]/G[n]->A

Aeijθ-νei(j-1)θ+νeijθ-eijθ

In[89]:=

AmpFact[theta_] = Simplify[TrigReduce[ComplexExpand[A /. Solve[expr == 0,A][[1,1]]]]]

-iνsin(θ)+νcos(θ)-ν+1

In[90]:=

A[theta_,nu_]=Sqrt[TrigReduce[ComplexExpand[AmpFact[theta] Conjugate[AmpFact[theta]]]]]

-2ν2cos(θ)+2ν2+2νcos(θ)-2ν+1

In[93]:=

UpwindStabPlot=Plot[Table[A[theta,nu],{nu,0.1,1.0,0.1}],{theta,0,2Pi},

GridLines->Automatic,Axes->False,Frame->True,FrameLabel->{"theta","A(theta)"}];

Export["/home/student/courses/MATH761/lab05/UpwindStabPlot.pdf",UpwindStabPlot]

/home/student/courses/MATH761/lab05/UpwindStabPlot.pdf

In[94]:=

Figure 1. Upwind amplification factor obtained from Von Neumann analysis

Modified equation.

In[94]:=

Upwind = s[t+k,x] - (s[t,x] - nu (s[t,x]-s[t,x-h]))

ν(s(t,x)-s(t,x-h))+s(k+t,x)-s(t,x)

In[96]:=

mUpwind = Simplify[Normal[Series[Upwind,{k,0,2},{h,0,2}]]]

-12h2νs(0,2)(t,x)+hνs(0,1)(t,x)+12k2s(2,0)(t,x)+ks(1,0)(t,x)

In[97]:=

From above series expansions find the modified equation

st+usx=-k2stt+h2ν2ksxx+𝒪(k2,h2)=12(-ku2+h2νk)sxx+𝒪(k2,h2)=νh22k(1-ν)sxx+𝒪(k2,h2),

again an advection-diffusion equation with diffusivity

α=νh22k(1-ν).

Note that the diffusivity is zero at CFL ν=1. The analytical solution to

{ st+usx=αsxx s(t=0,x)=H(-x) .

is

s(t,x)=12[1+erf(x-ut4αt)],erf(x)=2π0xe-ξ2dξ

In[99]:=

s[t_,x_]=(1+Erf[(x-u t)/Sqrt[4 alpha t]])/2

12(erf(x-tu2αt)+1)

In[100]:=

Simplify[ D[s[t,x],t] + u D[s[t,x],x] - alpha D[s[t,x],{x,2}] ]

0

In[101]:=

Qin+1=Qin-1-ν(Qi+1n-Qi-1n)

Qin+1=Qin-1-ν2(Qi+1n-Qi-1n)+ν22(Qi+1n-2Qin+Qi-1n)

3Numerical experiments

Compilation of the above implementation leads to a Python-loadable module than can be used for numerical experiments.

Python]

from pylab import *

Python]

import os,sys

os.chdir('/home/student/courses/MATH761/lab05')

cwd=os.getcwd()

sys.path.append(cwd)

Python]

from lab05 import *

Python]

print scheme.__doc__

q = scheme(method,cfl,q0,q1,qlft,qrgt,[m,nsteps])

Wrapper for ‘‘scheme‘‘. Parameters ---------- method : input int cfl : input float q0 : in/output rank-1 array('d') with bounds (m + 2) q1 : in/output rank-1 array('d') with bounds (m + 2) qlft : input rank-1 array('d') with bounds (nsteps + 1) qrgt : input rank-1 array('d') with bounds (nsteps + 1) Other Parameters ---------------- m : input int, optional Default: (len(q0)-2) nsteps : input int, optional Default: (len(qlft)-1) Returns -------

q : rank-1 array('d') with bounds (m + 2)

Python]

3.1Discontinuous boundary condition

Study now the behavior for a discontinuous (shock) initial condition q(0,x)=H(-x). The upwind solution will be compared to the exact solution q(t,x)=H(ut-x) for the advection equation qt+uqx=0, and the exact solution

s(t,x)=12[1+erf(ut-x4αt)],erf(x)=2π0xe-ξ2dξ

to the modified equation st+usx=αsxx, with artificial diffusivity

α=νh22k(1-ν).

Python]

def f(x,kappa):

return zeros(size(x))

def g(t,kappa):

return (sign(t)+1)/2

u=1;

Python]

FTCS=1; Upwind=2; LaxFriedrichs=3; LeapFrog=4; LaxWendroff=5; BeamWarming=6;

Python]

kappa=4

Python]

3.1.1Upwind

Python]

method=Upwind

from math import erf

m=99; h=1./(m+1); x=arange(m+2)*h;

dcfl=0.2; tfinal=0.5;

clf();

qex=g(tfinal-x/u,kappa);

plot(x[1:m],qex[1:m],'k.'); s = zeros(size(x));

for cfl in arange(dcfl,1+dcfl,dcfl):

k=h*cfl/u; nSteps=ceil(tfinal/k); t=arange(nSteps+1)*k; kappa=4;

Q0=f(x,kappa); Q1=zeros(size(x));

Qlft=g(t,kappa); Qrgt=zeros(size(t));

Q1=scheme(method,cfl,Q0,Q1,Qlft,Qrgt);

alpha = max(cfl*h**2*(1-cfl)/(2*k),10**(-6));

y = (u*tfinal-x)/sqrt(4*alpha*tfinal);

for i in range(m+1):

s[i] = 0.5*(1+erf(y[i]));

plot(x[1:m],Q1[1:m],'b',x[1:m],s[1:m],'r.');

xlabel('x'); ylabel('q'); title('Shock propagation by upwind scheme');

savefig("Lab05UpwindShockInitCond.pdf");

Python]

Figure 2. The exact solution to the modified equation corresponds closely to the results from the upwind scheme