Burger equation with MacCormack scheme. · Ricardo

Burger equation with MacCormack scheme.

Burgers with MacCormack

Conside the 1D Burgers equation:

\begin{equation} \frac{\partial u}{\partial t}=-u\frac{\partial u}{\partial x} \end{equation}

We want to represent this in conservative forms so that we can better deal with potential shocks, which gives us:

\begin{equation} \frac{\partial u}{\partial t}=-\frac{\partial }{\partial x}\left(\frac{u^2}{2}\right) \end{equation}

We can also write this as:

\begin{equation} \frac{\partial u}{\partial t}=-\frac{\partial F}{\partial x} \end{equation}

If we take $F=\frac{u^2}{2}$. Start with a Heaviside function (a sep function) with the following values:

\begin{equation} u(x,0)=\left\{\begin{array}{cc} 1 & 0\leq x<2 \\ 0 & 2\leq x\leq 4 \end{array}\right. \end{equation}

import numpy as np
import matplotlib.pyplot as plt
from numba import njit
from matplotlib.animation import FuncAnimation
from jupyterthemes import jtplot
jtplot.style(theme='monokai')

Create the initial conditions for $u(x,0)$.

def IC(Nx,Nt,x):
    u=np.zeros((Nx,Nt)) #Create the matrix
    mask=np.where(x<2) #Create a mask where x is less than 2
    #Now, create a loop to put the initial values.
    for i in range(len(mask[-1])):
        u[i,0]=1
    return u

Now, you can use the MacCormack method to solve the PDE. The MacCormack scheme is:

\begin{equation} \large\begin{array}{cc} u_i^*=u_i^t-\frac{\Delta t}{\Delta x}(F_{i+1}^t+F_i^t) & \text{Predictor} \\
u_i^{t+1}=\frac{1}{2}\left(u_{i}^t+u_i^*-\frac{\Delta t}{\Delta x}(F_i^*-F_{i-1}^*)\right) & \text{Corrector} \end{array} \end{equation}

Remember that

\begin{equation} F=\frac{u^2}{2} \end{equation}

You can create two functions to solve this system

def F(u):
    return u**2/2

def u_star(u,k,i,j):
    return u[i,j]-k*(F(u[i+1,j])-F(u[i,j]))

def solution(Nx,Nt,x,dx,dt):
    u=IC(Nx,Nt,x) #Use the function to create the matrix and put the IC
    k=dt/dx       #For simplicity
    for j in range(Nt-1):
        for i in range(Nx-1):
            u[i,j+1]=0.5*(u[i,j]+u_star(u,k,i,j)-k*(F(u_star(u,k,i,j))-F(u_star(u,k,i-1,j))))
        u[0,j+1]=1
    return u

Use $N_x=81$, $N_t=70$ and $\Delta t=0.5\Delta x$.

Nx=81
Nt=70
x=np.linspace(0,4,Nx)
dx=4/(Nx-1)
dt=0.5*dx

u=solution(Nx,Nt,x,dx,dt)

Create an animate plot.

fig,axs=plt.subplots(1,figsize=(12,5))
line,=axs.plot([],[],color='teal',marker='o',markevery=5)
axs.set_xlim(x.min(),x.max())
axs.set_ylim(u.min()-0.5,u.max()+0.5)
axs.grid(False)

def animate(i):
    global x,u
    #axs.clear_collections()
    line.set_data(x,u[:,i])
    return line,

anim=FuncAnimation(fig,animate,frames=Nt,interval=60,blit=True)
plt.close()
anim.save('burger.mp4',fps=20)

The oscillations at the front of the shock are characteristic of all 2nd-order methods, but there are ways to remove them. One option is numerical damping.

A common damping term used with MacCormack scheme is: \begin{equation} \epsilon(u_{i+1}^t-2u_i^t+u_{i-1}^t) \end{equation}

I’ll add this term to the predictor step so i get this:

\begin{equation} u_i^*=u_i^t-\frac{\Delta t}{\Delta x}(F_{i+1}^t+F_i^t)+\epsilon(u_{i+1}^t-2u_i^t+u_{i-1}^t) \end{equation}

But I have a problem when $i=0$, because i’m gonna get $u_{-1}^{n}$. and that value is not part of my grid. So what I can do? Well, suppose that you have:

\begin{equation} \large\begin{array}{ccc} \frac{\partial u_0^t}{\partial t}=0 & \text{ then $\rightarrow$ } & \frac{\partial u_0^t}{\partial t}=\frac{u_{0}^t-u_{-1}^t}{\Delta t}=0 \end{array} \end{equation}

So, it’s easy to see that I can have $u_{-1}^t=u_0^{t}$. So, for the firs value, I have:

\begin{equation} u_0^*=u_0^t-\frac{\Delta t}{\Delta x}(F_{1}^t+F_0^t)+\epsilon(u_{1}^t-u_0^t) \end{equation}

def u_star(u,k,i,j):
    global epsilon
    if (i==0):
        return u[i,j]-k*(F(u[i+1,j])-F(u[i,j]))+epsilon*(u[i+1,j]-u[i,j])
    else:
        return u[i,j]-k*(F(u[i+1,j])-F(u[i,j]))+epsilon*(u[i+1,j]-2*u[i,j]+u[i-1,j])

epsilon=0.5
u=solution(Nx,Nt,x,dx,dt)

anim=FuncAnimation(fig,animate,frames=Nt,interval=60,blit=True)

anim.save('burger_no.mp4',fps=20)

That’s all for this post! You can check the jupyter notebook from this problem here.