diff --git a/.gitattributes b/.gitattributes index 206b15a..a04dcad 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,3 @@ *.png filter=lfs diff=lfs merge=lfs -text *.svg filter=lfs diff=lfs merge=lfs -text +*.mp4 filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore index 77e6580..40c2b06 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,6 @@ plots/ # vscode workspace config .vscode/ + +# LaTeX compile files + diff --git a/Exercise_03/Dirichlet_EA.m b/Exercise_03/Dirichlet_EA.m deleted file mode 100755 index 1243748..0000000 --- a/Exercise_03/Dirichlet_EA.m +++ /dev/null @@ -1,59 +0,0 @@ -function [x,t,u] = Dirichlet_EA(L,N,T,K,c1,c2,f,u0,D) -% ---- Solution of heat equation ---- -% u_t - u_xx = f in the interval [-L,L] (doesn't matter if we change it) -% Dirichlet BC -% -% ----------------------------------------------- -% Sintassi: -% [x,t,u]=calore_template(L,N,T,K,c1,c2,fun,u0) -% -% Input: -% L Half of the width (-L,L) -% N number of intervals in (-L,L) -% T max time (0,T) -% K number of intervals in (0,T) -% c1 Dirichlet BC in x=-L -% c2 Dirichlet BC in x=L -% f force function -% u0 initial condition in t=0 -% -% Output: -% x vector of the spatial nodes -% t vector of the time nodes -% u numeric solution of the problem - -% discretisation step in time and space -h=L/N; %space -tau=T/K; %time -% Initialization of t -t=linspace(0,T,K+1)'; -% initialization of x -x=linspace(0,L,N+1); - -% Initialization of the matrix solution u -u=zeros(N+1,K+1); -% Intial conditions -u(:,1)=u0(x); - -% BC -u(1,:)=c1(t); -u(end,:)=c2(t); - -% Creation of the matrix A -% We obtained this matrix using the Central Discretization method -e=ones(N-1,1); -A=spdiags([-e,2*e,-e],[-1,0,1],N-1,N-1)/(h^2); -I=speye(N-1,N-1); - -% Compute the solution -% What we are doing here is to compute the solution in the interval for -% each time k -for k=1:K - % Assembly of the force - F=f(x(2:end-1),t(k)); - % Correction of the force using the BC - F(1)=F(1) + D*c1(t(k))/(h^2); - F(end)=F(end) + D*c2(t(k))/(h^2); - % Solution using Eulero forward - u(2:end-1,k+1) = ((I - tau*D*A)*u(2:end-1,k))' + tau*F; -end diff --git a/Exercise_03/Exercise3.pdf b/Exercise_03/Exercise3.pdf index 40cfd4b..c7a10f4 100644 Binary files a/Exercise_03/Exercise3.pdf and b/Exercise_03/Exercise3.pdf differ diff --git a/Exercise_03/Mixed_EA.m b/Exercise_03/Mixed_EA.m deleted file mode 100755 index 1ac4aee..0000000 --- a/Exercise_03/Mixed_EA.m +++ /dev/null @@ -1,63 +0,0 @@ -function [x,t,u] = Mixed_EA(L,N,T,K,c1,c2,f,u0,D) -% ---- Solution of heat equation ---- -% u_t - u_xx = f in the interval [-L,L] (doesn't matter if we change it) -% Dirichlet BC -% -% ----------------------------------------------- -% Sintassi: -% [x,t,u]=calore_template(L,N,T,K,c1,c2,fun,u0) -% -% Input: -% L Half of the width (-L,L) -% N number of intervals in (-L,L) -% T max time (0,T) -% K number of intervals in (0,T) -% c1 Dirichlet BC in x=-L -% c2 Dirichlet BC in x=L -% f force function -% u0 initial condition in t=0 -% -% Output: -% x vector of the spatial nodes -% t vector of the time nodes -% u numeric solution of the problem - -% discretisation step in time and space -h=L/N; %space -tau=T/K; %time -% Initialization of t -t=linspace(0,T,K+1)'; -% initialization of x -x=linspace(0,L,N+1); - -% Initialization of the matrix solution u -u=zeros(N+1,K+1); -% Intial conditions -u(:,1)=u0(x); - -% BC Dirichlet -u(1,:)=c1(t); - -% Creation of the matrix A -% We obtained this matrix using the Central Discretization method -e=ones(N-1,1); -A=spdiags([-e,2*e,-e],[-1,0,1],N-1,N-1)/(h^2); -%modify the matrix such that we can use the noimann condition to calculate -%the last node. -%In this case we want to use a second order decentralized approximation -A(end,end-1)=-2/(h^2); -I=speye(N-1,N-1); - -% Compute the solution -% What we are doing here is to compute the solution in the interval for -% each time k -for k=1:K - % Assembly of the force - F=f(x(2:end-1),t(k)); - % Correction of the force using the BC - F(1)=F(1) + D*c1(t(k))/(h^2); - F(end)=F(end) + 2*h*c2; - % Solution using Eulero forward - u(2:end-1,k+1) = ((I - D*tau*A)*u(2:end-1,k))' + tau*F; - u(end,k+1)=u(end-2,k+1) + c2*2*h*D; -end diff --git a/Exercise_03/Mixed_EI.m b/Exercise_03/Mixed_EI.m deleted file mode 100755 index 635f458..0000000 --- a/Exercise_03/Mixed_EI.m +++ /dev/null @@ -1,62 +0,0 @@ -function [x,t,u] = Mixed_EI(L,N,T,K,c1,c2,f,u0,D) -% ---- Risoluzione dell'equazione del calore ---- -% u_t - u_xx = f nell'intervallo [-L,L] -% con condizioni al bordo di Dirichlet -% e condizioni iniziali. -% ----------------------------------------------- -% Sintassi: -% [x,t,u]=calore_template(L,N,T,K,c1,c2,fun,u0) -% -% Input: -% L semiampiezza intervallo spaziale (-L,L) -% N numero di sottointervalli in (-L,L) -% T estremo finale intervallo temporale (0,T) -% K numero di sottointervalli in (0,T) -% c1 funzione che descrive la condizione di Dirichlet in x=-L -% c2 funzione che descrive la condizione di Dirichlet in x=L -% f funzione che descrive il termine noto dell'equazione -% u0 funzione che descrive la condizione iniziale in t=0 -% -% Output: -% x vettore dei nodi spaziali -% t vettore dei nodi temporali -% u soluzione numerica -% del problema - -% Calcolo passo di discretizzazione in spazio e tempo -h=L/N; -tau=T/K; -% Inizializzazione del vettore t -t=linspace(0,T,K+1); -% Inizializzazione del vettore x -x=linspace(0,L,N+1); - -% Inizializzazione della matrice soluzione u -u=zeros(N+1,K+1); -% Condizione iniziale -u(:,1)=u0(x); - -% BC Dirichlet -u(1,:)=c1(t); - -% Creation of the matrix A -% We obtained this matrix using the Central Discretization method -e=ones(N-1,1); -A=spdiags([-e,2*e,-e],[-1,0,1],N-1,N-1)/(h^2); -%modify the matrix such that we can use the noimann condition to calculate -%the last node. -%In this case we want to use a second order decentralized approximation -A(end,end-1)=-2/(h^2); -I=speye(N-1,N-1); - - -for k=1:K - % Assemblaggio termine noto - F=f(x(2:end-1),t(k+1)); - % Correzione del termine noto con le condizioni al bordo - F(1)=F(1) + c1(t(k+1))/(h^2); - F(end)=c2*h*2; - % Risoluzione del problema - u(2:end-1,k+1) = ((I+tau*A)\u(2:end-1,k))' + tau*F; - u(end,k+1)=u(end-2,k+1) + c2*2*h; -end diff --git a/Exercise_03/NSSC_1.m b/Exercise_03/NSSC_1.m deleted file mode 100755 index e694ce7..0000000 --- a/Exercise_03/NSSC_1.m +++ /dev/null @@ -1,107 +0,0 @@ -%% Euler forward Dirichlet -L = 1; % domain size (in the lecture notes this is denote h) -T = 2; % time limit (max time) -f = @(x,t) 0*x.*t; % rhs of the more general equation `u_t - d u_xx = f` -c1 = @(t) 1+0*t; % _right_ boundary condition -c2 = @(t) 0*t; % _left_ boundary condition -u0 = @(x) 0*x; % initial values -D = 0.5; % diffusion parameter `d` in `u_t - d u_xx = f` -%uex = @(x,t) cos(x).*exp(t); - -N = 10; % nr. of _space_ discretization points -K = 200; % nr. of _time_ discretization points -[x, t, u] = Dirichlet_EA(L, N, T, K, c1, c2, f, u0, D); - -% Report stability condition `D Delta T / (Delta x)^2 > 0.5` -Delta_T = T / K; -Delta_x = L / N; -d = D * Delta_T / Delta_x^2; -fprintf("Stability Condition: 0.5 >= D * Delta_T / Delta_x^2 = %f\n", d) -if d > 0.5 - fprintf("-> NOT Stable\n") -else - fprintf("-> Stable\n") -end - -figure(1) -for ii = 1:K+1 % iterates time - hold on - plot(x, u(:, ii)'); - xlim([0 L]) - pause(0.05); - hold off -end - -% 3D plot of space solution over time -space = linspace(0,L,101); -time = linspace(0,T,201); -[xx,yy] = meshgrid(time,space); -%exsol = uex(yy,xx); -figure(2) -mesh(t,x,u) -%figure(2) -%mesh(xx,yy,exsol) - -%% Eulero forward Mixed BC - -L=2*pi; -T=5; -f=@(x,t) 0*x.*t; -c1=@(t) 1+0*t; -c2=0; -u0=@(x) 0*x; -D=1.1; -%uex=@(x,t) cos(x).*exp(t); - -N=25; -K=200; -[x,t,u]=Mixed_EA(L,N,T,K,c1,c2,f,u0,D); - -figure(1) -for ii=1:K+1 - plot(x,u(:,ii)'); - xlim([0 L]) - ylim([0 1.5]) - pause(0.02); -end - -space=linspace(0,L,101); -time=linspace(0,T,201); -[xx,yy]=meshgrid(time,space); -%exsol=uex(yy,xx); -figure(2) -mesh(t,x,u) -%figure(2) -%mesh(xx,yy,exsol) - -%% Eulero Backward Mixed BC - -L=2*pi; -T=5; -f=@(x,t) 0*x.*t; -c1=@(t) 1+0*t; -c2=0; -u0=@(x) 0*x; -D=1; -%uex=@(x,t) cos(x).*exp(t); - -N=25; -K=200; -[x,t,u]=Mixed_EI(L,N,T,K,c1,c2,f,u0,D); - -figure(1) -for ii=1:K+1 - plot(x,u(:,ii)'); - xlim([0 L]) - ylim([0 1.5]) - pause(0.02); -end - -space=linspace(0,L,101); -time=linspace(0,T,201); -[xx,yy]=meshgrid(time,space); -%exsol=uex(yy,xx); -figure(2) -mesh(t,x,u) -%figure(2) -%mesh(xx,yy,exsol) diff --git a/Exercise_03/NSSC_3.m b/Exercise_03/NSSC_3.m deleted file mode 100644 index c808100..0000000 --- a/Exercise_03/NSSC_3.m +++ /dev/null @@ -1,43 +0,0 @@ -%% exercise number 2 -%problem characteristics -U=0.7;%convection velocity -delta_x=0.01; %space discretization -L=1; %max length of our domain -T=1; %max time considered - -N=L/delta_x; %number of intervals in space -K=100; %number of intervals in time - -%two initial conditions -square_pulse=@(x) heaviside(x-0.1) - heaviside(x- 0.3); -gauss_signal=@(x) exp(-10*(4*x - 1).^2); - -[x,t,c] = UW_scheme(L,N,T,K,U,square_pulse); -ex_sol=@(x,t) square_pulse(x-U*t); -f1=figure(1); -for ii=1:K+1 - clf(f1) - hold on - plot(x,c(:,ii)','-bo'); - plot(x,ex_sol(x,t(ii))); - hold off - legend("aproximated solution","exact solution") - xlim([0 L]) - ylim([0 1.1]) - pause(0.02); -end - -[x,t,c] = UW_scheme(L,N,T,K,U,gauss_signal); -ex_sol=@(x,t) gauss_signal(x-U*t); -f2=figure(2); -for ii=1:K+1 - clf(f2) - hold on - plot(x,c(:,ii)','-bo'); - plot(x,ex_sol(x,t(ii))); - legend("aproximated solution","exact solution") - xlim([0 L]) - ylim([0 1.1]) - pause(0.02); -end - diff --git a/Exercise_03/UW_scheme.m b/Exercise_03/UW_scheme.m deleted file mode 100644 index 387dadc..0000000 --- a/Exercise_03/UW_scheme.m +++ /dev/null @@ -1,51 +0,0 @@ -function [x,t,c] = UW_scheme(xf,N,T,K,U,c0) -% ---- Numerical solution of the linear advection equation in a periodic domain ---- -% c_t+ U * c_x = 0 with domain [0,xf] -% given the initial condition c0. -% ----------------------------------------------- -% Sintax: -% [x,t,c] = UW_scheme(xf,N,T,K,U,c0) -% -% Input: -% xf end of our domain -% N number of space intervals -% T max time -% K number of time intervals -% U convection velocity -% c0 initial condition -% -% Output: -% x vector of spatial nodes -% t vector of time nodes -% c numerical solution - -% Space and time intervals size -dx=xf/N; -dt=T/K; -% initialization of x and t vectors (nodes) -x=linspace(0,xf,N+1)'; -t=linspace(0,T,K+1)'; - -% Solution matrix -c=zeros(N+1,K+1); - -% Initial conditions -c(:,1) = c0(x); - - -% Creating our matrix -e = ones(N+1,1); -B = spdiags([-e,e],[-1,0],N+1,N+1); -I = speye(N+1); - -%"printing" courant number and numerical viscosity -C0=(U*dt/dx) -numerical_viscosity= U*dx*(1-C0)/2 - -%final metrix to compute the solution -A = I - C0*B; - -%finding the solution -for k=1:K - c(1:end,k+1) = A*c(1:end,k); -end \ No newline at end of file diff --git a/Exercise_03/calore_CN.m b/Exercise_03/calore_CN.m deleted file mode 100644 index 2cb2331..0000000 --- a/Exercise_03/calore_CN.m +++ /dev/null @@ -1,60 +0,0 @@ -function [x,t,u] = calore_CN(L,N,T,K,c1,c2,f,u0) -% ---- Risoluzione dell'equazione del calore ---- -% u_t - u_xx = f nell'intervallo [-L,L] -% con condizioni al bordo di Dirichlet -% e condizioni iniziali. -% ----------------------------------------------- -% Sintassi: -% [x,t,u]=calore_template(L,N,T,K,c1,c2,fun,u0) -% -% Input: -% L semiampiezza intervallo spaziale (-L,L) -% N numero di sottointervalli in (-L,L) -% T estremo finale intervallo temporale (0,T) -% K numero di sottointervalli in (0,T) -% c1 funzione che descrive la condizione di Dirichlet in x=-L -% c2 funzione che descrive la condizione di Dirichlet in x=L -% f funzione che descrive il termine noto dell'equazione -% u0 funzione che descrive la condizione iniziale in t=0 -% -% Output: -% x vettore dei nodi spaziali -% t vettore dei nodi temporali -% u soluzione numerica -% del problema - -% Calcolo passo di discretizzazione in spazio e tempo -h=2*L/N; -tau=T/K; -% Inizializzazione del vettore t -t=linspace(0,T,K+1)'; -% Inizializzazione del vettore x -x=linspace(-L,L,N+1); - -% Inizializzazione della matrice soluzione u -u=zeros(N+1,K+1); -% Condizione iniziale -u(:,1)=u0(x); - -% Condizioni al bordo -u(1,:)=c1(t); -u(end,:)=c2(t); - -% Costruzione della matrice A -e=ones(N-1,1); -A=spdiags([-e,2*e,-e],[-1,0,1],N-1,N-1)/(h^2); -I=speye(N-1,N-1); - -% Ciclo iterativo -for k=1:K - % Assemblaggio termine noto - F1=f(x(2:end-1),t(k)); - F2=f(x(2:end-1),t(k+1)) - % Correzione del termine noto con le condizioni al bordo - F1(1)=F1(1) + c1(t(k))/(h^2); - F1(end)=F1(end) + c2(t(k))/(h^2); - F2(1)=F2(1) + c1(t(k+1))/(h^2); - F2(end)=F2(end) + c2(t(k+1))/(h^2); - % Risoluzione del problema - u(2:end-1,k+1) = ((I + 0.5*tau*A)\((I - 0.5*tau*A)*u(2:end-1,k)))' + 0.5*tau*F1 + 0.5*tau*F2; -end diff --git a/Exercise_03/image.png b/Exercise_03/plots/image.png similarity index 100% rename from Exercise_03/image.png rename to Exercise_03/plots/image.png diff --git a/Exercise_03/plots/task01_1_00023.png b/Exercise_03/plots/task01_1_00023.png new file mode 100644 index 0000000..4afbbf3 --- /dev/null +++ b/Exercise_03/plots/task01_1_00023.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2f3a387e39af2aeb46d9cf79f5bfbcfb127b4881d2f2a100ec4ba8fa65fdbe41 +size 26525 diff --git a/Exercise_03/plots/task01_1_00199.png b/Exercise_03/plots/task01_1_00199.png new file mode 100644 index 0000000..24d543d --- /dev/null +++ b/Exercise_03/plots/task01_1_00199.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95552139098616710bcd8538058cd1b8b150593179a3712e703cb755193f0ef0 +size 27939 diff --git a/Exercise_03/plots/task01_1_Cinf.png b/Exercise_03/plots/task01_1_Cinf.png new file mode 100644 index 0000000..e06d74c --- /dev/null +++ b/Exercise_03/plots/task01_1_Cinf.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2fc4f7ced16f9882cd9fdc60cba4edc61d664a20701f8f09e8fc2f2ff13f047f +size 16938 diff --git a/Exercise_03/plots/task01_2_00023.png b/Exercise_03/plots/task01_2_00023.png new file mode 100644 index 0000000..99ef5e4 --- /dev/null +++ b/Exercise_03/plots/task01_2_00023.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9e444987276bbdb52474d861a4e99dba7b8eeb44858169287aac3d5b2214f6a4 +size 26762 diff --git a/Exercise_03/plots/task01_2_00199.png b/Exercise_03/plots/task01_2_00199.png new file mode 100644 index 0000000..dd0c744 --- /dev/null +++ b/Exercise_03/plots/task01_2_00199.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:04c6e7b76df32edcece0e78b82223a4435b1b59bb606d67438d41e823da04625 +size 29894 diff --git a/Exercise_03/plots/task01_2_Cinf.png b/Exercise_03/plots/task01_2_Cinf.png new file mode 100644 index 0000000..3a83102 --- /dev/null +++ b/Exercise_03/plots/task01_2_Cinf.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c1d7d93d1fab88ffcc5f0de0d7ef5bb04d7aa847f56c7a01c4aac8c50ec0ba1 +size 29518 diff --git a/Exercise_03/plots/task01_3_00023.png b/Exercise_03/plots/task01_3_00023.png new file mode 100644 index 0000000..149390e --- /dev/null +++ b/Exercise_03/plots/task01_3_00023.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5fe9ec2fd444347e9b1b043ab04160a4343729c08d88e9d54ae0bd4fda69b8c0 +size 26892 diff --git a/Exercise_03/plots/task01_3_00199.png b/Exercise_03/plots/task01_3_00199.png new file mode 100644 index 0000000..5198eb7 --- /dev/null +++ b/Exercise_03/plots/task01_3_00199.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:43bcdc98149a02afb8eb73c07cf8e262de67358b120f38c1b6aceab0a2fcfcb1 +size 28203 diff --git a/Exercise_03/plots/task01_4_00023.png b/Exercise_03/plots/task01_4_00023.png new file mode 100644 index 0000000..6adcf38 --- /dev/null +++ b/Exercise_03/plots/task01_4_00023.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:90edbaf68969c5f5b3aaf61fc8c6bb8be0023092739c3da46a8fd4304ef891f7 +size 26769 diff --git a/Exercise_03/plots/task01_4_00199.png b/Exercise_03/plots/task01_4_00199.png new file mode 100644 index 0000000..50e7993 --- /dev/null +++ b/Exercise_03/plots/task01_4_00199.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:18f7cddbe8f62a575090da662af1a90d1e9792899fcd7ae2b0e7d28e26390b3d +size 28147 diff --git a/Exercise_03/plots/task01_all.png b/Exercise_03/plots/task01_all.png new file mode 100644 index 0000000..53189cb --- /dev/null +++ b/Exercise_03/plots/task01_all.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:160da35a25762545c991ec9f8bbf5e7710b6904a846d83256207faeffba400a0 +size 36056 diff --git a/Exercise_03/plots/task01_x_00023.png b/Exercise_03/plots/task01_x_00023.png new file mode 100644 index 0000000..11fae4a --- /dev/null +++ b/Exercise_03/plots/task01_x_00023.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fb71088e226e27b278dc3df2bb757990f5d75e41cb6f2f3bfd59ab1751a01610 +size 30363 diff --git a/Exercise_03/plots/task01_x_00199.png b/Exercise_03/plots/task01_x_00199.png new file mode 100644 index 0000000..05c6fab --- /dev/null +++ b/Exercise_03/plots/task01_x_00199.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cab0214ac3feaaf46f03e930f1b16a91f25ad4b3c2ce9e400cf61c94c89baabf +size 17909 diff --git a/Exercise_03/plots/task02_gauss_C0_0-7_00150.png b/Exercise_03/plots/task02_gauss_C0_0-7_00150.png new file mode 100644 index 0000000..73ede51 --- /dev/null +++ b/Exercise_03/plots/task02_gauss_C0_0-7_00150.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:615cfa95a32749e03816c512d31414364a357dbaa2ba7cedb21794598c1419f7 +size 31158 diff --git a/Exercise_03/plots/task02_gauss_C0_1-1_00150.png b/Exercise_03/plots/task02_gauss_C0_1-1_00150.png new file mode 100644 index 0000000..dbf51be --- /dev/null +++ b/Exercise_03/plots/task02_gauss_C0_1-1_00150.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1103b34c8bfbecd65aef5c8734863ccfd2ea9137e94bea8e054e2ebccd11020f +size 23542 diff --git a/Exercise_03/plots/task02_gauss_C0_1_00150.png b/Exercise_03/plots/task02_gauss_C0_1_00150.png new file mode 100644 index 0000000..01fcc92 --- /dev/null +++ b/Exercise_03/plots/task02_gauss_C0_1_00150.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:171b8ca2eea16fd27d29c900435ee2aa263a64c6693bbb156f58d479de20db1b +size 31883 diff --git a/Exercise_03/plots/task02_square_C0_0-7_00150.png b/Exercise_03/plots/task02_square_C0_0-7_00150.png new file mode 100644 index 0000000..724d7e5 --- /dev/null +++ b/Exercise_03/plots/task02_square_C0_0-7_00150.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8081b4f8783e620fd49a32be3699d6d4bec4f4e1a261fafc1def35c352688d41 +size 28835 diff --git a/Exercise_03/plots/task02_square_C0_1-1_00150.png b/Exercise_03/plots/task02_square_C0_1-1_00150.png new file mode 100644 index 0000000..0f2fe98 --- /dev/null +++ b/Exercise_03/plots/task02_square_C0_1-1_00150.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:aac17de0c8cc3a27b7c2c119ab1e0d46c64da23c21b9b63e9466f3099bea488c +size 23647 diff --git a/Exercise_03/plots/task02_square_C0_1_00150.png b/Exercise_03/plots/task02_square_C0_1_00150.png new file mode 100644 index 0000000..73bc6d7 --- /dev/null +++ b/Exercise_03/plots/task02_square_C0_1_00150.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:62c2f1bca9416740991af98b0988965a33cd8e15b525f5473f7eae0eff2dc780 +size 23572 diff --git a/Exercise_03/report.tex b/Exercise_03/report.tex index fb40d13..c45ce24 100644 --- a/Exercise_03/report.tex +++ b/Exercise_03/report.tex @@ -12,7 +12,7 @@ % Document meta into \title{NSSC 2 - Assignement 3} \author{Bianchi Riccardo, Kapla Daniel, Kuen Jakob, Müller David} -\date{November 24, 2021} +\date{May 17, 2022} % Set PDF title, author and creator. \AtBeginDocument{ \hypersetup{ @@ -88,7 +88,7 @@ We are given the 1D unsteady diffusion equation \end{equation} with a scalar diffusion coefficient $D = 10^{-6}$. The domain size is $h$ which is discretized with $N_x$ points to give the grid space $\Delta x$ with a time step $\Delta t$. The initial condition is $C = 0$ inside the domain. -Furthermore, denote with $N_t\in\mathbb{N}$ the number of time steps of the simulation where $t_0 = 0$ is the initial time. All $N_t$ discretized time points $t_n = n \Delta t$ leading to the final time point of the simulation as $t_{N_t} = N_t \Delta t$. The discretized $x$ points of the domain are $x_i = (i - 1)\Delta x = (i - 1)h / (N_x - 1)$ for $i = 1, ..., N_x$. This gives exactly $N_x$ grid points with equal distance between adjacent points on the domain $[0, h]$ with the first point $x_1 = 0$ and the last point $x_{N_x} = h$. +Furthermore, denote with $N_t\in\mathbb{N}$ are the number of time steps of the simulation where $t_0 = 0$ is the initial time. All $N_t$ discretized time points $t_n = n \Delta t$ leading to the final time point of the simulation as $t_{N_t} = N_t \Delta t$. The discretized $x$ points of the domain are $x_i = (i - 1)\Delta x = (i - 1)h / (N_x - 1)$ for $i = 1, ..., N_x$. This gives exactly $N_x$ grid points with equal distance between adjacent points on the domain $[0, h]$ with the first point $x_1 = 0$ and the last point $x_{N_x} = h$. In the following we will also use the short hand notation \begin{displaymath} @@ -104,7 +104,7 @@ Furthermore, define \end{displaymath} \subsection{Explicit scheme with Dirichlet/Neumann BC}\label{sec:task01_1} -Given the Dirichlet boundary conditions $C(0, t) = 0$ and the Neumann BC $\partial_x C(h, t) = 0$. First we derive a $2^{nd}$ order \emph{explicit} finite difference approach with a $1^{st}$ order discretization in time (see Figure~\ref{fig:ex1}). +Given the Dirichlet boundary conditions $C(0, t) = 0$ and the Neumann boundary conditions $\partial_x C(h, t) = 0$. First we derive a $2^{nd}$ order \emph{explicit} finite difference approach with a $1^{st}$ order discretization in time (see Figure~\ref{fig:ex1}). \begin{figure}[h!] \centering @@ -161,7 +161,7 @@ To derive a second order scheme (assuming $C$ is three time continuously differe \begin{displaymath} C(x + \Delta x, t) = C(x, t) + \partial_x C(x, t)\Delta x + \partial_x^2 C(x, t)\frac{\Delta x^2}{2} + \partial_x^3 C(x, t)\frac{\Delta x^3}{6} + \mathcal{O}(\Delta x^4). \end{displaymath} -Replace $\Delta x$ with $\pm\Delta x$ and add the two equation together, then +Replace $\Delta x$ with $\pm\Delta x$ and add the two equation together which gives \begin{displaymath} C(x + \Delta x, t) + C(x - \Delta x, t) = 2 C(x, t) + \partial_x^2 C(x, t)\Delta x^2 + \mathcal{O}(\Delta x^4). \end{displaymath} @@ -171,7 +171,7 @@ The first and third order terms drop out due to different signs. Finally, this r \end{displaymath} which is an approximation of the second derivative with error proportional to $\Delta x^2$. For the first order approximation in time the same trick can be used except that only the first two terms of the Taylor expantion need to be considured. -Therefore, the $2^{nd}$ order scheme for space and $1^{st}$ order in time at $(i, n)$ using the explicit scheme derives as +Therefore, the $2^{nd}$ order scheme for space and $1^{st}$ order in time at $(i, n)$ using the explicit scheme derive as \begin{displaymath} \partial_x^2 \widehat{C}_i^n = \frac{\widehat{C}_{i-1}^{n} - 2\widehat{C}_{i}^{n} + \widehat{C}_{i+1}^{n}}{\Delta x^2}, \qquad @@ -181,7 +181,7 @@ Substitution into \eqref{eq:ex1} yields after rearranging the update rule for in \begin{equation}\label{eq:task01_1_update} \widehat{C}_i^{n+1} = \widehat{C}_i^n + \frac{D\Delta t}{\Delta x^2}(\widehat{C}_{i-1}^{n} - 2\widehat{C}_{i}^{n} + \widehat{C}_{i+1}^{n}). \end{equation} -This holds at $x_i$ where $i = 2, ..., N_x - 1$, or in other words everywhere inside the space domain excluding the boundary. The boundary needs to be handled seperately. The left boundary condition is a Dirichlet constraint which is simply constanct giving $C_1^n = 1$ for all time while the Neumann condition on the right requires an additional discretization step for computing the next value. To achieve a $2^{nd}$ order discretization scheme it's usualy required to take the sum/difference of an Taylor expantion into the left and right direction at a given point. As we are on the boundary there is no point at the right, which can be simply solved by adding a ghost point $x_{N_x+1}$ to the system (which will not show up in the final scheme). This leads to the two $3^{rd}$ order expantions evaluated at the right boundary as +This holds at $x_i$ where $i = 2, ..., N_x - 1$, or in other words, everywhere inside the space domain except the boundary. The boundary needs to be handled seperately. The left boundary condition is a Dirichlet constraint which is simply a constant giving $C_1^n = 1$ for all time while the Neumann condition on the right requires an additional discretization step for computing the next value. To achieve a $2^{nd}$ order discretization scheme it is usualy required to take the sum/difference of an Taylor expantion to the left and right direction at a given point.However, on the boundary there is no point at the right, which can be simply solved by adding a ghost point $x_{N_x+1}$ to the system (which will not show up in the final scheme). This leads to the two $3^{rd}$ order expantions evaluated at the right boundary as \begin{align*} C_{N_x-1}^n &= C_{N_x}^n - \partial_x C_{N_x}^n\Delta x + \partial_x^2 C_{N_x}^n + \mathcal{O}(\Delta x^3), \\ C_{N_x+1}^n &= C_{N_x}^n + \partial_x C_{N_x}^n\Delta x + \partial_x^2 C_{N_x}^n + \mathcal{O}(\Delta x^3). @@ -194,7 +194,7 @@ which yields a $2^{nd}$ order equation for the Neumann BC on the right as \begin{displaymath} C_{N_x-1}^n = C_{N_x+1}^n. \end{displaymath} -Now where ready to give an equation system of the entire system (including the boundaryies) which reads +This results in an system of equations containing the entire system (including the boundaryies) which reads \begin{align*} \widehat{C}_1^{n+1} &= 1, \\ \widehat{C}_i^{n+1} &= d\widehat{C}_{i-1}^{n} + (1 - 2d)\widehat{C}_{i}^{n} + d\widehat{C}_{i+1}^{n}, @@ -218,10 +218,19 @@ for a tridiagonal matrix $A_1$ of dimensions $N_x\times N_x$ \end{pmatrix}. \end{displaymath} -\subsubsection{Stability} \todo{Prove that the update scheme is unstable for $d = \frac{D\Delta x^2}{\Delta t} > 0.5$} +\begin{figure}[!h] + \centering + \includegraphics[width=0.48\textwidth]{task01_1_00023.png} + \includegraphics[width=0.48\textwidth]{task01_x_00023.png} + \includegraphics[width=0.48\textwidth]{task01_1_00199.png} + \includegraphics[width=0.48\textwidth]{task01_x_00199.png} + \caption{\label{fig:task01_stable}Comparison for stable (left, $d = 0.48 \leq 0.5$) vs. unstable (right, $d = 0.55 > 0.5$). At the top the simulation snapshot after 120 time steps and at the bottom after 1000 timesteps.} +\end{figure} + + \subsection{Explicit scheme with Dirichlet BC at both boundaries}\label{sec:task01_2} -This is identical to the previous task except the right boundary condition. The new boundary condition is a Dirichlet BC with $C_{N_x}^n = 0$ which alters the equation system from Section~\ref{sec:task01_1} in the last two equations to +In this task two Dirichlet boundary conditions are given. The new boundary condition is a Dirichlet BC with $C_{N_x}^n = 0$ which alters the equation system from Section~\ref{sec:task01_1} in the last two equations to \begin{align*} \widehat{C}_1^{n+1} &= 1, \\ \widehat{C}_i^{n+1} &= d\widehat{C}_{i-1}^{n} + (1 - 2d)\widehat{C}_{i}^{n} + d\widehat{C}_{i+1}^{n}, @@ -229,7 +238,7 @@ This is identical to the previous task except the right boundary condition. The \widehat{C}_{N_x-1}^{n+1} &= d\widehat{C}_{N_x-2}^{n} + (1 - 2d)\widehat{C}_{N_x-1}^{n}, \\ \widehat{C}_{N_x}^{n+1} &= 0. \end{align*} -which yields a new tridiagonal matrix $A_2$ of size $N_x\times N_x$ for the update rule $C^{n+1} = A_2 C^{n}$ as +which yields to a new tridiagonal matrix $A_2$ of size $N_x\times N_x$ for the update rule $C^{n+1} = A_2 C^{n}$ as \begin{displaymath} A_2 = \begin{pmatrix} 1 & 0 \\ @@ -242,10 +251,17 @@ which yields a new tridiagonal matrix $A_2$ of size $N_x\times N_x$ for the upda \end{pmatrix}. \end{displaymath} -\todo{include pictures and compare with Section~\ref{sec:task01_1}} +See Figure~\ref{fig:task01_inf} for $\lim_{t\to\infty}C(x, t)$ simulation (many timesteps) for subtask 1 and 2. In comparison both lead to a straight line solution (last energy) such that the Dirichlet or Neumann BC are fullfilled. + +\begin{figure}[!h] + \centering + \includegraphics[width=0.48\textwidth]{task01_1_Cinf.png} + \includegraphics[width=0.48\textwidth]{task01_2_Cinf.png} + \caption{\label{fig:task01_inf}Solution from Section~\ref{sec:task01_1} (left) and Section~\ref{sec:task01_2} (right) for $t\to\infty$ simulated by setting number of time steps to $N_t = 20000$.} +\end{figure} \subsection{Implicit scheme with Dirichlet/Neumann BC}\label{sec:task01_3} -The following computations are similar in nature to the explicit scheme, therefore well keep it short. The implicit discretization for the derivatives is (see: Figure~\ref{fig:ex1}) then +The following computations are similar in nature to the explicit scheme. The implicit discretization for the derivatives are (see: Figure~\ref{fig:ex1}) \begin{displaymath} \partial_x^2 \widehat{C}_{i}^{n+1} = \frac{\widehat{C}_{i-1}^{n+1} - 2\widehat{C}_{i}^{n+1} + \widehat{C}_{i+1}^{n+1}}{\Delta x^2}, \qquad @@ -275,9 +291,13 @@ where the $N_x\times N_x$ tridiagonal matrix $A_3$ has the form \end{displaymath} and the update is performed by solving for $C^{n+1}$. -\todo{include pictures and compare with Section~\ref{sec:task01_1}} +\begin{figure}[!h] + \centering + \includegraphics[width = 0.8\textwidth]{task01_all.png} + \caption{\label{fig:task01_all}Comparison of all four subtasks. As expected 1.1, 1.3 and 1.4 solve the same probelm and as such have (basically) identical solution while the subtask 1.2 solves for different BC (Dirichlet) which is fullfilled.} +\end{figure} -\subsection{Second order in time for implicit scheme with Dirichlet/Neumann BC} +\subsection{Second order in time for implicit scheme with Dirichlet/Neumann BC}\label{sec:task01_4} \begin{figure}[h!] \centering \begin{tikzpicture}[>=latex] @@ -302,12 +322,12 @@ and the update is performed by solving for $C^{n+1}$. minimum size = 4pt] at (\x, \y) {}; } \end{tikzpicture} - \caption{\label{fig:ex4}.Crank-Nicolson dependency relations.} + \caption{\label{fig:ex4}Crank-Nicolson dependency relations.} \end{figure} -To derive the second order accurate scheme in time we employ the Crank-Nicolson approach to derive the descritization at the time midpoints $t_{n+1/2} = (n + 1/2)\Delta t$ which we index with $n+1/2$. +To derive the second order accurate scheme in time one uses the Crank-Nicolson approach to derive the descritization at the time midpoints $t_{n+1/2} = (n + 1/2)\Delta t$ which are indexed with $n+1/2$. -By expantion into $\pm\Delta t / 2$ at the midpoints we get +By expantion into $\pm\Delta t / 2$ at the midpoints one get \begin{align*} C_i^n &= C_i^{n+1/2} - \partial_tC_i^{n+1/2}\frac{\Delta t}{2} + \partial_t^2 C_i^{n+1/2}\frac{\Delta t^2}{8} + \mathcal{O}(\Delta t^3), \\ C_i^{n+1} &= C_i^{n+1/2} + \partial_tC_i^{n+1/2}\frac{\Delta t}{2} + \partial_t^2 C_i^{n+1/2}\frac{\Delta t^2}{8} + \mathcal{O}(\Delta t^3). @@ -325,12 +345,12 @@ leading to an second order in time and space discretization scheme \partial_t \widehat{C}_{i}^{n+1/2} - D \partial_x^2 \widehat{C}_{i}^{n+1/2} = \mathcal{O}(\Delta x^2 + \Delta t^2). \end{displaymath} -Next we need to ensure the evaluation to be done at the known grid points instead of the unknown time midpoints. Therefore, we replace the evaluation at the time midpoints by there in time mean of the two direct neighbouring grid points +Next one need to ensure the evaluation to be done at the known grid points instead of the unknown time midpoints. Therefore, replacing the evaluation at the time midpoints by the time mean of the two direct neighbouring grid points \begin{displaymath} \widehat{C}_i^{n+1/2} = \frac{\widehat{C}_i^{n} + \widehat{C}_i^{n+1}}{2}. \end{displaymath} -After a bit of algebra and condideration of the Dirichlet and Neumann BC we end up with +After a bit of algebra and consideration of the Dirichlet and Neumann BC one end up with \begin{align*} \widehat{C}_1^{n+1} &= \widehat{C}_1^{n} = 1, \\ \widehat{C}_i^{n+1} - \frac{d}{2}\widehat{C}_{i-1}^{n+1} + dC_{i}^{n+1} - \frac{d}{2}\widehat{C}_{i+1}^{n+1} @@ -339,7 +359,7 @@ After a bit of algebra and condideration of the Dirichlet and Neumann BC we end \widehat{C}_i^{n+1} - d\widehat{C}_{N_x-1}^{n+1} + dC_{N_x}^{n+1} &= C_i^{n} + d\widehat{C}_{N_x-1}^{n} - dC_{N_x}^{n}. \end{align*} -To write this again in a compact matrix equation system we define the $N_x\times N_x$ matrix $A_4$ as +To write this again in a compact matrix equation system one defines the $N_x\times N_x$ matrix $A_4$ as \begin{displaymath} A_4 = \begin{pmatrix} 0 & 0 \\ @@ -356,4 +376,79 @@ then the entire system has the form \end{displaymath} where $I$ is the identity. Again, the update is performed by solving this tridiagonal system for $C^{n+1}$. +For comparison against the other methods see Figure~\ref{fig:task01_all}. + +\subsection{Notes on Implementation} +All four tasks follow the same basic sructure which can be written as a generalized linear system of the form +\begin{displaymath} + L C^{n+1} = R C^n +\end{displaymath} +for updating the solution by one time step. The two matrices are dependent on the used scheme and the boundary conditions, see Table~\ref{tab:ex1}. + +\begin{table}[h!] + \centering + \begin{tabular}{l | c c} + Task & $L$ & $R$ \\ \hline + 1.1 & $I$ & $A_1$ \\ + 1.2 & $I$ & $A_2$ \\ + 1.3 & $A_3$ & $I$ \\ + 1.4 & $I + A_4$ & $I - A_4$ \\ + \end{tabular} + \caption{\label{tab:ex1}Left and right hand side matrices of the general update rule $L C^{n+1} = R C^n$ with $A_i$ depending on the subtask as defined in Section~\ref{sec:task01_1} till \ref{sec:task01_4} and $I$ the identity matrix.} +\end{table} + +As a boild down solver the following is sufficient to compute the solution given an initial solution $C_0$ (argument \texttt{C}) with the appropriately defined matrices $L, R$ (arguments \texttt{L, R}) which incorporate the scheme, space and time step size $\Delta x, \Delta t$ as well as the dispersion parameter $D$ and the boundary conditions) at time $T = N_t \Delta$ (implicitly defined through the parameter \texttt{nx}). +\begin{python} +def solve(C, L, R, nt): + 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) + return C +\end{python} +This code assumes \texttt{C} to be a 1D \texttt{numpy} array as well as $L, R$ to by \texttt{scipy.sparse.spmatrix} sparse tridiagonal matrices or \texttt{None} which is equivalent to the identity matrix. + +The additional code in the script \texttt{task01.py} contains setting up the needed matrices and plotting. + +\newpage +\section{Numerical solution of the linear advection equation in a periodic domain} +First a few words about the upwind scheme. With a positive $U$ the upwind means that it is discretized by ``going left'', meaning into the opposite direction of the current position. In a similar faschion as above this leads to the discretization +\begin{align*} + \partial_x C_i^{n} &= \frac{C_i^n - C_{i-1}^n}{\Delta x} + \mathcal{O}(\Delta x), \\ + \partial_t C_i^{n+1} &= \frac{C_i^{n+1} - C_i^n}{\Delta t} + \mathcal{O}(\Delta t). +\end{align*} +One ends up with a first order discretized equation +\begin{displaymath} + 0 = \frac{\widehat{C}_i^{n+1} - \widehat{C}_i^n}{\Delta t} + U \frac{\widehat{C}_i^n - \widehat{C}_{i-1}^n}{\Delta x} +\end{displaymath} +leading to the update rule +\begin{align*} + C_i^{n+1} &= (1 - C_0)C_i^n + C_oC_{i-1}^n, && i = 2, ..., N_x +\end{align*} +with the current $C_0 = \frac{U \Delta x}{\Delta t}$. The boundary condition enforces periodizity which means $C_1^n = C_{N_x}^n$ and therefore the update for the left most point is +\begin{displaymath} + C_1^{n+1} = (1 - C_0)C_1^n + C_oC_{N_x}^n. +\end{displaymath} + +\begin{figure}[!h] + \centering + \includegraphics[width = 0.3\textwidth]{task02_gauss_C0_0-7_00150.png} + \includegraphics[width = 0.3\textwidth]{task02_gauss_C0_1_00150.png} + \includegraphics[width = 0.3\textwidth]{task02_gauss_C0_1-1_00150.png} + \includegraphics[width = 0.3\textwidth]{task02_square_C0_0-7_00150.png} + \includegraphics[width = 0.3\textwidth]{task02_square_C0_1_00150.png} + \includegraphics[width = 0.3\textwidth]{task02_square_C0_1-1_00150.png} + \caption{\label{fig:task02_all}For initial Gauss wavelet (top) and Square wavelet (bottom) after 150 iterations (one leap around the boundary) with different current $C_0$. Left: $C_0 = 0.7$, Center: $C_0 = 1$ (perfect) and Right: $C_0 = 1.1$ (unstable).} +\end{figure} + +For implementation one gets a very simple solver which computes the wave form at time $T = N_t \Delta t$ with $\Delta t = U \Delta x / C_0$ as the following; +\begin{python} +def solve(C, C0, nt): + nx = C.shape[0] + im1 = np.array([nx - 1] + list(range(nx - 1))) + for t in range(nt): + C = (1 - C0) * C + C0 * C[im1] + return C +\end{python} +where \texttt{C} is the initial wave form, the constant \texttt{C0} is the current $C_0$ and \texttt{nt} is the number of time steps to be performed. Again, the attached script \texttt{task02.py} implements this with additional code for setting up the initial conditions and plotting. + \end{document} diff --git a/Exercise_03/task01.py b/Exercise_03/task01.py new file mode 100644 index 0000000..ca59fff --- /dev/null +++ b/Exercise_03/task01.py @@ -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") diff --git a/Exercise_03/task01_1-2.py b/Exercise_03/task01_1-2.py deleted file mode 100644 index c6ad816..0000000 --- a/Exercise_03/task01_1-2.py +++ /dev/null @@ -1,63 +0,0 @@ -# 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 diff --git a/Exercise_03/task01_3.py b/Exercise_03/task01_3.py deleted file mode 100644 index 021624d..0000000 --- a/Exercise_03/task01_3.py +++ /dev/null @@ -1,50 +0,0 @@ -# Task 1.3 -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 - -# Setup implicit scheme equation matrix -T = (1 + 2 * d) * np.eye(nx) - d * np.eye(nx, k = 1) - d * np.eye(nx, k = -1) -# fix boundary condition equations -T[0, 0] = 1 # Left Dirichlet BC -T[0, 1] = 0 -T[-1, -2] = 1 # Right Neumann BC -T[-1, -1] = 0 - -# Set initial solution -C = np.zeros(nx) -C[0] = 1 -C[-1] = C[-2] # (0 = 0) - -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/task01_3_{i:0>5}.png") - i += 1 - # update solution using the implicit schema - C = np.linalg.solve(T, C) - # fix BC conditions (theoretically, they are set by the update but for - # stability reasons (numerical) we enforce the correct values) - C[0] = 1 - C[-1] = C[-2] - -# to convert generated image sequence to video use: -# $> ffmpeg -r 60 -i plots/task01_3_%05d.png -pix_fmt yuv420p video_1_3.mp4 diff --git a/Exercise_03/task01_4.py b/Exercise_03/task01_4.py deleted file mode 100644 index 68927b5..0000000 --- a/Exercise_03/task01_4.py +++ /dev/null @@ -1,74 +0,0 @@ -# Task 1.4 -import numpy as np -import scipy, scipy.sparse, scipy.linalg -from matplotlib import pyplot as plt - -# plotting helper function -def plot(C, x, t, name): - plt.clf() - plt.plot(x, C) - plt.xlim([0, x[-1]]) - plt.ylim([0, 1.2]) - plt.title(f"{name} - time: {t: >12.0f}") - plt.savefig(f"plots/{name}_{plot.fignr:0>5}.png") - plot.fignr += 1 - -# set static variable as function attribute -plot.fignr = 1 -# and initialize a figure -plt.figure(figsize = (8, 6), dpi = 100) - -# Config -D = 1e-6 # diffusion coefficient -h = 1 # space domain (max x size) -T = 1e5 # solution end time -nx = 50 # nr of space discretization points -nt = 2000 # nr of time 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 - -# setup matrices for implicit update scheme `A C^n+1 = (2 I - A) C^n = B C^n` -# The matrix `A` is represented as a `3 x (nx - 1)` matrix as expected by -# `scipy.linalg.solve_banded` representing the 3 diagonals of the tridiagonal -# matrix `A`. -A = np.zeros((3, nx - 1)) -# upper minor diagonal -A[0, 2:] = -d -# main diagonal -A[1, 0] = 1 -A[1, 1:] = 1 + 2 * d -# and lower minor diagonal -A[2, :-2] = -d -A[2, -2] = -2 * d -# The right hand side matrix `B = 2 I - A` which is represented as a sparse -# matrix in diag. layout which allows for fast matrix vector multiplication -B = -A -B[1, ] += 2 -B = scipy.sparse.spdiags(B, (1, 0, -1), B.shape[1], B.shape[1]) - -# set descritized space evaluation points `x` of `C` -x = np.linspace(0, h, nx) - -# Set initial solution -C = np.zeros(nx) -C[0] = 1 -C[-1] = C[-3] # (0 = 0) - -for n in range(nt): - # generate roughly 400 plots - if n % (nt // 400) == 0: - plot(C, x, n * dt, "task01_4") - # update solution using the implicit schema - C[:-1] = scipy.linalg.solve_banded((1, 1), A, B @ C[:-1]) - # set/enforce boundary conditions - C[0] = 1 # left Dirichlet (theoretically not needed) - C[-1] = C[-3] # right Neumann condition - -# plot final state -plot(C, x, T, "task01_4") - -# to convert generated image sequence to video use: -# $> ffmpeg -r 60 -i plots/task01_4_%05d.png -pix_fmt yuv420p video_1_4.mp4 diff --git a/Exercise_03/task02.py b/Exercise_03/task02.py new file mode 100644 index 0000000..aa7cf94 --- /dev/null +++ b/Exercise_03/task02.py @@ -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 diff --git a/Exercise_03/video_1_1.mp4 b/Exercise_03/video_1_1.mp4 deleted file mode 100644 index 26f1aee..0000000 Binary files a/Exercise_03/video_1_1.mp4 and /dev/null differ diff --git a/Exercise_03/video_1_2.mp4 b/Exercise_03/video_1_2.mp4 deleted file mode 100644 index b4c9146..0000000 Binary files a/Exercise_03/video_1_2.mp4 and /dev/null differ diff --git a/Exercise_03/video_1_3.mp4 b/Exercise_03/video_1_3.mp4 deleted file mode 100644 index b51f590..0000000 Binary files a/Exercise_03/video_1_3.mp4 and /dev/null differ diff --git a/Exercise_03/video_1_4.mp4 b/Exercise_03/video_1_4.mp4 deleted file mode 100644 index ab99238..0000000 Binary files a/Exercise_03/video_1_4.mp4 and /dev/null differ diff --git a/Exercise_03/videos/task02_gauss_C0_0.7.mp4 b/Exercise_03/videos/task02_gauss_C0_0.7.mp4 new file mode 100644 index 0000000..275281b --- /dev/null +++ b/Exercise_03/videos/task02_gauss_C0_0.7.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d89c9fde27a566b7eb7e2e2afba730859ef53861f4a0a96f0dc0fe65f4bed2b1 +size 133197 diff --git a/Exercise_03/videos/task02_gauss_C0_1.1.mp4 b/Exercise_03/videos/task02_gauss_C0_1.1.mp4 new file mode 100644 index 0000000..9213781 --- /dev/null +++ b/Exercise_03/videos/task02_gauss_C0_1.1.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f87227669fae814395143f29f752147d81f061b71e1e7c55cd32201500aefcfa +size 205193 diff --git a/Exercise_03/videos/task02_gauss_C0_1.mp4 b/Exercise_03/videos/task02_gauss_C0_1.mp4 new file mode 100644 index 0000000..54ee85c --- /dev/null +++ b/Exercise_03/videos/task02_gauss_C0_1.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9c6d31db4c9d079ddade02ff81d4f43453c38c58cde159db128f81c4dc052a04 +size 110100 diff --git a/Exercise_03/videos/task02_square_C0_0.7.mp4 b/Exercise_03/videos/task02_square_C0_0.7.mp4 new file mode 100644 index 0000000..b8b300b --- /dev/null +++ b/Exercise_03/videos/task02_square_C0_0.7.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b57cd2c81fc5a504c37723006a53fec92771208774feb60036e0e1b8e6b5cfe6 +size 139026 diff --git a/Exercise_03/videos/task02_square_C0_1.1.mp4 b/Exercise_03/videos/task02_square_C0_1.1.mp4 new file mode 100644 index 0000000..93d5758 --- /dev/null +++ b/Exercise_03/videos/task02_square_C0_1.1.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7280682f2baca6f8060842414cb21b7a14d954570213a603376d77a4ba4f5b79 +size 203627 diff --git a/Exercise_03/videos/task02_square_C0_1.mp4 b/Exercise_03/videos/task02_square_C0_1.mp4 new file mode 100644 index 0000000..5be2df3 --- /dev/null +++ b/Exercise_03/videos/task02_square_C0_1.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d76345c0bc2b3bb4a8681a01e897d4a3c7cd07910e59955639a6132e964dbdab +size 63942 diff --git a/Exercise_03/videos/video_1_1.mp4 b/Exercise_03/videos/video_1_1.mp4 new file mode 100644 index 0000000..367f92e --- /dev/null +++ b/Exercise_03/videos/video_1_1.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4a4cb97980df40f3b974293f8df9aaa9957c2a00904ff41ae8ebba4cafae05ac +size 55727 diff --git a/Exercise_03/videos/video_1_2.mp4 b/Exercise_03/videos/video_1_2.mp4 new file mode 100644 index 0000000..0ff5f8f --- /dev/null +++ b/Exercise_03/videos/video_1_2.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e8c78843e824c429f1fda7e719b170df07f090177249e02d779c6b1fb5c5dd92 +size 52307 diff --git a/Exercise_03/videos/video_1_3.mp4 b/Exercise_03/videos/video_1_3.mp4 new file mode 100644 index 0000000..51dc003 --- /dev/null +++ b/Exercise_03/videos/video_1_3.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cc654c8b8ebcc49756d61b442a38d49fbba8c60a4072384114c6523315d4aef2 +size 54732 diff --git a/Exercise_03/videos/video_1_4.mp4 b/Exercise_03/videos/video_1_4.mp4 new file mode 100644 index 0000000..5fcb585 --- /dev/null +++ b/Exercise_03/videos/video_1_4.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1d141868869243e85e057a38dce2dd749987c115059c56325e1a9d202d26b0f0 +size 55802 diff --git a/Exercise_03/videos/video_1_x.mp4 b/Exercise_03/videos/video_1_x.mp4 new file mode 100644 index 0000000..df52be2 --- /dev/null +++ b/Exercise_03/videos/video_1_x.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2f37b8b3f4773af979376d5c4083c5fdc8276c280d592a6f1410a35ad620e05a +size 127767 diff --git a/Exercise_03/videos/video_2_gauss_C0_1.mp4 b/Exercise_03/videos/video_2_gauss_C0_1.mp4 new file mode 100644 index 0000000..cdd88f0 --- /dev/null +++ b/Exercise_03/videos/video_2_gauss_C0_1.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3ea7f54b6147da2edafeb0e805bdc6a568a18d477bedb20f5515ede38fba0a68 +size 59759