NSSC/Exercise_03/task02.py

69 lines
3.1 KiB
Python

import numpy as np
from scipy.sparse import spdiags
from scipy.linalg import solve_banded
from matplotlib import pyplot as plt
# Config
dx = 0.01 # space step size
h = 1.5 # space domain (max x size)
# plots a solution to file, simply for code size reduction in `solve`
def plot(x, t, C, C0, analytic, plotname):
plt.clf()
plt.plot(x, C, "o")
plt.xlim([0, h])
plt.title(plotname)
plt.xlabel("Periodic Space: x")
plt.ylabel("Wave Form: C(x, t)")
if analytic is not None:
plt.plot(x, analytic(x, t, C0))
plt.savefig(f"plots/{plotname}_{plot.i:0>5}.png")
plot.i += 1
plot.i = 0
# solver for `C_t + U C_x = 0` given initial state `C`, the current `C0` which
# incorporates `U` as well as the space and time discretization and the number
# of time steps `nt`.
def solve(C, C0, nt, plotname = None, plotskip = 1, analytic = None):
nx = C.shape[0]
if plotname is not None:
plot.i = 0 # (re)set plot counter
x = np.linspace(0, h, nx) # space grid points
fig = plt.figure(figsize = (8, 6), dpi = 100) # setup plot figure size
plot(x, 0, C, C0, analytic, plotname) # plot initial solution
# space grid point `Indices Minus 1`
im1 = np.array([nx - 1] + list(range(nx - 1)))
for t in range(nt):
# upwind update scheme
C = (1 - C0) * C + C0 * C[im1]
if plotname is not None and ((t + 1) % plotskip == 0):
plot(x, t + 1, C, C0, analytic, plotname) # plot current solution
return C
# setup initial conditions
x = np.linspace(0, h, int(h / dx))
gauss = np.exp(-10 * (4 * x - 1)**2)
square = np.array((0.1 < x) * (x < 0.3), dtype = "float")
def gauss_analytic(x, t, C0):
return np.exp(-10 * (4 * (np.mod(x - t * dx / C0, h + 1e-9)) - 1)**2)
def square_analytic(x, t, C0):
x = x - t * dx / C0
x = np.mod(x, h + 1e-9) # hack to avoid shift in the plot
return np.array((0.1 < x) * (x < 0.3), dtype = "float")
solve(gauss, 1, 200, "task02_gauss_C0_1", analytic = gauss_analytic)
solve(square, 1, 200, "task02_square_C0_1", analytic = square_analytic)
solve(gauss, 0.7, 200, "task02_gauss_C0_0.7", analytic = gauss_analytic)
solve(square, 0.7, 200, "task02_square_C0_0.7", analytic = square_analytic)
solve(gauss, 1.1, 200, "task02_gauss_C0_1.1", analytic = gauss_analytic)
solve(square, 1.1, 200, "task02_square_C0_1.1", analytic = square_analytic)
# To generate videos out of the generated plots
# $> ffmpeg -y -r 60 -i plots/task02_gauss_C0_1_%05d.png -pix_fmt yuv420p task02_gauss_C0_1.mp4
# $> ffmpeg -y -r 60 -i plots/task02_square_C0_1_%05d.png -pix_fmt yuv420p task02_square_C0_1.mp4
# $> ffmpeg -y -r 60 -i plots/task02_gauss_C0_0.7_%05d.png -pix_fmt yuv420p task02_gauss_C0_0.7.mp4
# $> ffmpeg -y -r 60 -i plots/task02_square_C0_0.7_%05d.png -pix_fmt yuv420p task02_square_C0_0.7.mp4
# $> ffmpeg -y -r 60 -i plots/task02_gauss_C0_1.1_%05d.png -pix_fmt yuv420p task02_gauss_C0_1.1.mp4
# $> ffmpeg -y -r 60 -i plots/task02_square_C0_1.1_%05d.png -pix_fmt yuv420p task02_square_C0_1.1.mp4