MATH76109/21/2018
Semi-discretization of the advection equation
using a centered difference scheme leads to the ODE system
with . We consider the solution of the above ODE system by:
Forward Euler (FTCS scheme)
with known as the CFL number.
Midpoint (leap-frog scheme)
Lax-Friedrichs
with the averaging operator
Lax-Wendroff
with
This Lab introduces a number of useful techniques:
linking efficient compiled implementations (in Fortran) to an interpreted language (Python), and thus develop an environment for interactive investigation of behavior of numerical schemes;
literate programming within TeXmacs;
development of a Makefile to automate common tasks
Literate programming is the simultaneous development of code implementing an algorithm with construction of full documentation of the underlying mathematics. Within this document tabular material such as the following examples contains code in the left column and comments on the code in the right column. The following block can be copy/pasted to generate additional blocks.
|
Fortran comments start with ! |
|
C++ comments start with // |
|
Python comments start with # |
The ./lab04/Makefile extracts verbatim all code within the Fortran-code TeXmacs environment into a lab04.f90 file that is compiled into a Python-loadable module by the f2py utility. The TeXmacs file is first converted to LaTeX, after which the awk utility is invoked to extract text within the tmcode[fortran] environment.
./lab04/Makefile:
|
A module is constructed with global definitions.
|
|
|
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 |
|
Carry out time steps. For , use specified left boundary value, extrapolate at right. For use specified right boundary value, extrapolate at left.
|
|
for
for |
|
|
|
|
|
|
Compilation of the above implementation leads to a Python-loadable module than can be used for numerical experiments.
from pylab import *
Python]
import os,sys
os.chdir('/home/student/courses/MATH761/lab04')
cwd=os.getcwd()
sys.path.append(cwd)
Python]
from lab04 import *
Python]
print scheme.__doc__
Python]
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 -------
Python]
The boundary value problem
(1) |
is a simplified model of the penetration of a wave into a domain from the left.
def f(x,kappa):
return zeros(size(x))
Python]
def g(t,kappa):
return sin(2*kappa*pi*t)
Python]
m=99; h=1./(m+1); x=arange(m+2)*h;
Python]
u=1;
Python]
FTCS=1; Upwind=2; LaxFriedrichs=3; LeapFrog=4;
LaxWendroff=5; BeamWarming=6;
Python]
Python]
The Fortran code can be invoked from within Python for interactive investigation of the behavior of the numerical schemes.
method=FTCS; nSteps=100; cfl=1; k=h*cfl/u;
t=arange(nSteps+1)*k; kappa=4;
Python]
q0=f(x,kappa); q1=zeros(size(x)); Q0=f(x,kappa);
Q1=zeros(size(x));
Python]
Qlft=g(t,kappa); Qrgt=zeros(size(t));
Python]
Q1=scheme(method,cfl,Q0,Q1,Qlft,Qrgt);
Python]
plot(x[1:m],q0[1:m],'b',x[1:m],Q1[1:m],'r');
xlabel('x'); ylabel('q'); title('FTCS solution of
advection equation');
savefig("Lab04Fig01.pdf");
Python]
Python]
![]() |
More importantly, the Fortran code can be included in Python loops to study the influence of discretization parameters. For example, the predictions of a scheme at different CFL numbers can be investigated. Note that all Python commands are now grouped in a single input field to be executed together, thus allowing efficient modification of initial, boundary conditions, numerical parameters.
method=Upwind;
m=99; h=1./(m+1); x=arange(m+2)*h;
dcfl=0.1; tfinal=0.5;
clf();
qex=g(tfinal-x/u,kappa);
plot(x[1:m],qex[1:m],'k.');
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);
plot(x[1:m],Q1[1:m],'b');
xlabel('x'); ylabel('q'); title('Effect of CFL upon Upwind
solution of advection equation');
savefig("Lab04UpwindSmoothInitCond.pdf");
Python]
Python]
![]() |
Figure 2. Upwind scheme exhibits large
artificial diffusion for .
|
method=LeapFrog;
m=99; h=1./(m+1); x=arange(m+2)*h;
dcfl=0.1; tfinal=0.5;
clf();
qex=g(tfinal-x/u,kappa);
plot(x[1:m],qex[1:m],'k.');
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-u*k,kappa); Q1=f(x,kappa);
Qlft=g(t,kappa); Qrgt=zeros(size(t));
Q1=scheme(method,cfl,Q0,Q1,Qlft,Qrgt);
plot(x[1:m],Q1[1:m],'b');
xlabel('x'); ylabel('q'); title('Effect of CFL upon
leap-frog solution of advection equation');
savefig("Lab04LeapFrogSmoothInitCond.pdf");
Python]
Python]
![]() |
method=LaxWendroff;
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.');
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);
plot(x[1:m],Q1[1:m],'b');
xlabel('x'); ylabel('q'); title('Effect of CFL upon
Lax-Wendroff solution of advection equation');
savefig("Lab04LaxWendroffSmoothInitCond.pdf");
Python]
Python]
![]() |
Study now the behavior for a discontinuous (shock) initial condition
def f(x,kappa):
return zeros(size(x))
def g(t,kappa):
return (sign(t)+1)/2
u=1;
Python]
kappa=4
Python]
Python]
method=Upwind;
m=99; h=1./(m+1); x=arange(m+2)*h;
dcfl=0.1; tfinal=0.5;
clf();
qex=g(tfinal-x/u,kappa);
plot(x[1:m],qex[1:m],'k.');
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);
plot(x[1:m],Q1[1:m],'b');
xlabel('x'); ylabel('q'); title('Shock propagation by
upwind scheme');
savefig("Lab04UpwindShockInitCond.pdf");
Python]
Python]
![]() |
Figure 5. Upwind scheme exhibits diffusion but
predicts correct shock position
|
method=LeapFrog;
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.');
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-u*k,kappa); Q1=f(x,kappa);
Qlft=g(t,kappa); Qrgt=zeros(size(t));
Q1=scheme(method,cfl,Q0,Q1,Qlft,Qrgt);
plot(x[1:m],Q1[1:m],'b');
xlabel('x'); ylabel('q'); title('Shock propagation by
leap-frog scheme');
savefig("Lab04LeapFrogShockInitCond.pdf");
Python]
Python]
![]() |
Figure 6. Leap-frog exhibits artificial
diffusion, dispersion, Gibbs oscillations
|
method=LaxWendroff;
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.');
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);
plot(x[1:m],Q1[1:m],'b');
xlabel('x'); ylabel('q'); title('Shock propagation by
Lax-Wendroff');
savefig("Lab04LaxWendroffShockInitCond.pdf");
Python]
Python]
![]() |
Figure 7. Lax-Wendroff is similar to leap-frog
with more rapidly decaying Gibbs oscillations
|