1D wave equation

https://en.wikipedia.org/wiki/Wave_equation

http://hplgit.github.io/num-methods-for-PDEs/doc/pub/wave/html/slides_wave-solarized.html

INTRODUCTION

The wave equation is an important second-order linear partial differential equation for the description of waves, such as mechanical waves or light waves.

The wave equation is the simplest example of a hyperbolic differential equation.

FIXED BOUNDARIES (DIRICHLET)


Unknown function u(x,t), x in [0,L], t in [0,T],
u is the factor representing a displacement from the rest situation,

wave equation u_tt = c^2 u_xx,

c is the constant wave velocity of the medium,
u_tt is double time derivative, 
u_xx is double spatial derivative.

Homogeneous Dirichlet conditions in 1D.
u(x,0) = f(x), x in [0,L], (initial string shape)
u_t(x,0) = 0, x in [0,L], (string starts from rest)
u(0,t) = 0, u(L,t) = 0, t in [0,T]. (fixed ends, no displacement)

Exact solution u(x,t) = f_R(x-ct) + f_L(x+ct),
For t=0: f_R(x) + f_L(x) = f(x), -cf_R' + cf_L' = 0.
Solution: f_R(y) = f_L(y) = f(y)/2,
u(x,t) = ( f(x-ct) + f(x+ct) )/2.
[Boundary conditions may create reflected waves.]

#         j  u(0,t)=0,   t increasing -->
# x=0  +--+--+--+--
#      |  |  |  |
#u(x,0)+--+--o--+--
#=f(x) |  |  |  |
#      +--o--o--o--  u(i,j)
#      |  |  |  |
#    i +--+--o--+--
#      |  |  |  |
# x=L  +--+--+--+--
#         j  u(L,t)=0

Waves on string.
The initial condition f(x) typically has a triangular shape for a picked guitar string.
A peak is at x_0 in [0,L], f(x) = 
[ x/x_0 for x < x_0,
[ (L-x) / (L-x_0) otherwise.

Discretizing the domain
x = i*dx, i = 0..Nx (Nx+1 points), Nx*dx = L, (mesh in space)
t = j*dt, j = 0..Nt (Nt+1 points), Nt*dt = T, (mesh in time)
We use the notation u(i,j)

Finite difference stencil (or scheme)
u_tt = [u(i,j-1) -2*u(i,j) + u(i,j+1)] / (dt*dt)   # central difference O(dt^2)
u_xx = [u(i-1,j) -2*u(i,j) + u(i+1,j)] / (dx*dx)   # central difference O(dx^2)

r = (c*dt/dx)^2, interior mesh points
Stability criterion: r < 1.
u(i,j-1) -2*u(i,j) + u(i,j+1) = r*[u(i-1,j) -2*u(i,j) + u(i+1,j)]

The stencil for the first time level.
u_t = [u(i,j+1) - u(i,j)] / dt   # forward difference O(dt)
u_t(x,0) = 0, u(i,1) = u(i,0), NOT GOOD

u_t = [u(i,j+1) - u(i,j-1)] / (2*dt)   # central difference O(dt^2)
u_t(x,0) = 0, u(i,1) = u(i,-1), how to get u(i,-1)?
Use the equation
2*u(i,1) -2*u(i,0) = r*[u(i-1,0) -2*u(i,0) + u(i+1,0)],

# The order of calculating u(i,j)

for i in range(Nx+1):   # initial condition j=0, all i
    u(i,0) = f(i*dx)   # t=0
assert u(0,0) == 0 and u(Nx,0) == 0

for j in range(1,Nt+1):   # boundary condition i=0 and i=Nx
    u(0,j) = 0   # x=0
    u(Nx,j) = 0   # x=L

for i in range(1,Nx):   # initial condition j=1
    u(i,1) = u(i,0) + (r/2)*[u(i-1,0) -2*u(i,0) + u(i+1,0)]

for j in range(1,Nt):
    for i in range(1,Nx):
        u(i,j+1) = -u(i,j-1) +2*u(i,j) + r*[u(i-1,j) -2*u(i,j) + u(i+1,j)]

# Given mesh points as arrays x and t (x[i], t[j])
dx = x[1] - x[0]
dt = t[1] - t[0]
r = (c*dt/dx)**2

# During calculations we need u(t) from three points in time:
# u[i] present time,
# u1[i] one step to the past,
# u2[i] two steps to the past.
# Generally, we cannot affort to keep all points in time.
# Next optimalization step is the vectorization of loops.

# Scalar version
for i in range(1,Nx):
    u[i] = -u2[i] + 2*u1[i] + r*(u1[i-1] -2*u1[i] + u1[i+1])

# Vectorized version
# 40 times faster, tests in timeit_array.py
u[1:-1] = -u2[1:-1] + 2*u1[1:-1] + r*(u1[:-2] -2*u1[1:-1] + u1[2:])

Generalized problem.
u_tt = c^2 u_xx + s(x,t), x in [0,L], t in [0,T].
c is the constant wave velocity of the medium,
s(x,t) source term.
u(x,0) = f(x), x in [0,L], (initial string shape)
u_t(x,0) = g(x), x in [0,L],
u(0,t) = 0, u(L,t) = 0, t in [0,T]. (fixed ends, no displacement)

REFLECTING BOUNDARIES (NEUMAN))

The wave equation in 1D: reflecting boundaries.


u_tt = c^2 u_xx, x in [0,L], t in [0,T].
u(x,0) = f(x), x in [0,L], (initial string shape)
u_t(x,0) = 0, x in [0,L], (string starts from rest)

Neumann conditions in 1D.
u_x(0,t) = 0, u_x(L,t) = 0, t in [0,T].

#         j  u_x(0,t)=0,   t increasing -->
# x=0  +--+--+--+--
#      |  |  |  |
#u(x,0)+--+--o--+--
#=f(x) |  |  |  |
#      +--o--o--o--  u(i,j)
#      |  |  |  |
#    i +--+--o--+--
#      |  |  |  |
# x=L  +--+--+--+--
#         j  u_x(L,t)=0

u_x = [u(i+1,j) - u(i-1,j)] / (2*dx)   # central difference O(dx^2)
u(1,j) = u(-1,j) for i=0,
u(Nx+1,j) = u(Nx-1,j) for i=Nx.

Use the equation for i=0
u(0,j-1) -2*u(0,j) + u(0,j+1) = 2*r*[-u(0,j) + u(1,j)]

Use the equation for i=Nx
u(Nx,j-1) -2*u(Nx,j) + u(Nx,j+1) = 2*r*[u(Nx-1,j) -u(Nx,j)]

# The order of calculating u(i,j)
for i in range(Nx+1):   # initial condition j=0
    u(i,0) = f(i*dx)   # t=0

# It can be done in one loop
for i in range(Nx+1):   # for j=1
    ip1 = i+1 if i < Nx else i-1
    im1 = i-1 if i > 0  else i+1
    u(i,1) = u(i,0) + (r/2)*[u(im1,0) -2*u(i,0) + u(ip1,0)]

# It can be done in one loop
for i in range(Nx+1):   # for j > 0
    ip1 = i+1 if i < Nx else i-1
    im1 = i-1 if i > 0  else i+1
    u(i,j+1) = -u(i,j-1) +2*u(i,j) + r*[u(im1,j) -2*u(i,j) + u(ip1,j)]