# Task 1.1, 1.2 import numpy as np from typing import Callable from matplotlib import pyplot as plt # Config D = 1e-6 # diffusion coefficient h = 1 # space domain (max x size) T = 2e6 # solution end time nx = 50 # nr of space discretization points nt = 20000 # nr of time discretization points # derived constants dx = h / (nx - 1) # space step size dt = T / (nt - 1) # time step size d = dt * D / dx**2 # stability/stepsize coefficient # report stability if d > 0.5: print("NOT Stable") else: print("Stable") # explicit scheme integration for `u_t - D u_xx = 0` with boundary conditions # enforced by `set_bounds` and initial conditions `initial`. def integrate(*, name: str, initial: np.array, set_bounds: Callable[[np.array], None]) -> None: C = initial # Setup boundary conditions set_bounds(C) i = 0 # index for plot generation plt.figure(figsize = (8, 6), dpi = 100) for t in range(nt): # every 400'th time step save a plot if t % (nt // 400) == 0: plt.clf() plt.plot(np.linspace(0, h, nx), C) plt.xlim([0, h]) plt.ylim([0, 1.2]) plt.savefig(f"plots/{name}_{i:0>5}.png") i += 1 # update solution using the explicit schema C[1:-1] += d * (C[2:] - 2 * C[1:-1] + C[:-2]) # update right Neumann BC set_bounds(C) # Subtask 1 boundary conditions (Dirichlet and Neumann) def bounds_1(C): C[0] = 1 C[-1] = C[-2] # Subtask 2 boundary conditions (two Dirichlet) def bounds_2(C): C[0] = 1 C[-1] = 0 # run simulations integrate(name = 'task01_1', initial = np.zeros(nx), set_bounds = bounds_1) integrate(name = 'task01_2', initial = np.zeros(nx), set_bounds = bounds_2) # to convert generated image sequence to video use: # $> ffmpeg -r 60 -i plots/task01_1_%05d.png -pix_fmt yuv420p video_1_1.mp4 # $> ffmpeg -r 60 -i plots/task01_2_%05d.png -pix_fmt yuv420p video_1_2.mp4