The Wave Equation

The wave equation is one of the canonical partial differential equationss with which numericists deal, and an example of a hyperbolic PDE. As you probably know, the equation for a parabola is

$$ x^2 = a^2 y^2+b. $$

Similar to this, the standard wave equation in one dimension is

$$ \frac{\partial^2 u}{\partial t^2} = c^2\frac{\partial ^2 u}{\partial x^2}. $$

This is a model for a system radiating information, where the speed of the propagation is $c$, whichand has units of m/s.

When $c$ is constant, the equation accepts leftward and rightward travelling wave solutions, $f(x+ct)$ and $g(x-ct)$.

Initial Conditions

The second order ODE can be rewritten as a pair of coupled first order ODEs, $$ \frac{\partial v}{\partial t} = c^2\frac{\partial ^2 u}{\partial t}, $$ $$ \frac{\partial u}{\partial t} = v. $$ where the second equation is a rewritten version of the identity, $v=\frac{\partial u}{\partial t}$. From this, it can be seen that we need to provide initial conditions for both $u$ and $v$, i.e $$ u(x,0)= U(x) $$ $$\frac{\partial u}{\partial t} (x,0)= V(x). $$

Boundary Conditions

The boundary conditions must supply enough information to control both leftward and rightward travelling waves, so that we need a boundary condition on every boundary.

Lets build a finite difference model for a wave equation

In [44]:
# import relevant modules

import numpy
from scipy import linalg
from bqplot import pyplot
from IPython.display import display
import ipywidgets

# set up our discretization

N = 101
Nt= 100
dx = 10.0/(N-1)
dt=1.0
c=1.0
x = numpy.linspace(-10.0, 10.0, N)

# useful matrices. A handles the new step, B the old.

A = numpy.zeros([2*N, 2*N])
B = numpy.zeros([2*N, 2*N])

for j in range(N):
    # Dirichlet boundary conditions
    A[j,j] = 1.0
    A[N-1,N-1] = 1.0
    A[N+j,N+j] = 1.0
    A[2*N-1,2*N-1] = 1.0
for i in range(1,N-1):
    A[i, i] = 1.0
    A[i, N+i-1] =-dt*c*1.0/dx**2/2.0
    A[i, N+i] = +dt*c*2.0/dx**2/2.0
    A[i, N+i+1] = -dt*c*1.0/dx**2/2.0
    A[N+i, i] = -dt/2.0
    A[N+i, N+i] = 1.0
    B[i, i] = 1.0
    B[i, N+i-1] = dt*c*1.0/dx**2/2.0
    B[i, N+i] = -dt*c*2.0/dx**2/2.0
    B[i, N+i+1] = dt*c*1.0/dx**2/2.0
    B[N+i, i] = dt/2.0
    B[N+i, N+i] = 1.0
    


# initial conditions
    
y = numpy.zeros(2*N)
y[:N]=numpy.exp(-x**2)

Y=[]
    
for _ in range(Nt):
    Y.append(y)
    z=numpy.dot(B,y)
    y = linalg.solve(A, z)

Y.append(y)

pyplot.figure(1)
xsc = pyplot.LinearScale(min=-10,max=10)
ysc = pyplot.LinearScale(min=-1,max=1)
axy = pyplot.Axis(label='u', scale=ysc, orientation='vertical', side='left', grid_lines='solid')
axx = pyplot.Axis(label='x', scale=xsc, grid_lines='solid')
lines = pyplot.Lines(x=x, y=Y[0][:N], scales = {'x': xsc, 'y': ysc})
plt = pyplot.Figure(layout=ipywidgets.Layout(width='auto'), marks=[lines],axes=[axx,axy])
def g(t):
    lines.y = Y[int(t/dt)][:N]
    
w = ipywidgets.interactive(g, t=(0.,1.0*Nt,1));
slider = w.children[0]
output = w.children[-1]

play = ipywidgets.Play(
#     interval=10,
    value=0,
    min=0,
    max=Nt,
    step=1,
    description="Press play",
    disabled=False
)


ipywidgets.jslink((play, 'value'), (slider, 'value'))

display(ipywidgets.HBox([play, slider]))
display(plt)
In [ ]:
 
In [ ]: