Burgers equation using FFT

Contents

Burgers equation using FFT#

See notes of Hannes Uecker, Example 3.6.

\[ u_t + f(u)_x = \nu u_{xx}, \qquad f(u) = \frac{1}{2} u^2 \]

with periodic boundaries and initial condition

\[ u(x,0) = 1/\cosh(4(x-\pi)) \]

Take Fourier transform

\[ \hat{u}_t + i k \hat{f} = -\nu k^2 \hat u, \qquad \hat{f} = \widehat{ \left(\frac{u^2}{2}\right) } \]

Semi-implicit scheme: forward Euler for non-linear term and backward Euler for viscous term

(2)#\[\begin{align} \frac{\hat{u}^{n+1} - \hat{u}^n}{\Delta t} + i k \hat{f}^n &= - \nu k^2 \hat{u}^{n+1} \\ \hat{u}^{n+1} = \frac{\hat{u}^n - (i k \Delta t) \hat{f}^n}{1 + \nu k^2 \Delta t} \end{align}\]
from pylab import *
from matplotlib.collections import PolyCollection
nu = 1.0e-2
N  = 128
h  = 2*pi/N
x  = h * arange(N)

t = 0.0; dt = h/5.0
tmax = 4.0; tplot = 0.1;
plotgap = int(round(tplot/dt)); dt = tplot/plotgap;
nplots = int(round(tmax/tplot))

k = 2*pi*fftfreq(N,h)
mu = 1.0/(1.0 + nu * dt * k**2)

# Initial condition
v = 1.0/cosh(4*(x-pi))

data = []; data.append(list(zip(x, v)))
tdata = []; tdata.append(0.0)

for i in range(1,nplots):
    for n in range(plotgap):
        t = t + dt
        vh = fft(v)
        fh = fft(0.5*v**2)
        vh = mu * (vh - dt * 1j * k * fh)
        v = real(ifft(vh))
    data.append(list(zip(x, v)))
    tdata.append(t);

fig = figure(figsize=(12,10))
ax = fig.add_subplot(111,projection='3d')
poly = PolyCollection(data, closed=False, facecolors='white', edgecolors='red')
poly.set_alpha(1)
ax.add_collection3d(poly, zs=tdata, zdir='y')
ax.set_xlabel('x'); ax.set_ylabel('t'); ax.set_zlabel('v')
ax.set_xlim3d(0, 2*pi); ax.set_ylim3d(0, 4); ax.set_zlim3d(0, 1)
ax.view_init(40,-70)
ax.set_box_aspect(aspect=(1, 1, 0.5))
_images/942525bf026d24f667d610c28a87a1f9d82abbc2e5bcd17d86ff56e2b4401cac.png

Animation#

import matplotlib.pyplot as plt
from matplotlib import animation
from matplotlib import rc
rc('animation', html='jshtml')

# First set up the figure, the axis, and the plot element we want to animate
fig = plt.figure()
ax = plt.axes(xlim=(0, 2*pi), ylim=(-0.1, 1.1))
line, = ax.plot([], [], 'r-', lw=2, label='u')
ax.set_xlabel('x'); ax.set_ylabel('u')
plt.close();

# initialization function: plot the background of each frame
def init():
    line.set_data([], [])
    return line,

# animation function.  This is called sequentially
def animate(i):
    x, v = zip(*data[i])
    line.set_data(x, v)
    return line,

# call the animator.  blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, animate, init_func=init, repeat=False,
                               frames=len(data), interval=50, blit=True)

# Save to file
#try:
#    anim.save('p06.mp4', fps=20, extra_args=['-vcodec', 'libx264'])
#except:
#    print("Cannot save mp4 file")
anim