Abgabe
This commit is contained in:
parent
3411749b63
commit
c13752c003
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,154 @@
|
|||
import numpy as np
|
||||
from scipy.sparse import spdiags
|
||||
from scipy.linalg import solve_banded
|
||||
from matplotlib import pyplot as plt
|
||||
|
||||
# Config
|
||||
D = 1e-6 # diffusion coefficient
|
||||
h = 1 # space domain (max x size)
|
||||
T = 2e5 # solution end time
|
||||
nx = 50 # nr of space discretization points
|
||||
nt = 1000 # nr of time discretization points
|
||||
|
||||
# derived constants
|
||||
dx = h / (nx - 1) # space step size
|
||||
dt = T / nt # time step size
|
||||
d = dt * D / dx**2 # stability/stepsize coefficient
|
||||
|
||||
# Task 1.1 equation system matrix `C^n+1 = A1 C^n`
|
||||
def A1(d):
|
||||
a1 = np.zeros([3, nx])
|
||||
# superdiagonal (above the main diagonal)
|
||||
a1[0, 1] = 0
|
||||
a1[0, 2:] = d
|
||||
# main diagonal
|
||||
a1[1, 0] = 1
|
||||
a1[1, 1:] = 1 - 2 * d
|
||||
# subdiagonal (below the main diagonal)
|
||||
a1[2, :-2] = d
|
||||
a1[2, -2] = 2 * d
|
||||
# convert to sparse tridiagonal matrix
|
||||
return spdiags(a1, [1, 0, -1], nx, nx)
|
||||
|
||||
# Task 1.2 equation system matrix `C^n+1 = A2 C^n`
|
||||
def A2(d):
|
||||
a2 = A1(d).data
|
||||
# addapt boundary condition coefficients, the rest is identical
|
||||
a2[0, -1] = a2[1, -1] = a2[2, -2] = 0
|
||||
# convert to sparse tridiag
|
||||
return spdiags(a2, [1, 0, -1], nx, nx)
|
||||
|
||||
# Task 1.3 equation system matrix for update rule `A3 C^n+1 = C^n`
|
||||
def A3(d):
|
||||
a3 = np.zeros([3, nx])
|
||||
# superdiagonal
|
||||
a3[0, 1] = 0
|
||||
a3[0, 2:] = -d
|
||||
# main diagonal
|
||||
a3[1, 0] = 1
|
||||
a3[1, 1:] = 1 + 2 * d
|
||||
# supdiagonal
|
||||
a3[2, :-2] = -d
|
||||
a3[2, -2] = -2 * d
|
||||
# as tridiag
|
||||
return spdiags(a3, [1, 0, -1], nx, nx)
|
||||
|
||||
# Task 1.4 equation system matrix `A4`` in `(I + A4) C^n+1 = (I - A4) C^n`
|
||||
def A4(d):
|
||||
a4 = np.zeros([3, nx])
|
||||
# superdiagonal
|
||||
a4[0, 2:] = -d / 2
|
||||
# main diagonal
|
||||
a4[1, 1:] = d
|
||||
# supdiagonal
|
||||
a4[2, :-2] = -d / 2
|
||||
a4[2, -2] = -d
|
||||
return spdiags(a4, [1, 0, -1], nx, nx)
|
||||
# setup `I + A4` and `I - A4`
|
||||
def IpA4(d):
|
||||
ipA4 = A4(d).data
|
||||
ipA4[1, ] += 1
|
||||
return spdiags(ipA4, [1, 0, -1], nx, nx)
|
||||
def ImA4(d):
|
||||
imA4 = -A4(d).data
|
||||
imA4[1, ] += 1
|
||||
return spdiags(imA4, [1, 0, -1], nx, nx)
|
||||
|
||||
# plots a solution to file, simply for code size reduction in `solve`
|
||||
def plot(x, C, name):
|
||||
plt.clf()
|
||||
plt.plot(x, C)
|
||||
plt.xlim([0, h])
|
||||
plt.ylim([0, 1.2])
|
||||
plt.title(name)
|
||||
plt.xlabel("Distance from Source: x")
|
||||
plt.ylabel("Concentration: C(x, t)")
|
||||
plt.savefig(f"plots/{name}_{plot.i:0>5}.png")
|
||||
plot.i += 1
|
||||
plot.i = 0
|
||||
|
||||
# solver for `C_t - D C_xx = 0` given discretized equation system matrices for
|
||||
# a time update rule `L C^n+1 = R C^n` starting from an initial solution `C`.
|
||||
# The update is iterated for `nt` time steps corresponding to a solution at
|
||||
# time `T = dt nt`
|
||||
def solve(C, L, R, nt, plotname = None, plotskip = 5):
|
||||
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, C, plotname) # plot initial solution
|
||||
for t in range(nt):
|
||||
rhs = C if R is None else R @ C
|
||||
C = rhs if L is None else solve_banded((1, 1), L.data, rhs)
|
||||
if plotname is not None and ((t + 1) % plotskip == 0):
|
||||
plot(x, C, plotname) # plot current solution
|
||||
return C
|
||||
|
||||
# setup initial solution
|
||||
C0 = np.zeros(nx)
|
||||
C0[0] = 1
|
||||
|
||||
# run simulation and generate plots for each subtask
|
||||
C1 = solve(C0, None, A1(d), nt, "task01_1")
|
||||
Cx = solve(C0, None, A1(0.55), 200, "task01_x", 1) # run with unstable `d > 0.5`
|
||||
C2 = solve(C0, None, A2(d), nt, "task01_2")
|
||||
C3 = solve(C0, A3(d), None, nt, "task01_3")
|
||||
C4 = solve(C0, IpA4(d), ImA4(d), nt, "task01_4")
|
||||
|
||||
# to convert generated image sequence to video use:
|
||||
# $> ffmpeg -y -r 60 -i plots/task01_1_%05d.png -pix_fmt yuv420p video_1_1.mp4
|
||||
# $> ffmpeg -y -r 60 -i plots/task01_x_%05d.png -pix_fmt yuv420p video_1_x.mp4
|
||||
# $> ffmpeg -y -r 60 -i plots/task01_2_%05d.png -pix_fmt yuv420p video_1_2.mp4
|
||||
# $> ffmpeg -y -r 60 -i plots/task01_3_%05d.png -pix_fmt yuv420p video_1_3.mp4
|
||||
# $> ffmpeg -y -r 60 -i plots/task01_4_%05d.png -pix_fmt yuv420p video_1_4.mp4
|
||||
|
||||
# compute till no time change, e.g. `t -> inf`
|
||||
C1inf = solve(C0, None, A1(d), 20000)
|
||||
C2inf = solve(C0, None, A2(d), 20000)
|
||||
|
||||
x = np.linspace(0, h, nx) # space grid points
|
||||
fig = plt.figure(figsize = (8, 6), dpi = 100) # setup plot figure size
|
||||
plot.i = 0 # reset plot counter
|
||||
plot(x, C1inf, "Cinf")
|
||||
plot(x, C2inf, "Cinf")
|
||||
|
||||
|
||||
# # All plots in one
|
||||
C1 = solve(C0, None, A1(d), nt)
|
||||
C2 = solve(C0, None, A2(d), nt)
|
||||
C3 = solve(C0, A3(d), None, nt)
|
||||
C4 = solve(C0, IpA4(d), ImA4(d), nt)
|
||||
|
||||
x = np.linspace(0, h, nx) # space grid points
|
||||
plt.figure(figsize = (8, 6), dpi = 100) # setup plot figure size
|
||||
plt.plot(x, C1, label = "1.1")
|
||||
plt.plot(x, C2, label = "1.2")
|
||||
plt.plot(x, C3, label = "1.3")
|
||||
plt.plot(x, C4, label = "1.4")
|
||||
plt.xlim([0, h])
|
||||
plt.ylim([0, 1.2])
|
||||
plt.title("All")
|
||||
plt.legend()
|
||||
plt.xlabel("Distance from Source: x")
|
||||
plt.ylabel("Concentration: C(x, t)")
|
||||
plt.savefig(f"plots/task01_all.png")
|
|
@ -0,0 +1,68 @@
|
|||
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
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue