Script for solving advection problems in 1D using FDM

We will use two different schemes to solve the general advection problem in 1D

First we load some useful libraries

[21]:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import animation
from IPython.display import HTML
from matplotlib.patches import Rectangle

Next we define some physics constants

[22]:
width   = 40           # width of domain
vel     = 4             # velocity in x direction
ampl    = 2             # amplitude of gaussian
sigma   = 1             # width of initial guassian
xc      = width/2.      # center of gaussian
dt      = 2e-2          # time step

and some numerical constants constants

[23]:
nx      = 201                                          # Number of gridpoints in x-direction
nt      = 100                                          # Number of timesteps to compute
Xvec,dx = np.linspace(0, width, nx,  retstep=True)    # X coordinate vector, constant spacing

Set the initial conditions

[24]:
C_init  = ampl*np.exp(-np.square(Xvec-xc)/sigma**2)
time    = 0

Make a function that computes temperature

[25]:
# hide
# only store the latest time step solution to Cold
def advect1d_uw(Cold):
    Cnew=Cold.copy()
    if vel>0:
        for i in range(1,len(Xvec)):
            Cnew[i] =dt*(-vel* (Cold[i] - Cold[i-1])/dx) + Cold[i]
    else:
         for i in range(0,len(Xvec)-1):
            Cnew[i] =dt*(-vel* (Cold[i+1] - Cold[i])/dx) + Cold[i]

    return Cnew


def advect1d_ftcs(Cold):
    Cnew=Cold.copy()
    for i in range(1,len(Xvec)-1):
            Cnew[i] =dt*(-vel* (Cold[i+1] - Cold[i-1])/(2*dx)) + Cold[i]

    return Cnew
[26]:
# write two functions that update the concentration using FTCS and upwind!

#def advect1d_uw(Cold):
#    Cnew=Cold.copy()
#    if vel>0:
#        for i in ???:
#            Cnew[i] ???
#    else:
#         for i in ???:
#            Cnew[i] =???
#
#    return Cnew


#def advect1d_ftcs(Cold):
#    Cnew=Cold.copy()
#    for i in ???:
#            Cnew[i] =???
#
#    return Cnew

Compute and visualize everything

[35]:
# First set up the figure, the axis, and the plot element we want to animate
fig = plt.figure(figsize=(10,5))
ax = plt.axes(xlim=(0, width), ylim=(-0.2*ampl, 1.5*ampl))
ax.set_xlabel('Distance')
ax.set_ylabel('Concentration')
timeLabel=ax.text(0.02,0.98,'Time: ',transform=ax.transAxes,va='top')

num_solutions       = 3
lines = []
for i in range(0,num_solutions):
    line, = ax.plot([], [], lw=1)
    lines.append(line)

# Initialize Tnew
Cnew_uw=C_init
Cnew_ftcs=C_init

# Animation function which updates figure data.  This is called sequentially
def animate(i):
    timeLabel._text='Time: %.1f'%(i*dt)

    # use global keyword to store the latest solution and update it using fdm_solve function
    global Cnew_uw, Cnew_ftcs, Cnew_ana

    # numerical solutions
    if i==0:
        Cnew_uw=C_init
        Cnew_ftcs=C_init
        Cnew_ana=C_init
    else:
        Cnew_uw=advect1d_uw(Cnew_uw)
        Cnew_ftcs=advect1d_ftcs(Cnew_ftcs)
        Cnew_ana=ampl*np.exp(-np.square(Xvec-xc-i*dt*vel)/sigma**2)

    lines[0].set_data(Xvec, Cnew_uw)
    lines[1].set_data(Xvec, Cnew_ftcs)
    lines[2].set_data(Xvec, Cnew_ana)

    return lines


# Call the animator.
anim = animation.FuncAnimation(fig, animate,frames=nt,interval=50)
plt.close(anim._fig)

# Call function to display the animation
#HTML(anim.to_html5_video())  # lower resolution
HTML(anim.to_jshtml())  # higher resolution

[35]:
[ ]: