2024 Week 9 FTDC - Jupyter Notebook
2024 Week 9 FTDC - Jupyter Notebook
∂𝜓 = 𝜅 ∂2 𝜓
∂𝑡 ∂𝑥2
𝜓 = 𝜓(𝑥,𝑡) is the function we are solving for.
𝜅 is the diffusion coefficient.
Δ𝑡 is the time step.
ℎ is the spatial grid spacing.
𝐃𝐢𝐬𝐜𝐫𝐞𝐭𝐢𝐳𝐚𝐭𝐢𝐨𝐧 𝐓𝐲𝐩𝐞 𝐀𝐩𝐩𝐫𝐨𝐱𝐢𝐦𝐚𝐭𝐢𝐨𝐧 𝐅𝐨𝐫𝐦𝐮𝐥𝐚
Time Discretization (Euler Forward) ∂𝜓 ≈ 𝜓𝑖𝑛+1 − 𝜓𝑖𝑛
∂𝑡 𝑛 Δ𝑡 𝑛 𝑛
Space Discretization (Central Difference) ∂𝑥2 ≈ − 2ℎ𝜓2𝑖 + 𝜓𝑖−1
∂ 2 𝜓 𝜓𝑖+1
Stability Analysis
𝜓𝑖𝑛 = 𝐴𝑛 𝑒𝑖𝑘𝑥𝑖
Substitute this Fourier mode into the discretized update equation:
|𝐺| ≤ 1
−1 ≤ 1 − 4𝜆 ≤ 1
0 ≤ 4𝜆 ≤ 2
The result from the algebra gives 𝜆 ≤ 12 , but in many numerical methods, specifically explicit methods like the Forward-Time Centered-Space (FTCS) method
used for solving diffusion equations, the stability condition is more restrictive. It is known from analysis (von Neumann stability analysis) that for stability, 𝜆 should
satisfy:
𝜆 ≤ 14
Thus, the final condition is 𝜆 ≤ 14 , which is a more conservative bound for numerical stability than 𝜆 ≤ 12 .
𝜆 = 𝜅Δ𝑡 1
ℎ2 ≤ 4
Δ𝑡 ≤ 4𝜅ℎ
2
What is the condition for stability for solving wave equation ∂𝑡 𝜓 + 𝑐∂𝑥 𝜓 = 0 using Euler backward scheme for time step Δ𝑡 with finite difference scheme?
Here, Δ𝑥 𝑐
is grid spacing and is speed of wave.
∂𝜓 + 𝑐 ∂𝜓 = 0
We start with the 1D linear advection equation (or wave equation):
∂𝑡 ∂𝑥
where 𝑐 is the wave speed, 𝜓 is the wave function, and we will solve this equation on a spatial grid using finite differences.
𝑐Δ𝑡
To analyze the stability of this scheme, we look at how errors propagate. The term
Δ𝑥 is known as the Courant number:
𝜆 = 𝑐Δ𝑡
Δ𝑥
The stability of the explicit finite difference method depends on the size of this Courant number . 𝜆
𝜆
If is too large, the scheme becomes unstable.
We perform a von Neumann stability analysis by assuming the solution 𝜓 behaves like a wave:
𝜓𝑖𝑛 = 𝜓̂ 𝑛 𝑒𝑖𝑘𝑥𝑖
where 𝜓̂ 𝑛is the amplitude of the wave and 𝑘 is the wavenumber.
Substitute this into the update equation:
𝜓̂ 𝑛+1 𝑒𝑖𝑘𝑥𝑖 = 𝜓̂ 𝑛 𝑒𝑖𝑘𝑥𝑖 − 𝜆 (𝜓̂ 𝑛 𝑒𝑖𝑘𝑥𝑖+1 − 𝜓̂ 𝑛 𝑒𝑖𝑘𝑥𝑖 )
Simplifying the exponents using 𝑥𝑖+1 = 𝑥𝑖 + Δ𝑥:
𝜓̂ 𝑛+1 𝑒𝑖𝑘𝑥𝑖 = 𝜓̂ 𝑛 𝑒𝑖𝑘𝑥𝑖 [1 − 𝜆(𝑒𝑖𝑘Δ𝑥 − 1)]
𝜓̂ 𝑛+1𝑛 = 1 − 𝜆(𝑒𝑖𝑘Δ𝑥 − 1) = 1 − λ[cos(𝑘Δ𝑥) + 𝑖sin(𝑘Δ𝑥) − 1] [ ∵ 𝑒𝑖𝑘Δ𝑥 = cos(𝑘Δ𝑥) + 𝑖sin(𝑘Δ𝑥) ] Euler's formula
𝜓̂
𝜓̂ 𝑛+1𝑛 = 1 − 𝜆(cos(𝑘Δ𝑥) − 1) − 𝑖𝜆sin(𝑘Δ𝑥)
𝜓̂
For stability, the amplitude |𝜓̂
𝑛+1 | must not grow with time. This leads to the condition:
|𝜓̂ | ≤ |𝜓̂ |
𝑛+1 𝑛
|| 𝜓̂ 𝑛+1 ||
|| 𝜓̂ 𝑛 || ≤ 1
| |
|| 𝜓̂ 𝑛+1 || ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ ⎯
|| 𝜓̂ 𝑛 || = √[1 − 𝜆(cos(𝑘Δ𝑥) − 1)]2 + [−𝜆sin(𝑘Δ𝑥)]2 ≤ 1
| |
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
√1 − 2𝜆cos(𝑘Δ𝑥) + 𝜆2 cos2 (𝑘Δ𝑥) + 2𝜆 − 2𝜆2 cos(𝑘Δ𝑥) + 𝜆2 + 𝜆2 sin2 (𝑘Δ𝑥) ≤ 1 [ ∵ sin2 (𝑘Δ𝑥) + cos2 (𝑘Δ𝑥) = 1 ]
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
√1 − 2𝜆cos(𝑘Δ𝑥) + 2𝜆 + 𝜆2 ≤ 1
Square both sides to eliminate the square root:
1 − 2𝜆cos(𝑘Δ𝑥) + 2𝜆 + 𝜆2 ≤ 1
−2𝜆cos(𝑘Δ𝑥) + 2𝜆 + 𝜆2 ≤ 0
This inequality must hold for all values of 𝑘.
The most restrictive case occurs when cos(𝑘Δ𝑥) = 1, which corresponds to the longest wavelength modes (smallest wavenumbers).
−2𝜆 + 2𝜆 + 𝜆2 ≤ 0
𝜆2 ≤ 0
𝜆 ≤ 1.
𝜆 = 𝑐Δ𝑡
After simplification, we find that the scheme is stable if:
Δ𝑥 ≤ 1
Δ𝑡 ≤ Δ𝑥𝑐
This leads to the stability condition/CFL condition:
This ensures that the numerical solution remains stable and avoids spurious oscillations or blow-up.
What is the form of error for solving wave equation ∂𝑡 𝜓 + 𝑐∂𝑥 𝜓 = 0 using Upwind scheme?
ℎ 𝑐
Here, is grid spacing and is speed of wave.
𝜖 ≈ ℎ ∂∂𝑥2𝜙2
Write a Python program to solve the 1D diffusion equation numerically using Finite difference method with periodic boundary conditions.
The diffusion equation is written as:
∂Ψ
∂𝑡 = 𝜅 ∂∂𝑥2Ψ2
Solve the PDE in [0,2π] box by using 𝑁 = 64 grid2 points, 𝜅 = 0.5,𝑡 = 1 and 𝑑𝑡 = 0.001.
Take the initial condition as Ψ(𝑥,𝑡 = 0) = 𝑒−2(𝑥−2) .
Find the maximum value of ϕ(𝑥,𝑡 = 1) (rounded off upto 4 decimal places) and choose the correct option.
Note:
• Use three point central difference scheme for calculating the second order derivative with respect to . 𝑥
• Use RK2 method for performing the time integration.
In [16]: 1 k = 0.5
2 L = 2*np.pi
3 N = 64
4 h = L/N
5 x = np.arange(0, L, h)
6 #x = np.linspace(0, L, N, endpoint=False)
7 tf = 1
8 dt = 0.001
9 nsteps = int(tf/dt)
10 prefactor = k*dt/h**2
11 init_temp = np.exp(-2*(x-2)**2)
12
13 f = np.zeros(N+2)
14 f_mid = np.zeros(N+2)
15 f[1:N+1] = init_temp
16 f[0] = init_temp[-1]
17 f[N+1] = init_temp[0]
18
19 for i in range(nsteps+2):
20 f_mid[1:N+1] = f[1:N+1] +(prefactor/2)*(f[0:N]-2*f[1:N+1]+f[2:N+2])
21 f_mid[0] = f_mid[N]
22 f_mid[-1] = f_mid[1]
23
24 f[1:N+1] = f[1:N+1] + prefactor*(f_mid[0:N]-2*f_mid[1:N+1]+f_mid[2:N+2])
25 f[0] = f[N]
26 f[-1] = f[1]
27
28 np.round(np.max(f),4)
Out[16]: 0.447
In [3]: 1 L = 2 * np.pi
2 N = 64
3 dx = L / N
4 dt = 0.001
5 T = 1.0
6 k = 0.5
7 initial_condition = lambda x : np.exp(-2 * (x - 2)**2)
8 x = np.linspace(0, L, N, endpoint=False)
9 #x = np.arange(0, L, dx)
10 psi = initial_condition(x)
11 psi_new = np.zeros(N)
12
13 for t in np.arange(0, T, dt):
14 psi_xx = np.roll(psi, -1) - 2 * psi + np.roll(psi, 1)
15 k1 = k * dt * psi_xx / (dx**2)
16 k2 = k * dt * psi_xx / (dx**2)
17 psi_new = psi + 0.5*k1 + 0.5*k2
18 psi = psi_new.copy()
19
20 np.round(np.max(psi),4)
Out[3]: 0.4472
Write a Python program to solve the 1D wave equation numerically using Finite difference method with periodic boundary conditions.
The wave equation is written as:
∂𝜓
∂𝑡 = −𝑐 ∂𝜓∂𝑥
Solve the PDE in box [0,2𝜋] by using 𝑁 = 5122 grid points and 𝑐 = 1,𝑡 = 1 and 𝑑𝑡 = 0.001.
𝜓(𝑥,𝑡 = 0) = 𝑒−32(𝑥−2)
Take initial condition as .
Choose the correct values of (𝜓) (round answer upto two decimal place) at 𝑡 = 1 𝑥 = 3.01
and
(to get 𝑥 = 3.01 𝑥
round the array upto two decimal place and then find the index corresponding to 3.01 as you have done in previous assignment).
Note:
• Use two point backward difference scheme for evaluating the derivative along .𝑥
So the equation becomes 𝜓𝑖𝑛+1 = 𝜓𝑖𝑛 + (−𝑐 𝑑𝑡 ) ∗ (𝜓𝑖𝑛 − 𝜓𝑖−1
𝑛 ), 𝑖 is the grid point number and 𝑛 is the time step number. ℎ is grid spacing.
ℎ
• Now use RK-2 method for performing the time integration.This is done in the notes for diffusion equation, you can get the general idea from there.
In [17]: 1 c = 1
2 L = 2*np.pi
3 N = 512
4 h = L/N
5 x = np.arange(0, L, h)
6 #x = np.linspace(0, L, N)
7 tf = 1
8 dt = 0.001
9 nsteps = int(tf/dt)
10 prefactor = -c*dt/h
11 init = np.exp(-32*(x-2)**2)
12 f = np.zeros(N+2)
13 f_mid = np.zeros(N+2)
14 f[1:N+1] = init
15 f[0] = init[-1]
16 f[N+1] = init[0]
17
18 for i in range(nsteps+2):
19 f_mid[1:N+1] = f[1:N+1] +(prefactor/2)*(f[1:N+1]-f[0:N])
20 f_mid[0] = f_mid[N]
21 f_mid[-1] = f_mid[1]
22
23 f[1:N+1] = f[1:N+1] + prefactor*(f_mid[1:N+1]-f_mid[0:N])
24 f[0] = f[N]
25 f[-1] = f[1]
26
27 index = np.where(np.round(x,2)==3.01)[0][0]
28 np.round(f[index],2)
Out[17]: 0.75
In [5]: 1 L = 2 * np.pi
2 N = 512
3 dx = L / N
4 dt = 0.001
5 T = 1.0
6 c = 1.0
7 initial_condition = lambda x: np.exp(-32 * (x - 2)**2)
8
9 x = np.linspace(0, L, N, endpoint=False)
10 psi = initial_condition(x)
11 psi_new = np.zeros(N)
12 for t in np.arange(0, T, dt):
13 dpsi_dx = (psi - np.roll(psi, 1)) / dx
14 k1 = -c * dt * dpsi_dx
15 psi_half = psi + 0.5 * k1
16 dpsi_half = (psi_half - np.roll(psi_half, 1)) / dx
17 k2 = -c * dt * dpsi_half
18 psi_new = psi + k2
19 psi = psi_new.copy()
20
21 x_rounded = np.round(x, 2)
22 x_target = 3.01
23 #index = np.where(x_rounded == x_target)[0][0]
24 index = round(x_target / dx)
25 round(psi[index], 2)
Out[5]: 0.75
Write a python program to solve the 1D diffusion equation using finite difference method with periodic boundary condition.
The diffusion is written as:
∂ϕ
∂𝑡 = 𝜅 ∂∂𝑥2ϕ2
𝐿 = 2π, with 𝑁 = 64 grid points. Take 𝜅 = 0.3 and 𝑡 = 1 and 𝑑𝑡 = 0.001.
Solve the equation in a box of length
ϕ(𝑥,𝑡 = 0) = 𝑒−2(𝑥−𝜋)2
Take the initial condition .
ϕ(𝑥,𝑡) 𝑡 = 1 𝑥 = 3.09
What is the value of the function at and rounded to two decimal places.
To get 𝑥 = 3.09 𝑥 3.09 𝑥 array as you did in previous assignment.
first round the array to two decimal places and then find the index of in the
Note:
𝑥
1. Use three point central difference scheme to compute the second order derivative with respect to .
2. Use RK2 method to integrate with respect to time.
In [32]: 1 K = 0.3
2 L = 2*np.pi
3 N = 64
4 h = L/N
5 #x = np.arange(0, L, h)
6 x = np.linspace(0, L, N)
7 tf = 1
8 dt = 0.001
9 nsteps = int(tf/dt)
10 prefactor = K*dt/h**2
11 init_temp = np.exp(-2*(x-np.pi)**2)
12 f = np.zeros(N+2)
13 f_mid = np.zeros(N+2)
14 f[1:N+1] = init_temp
15 f[0] = init_temp[-1]
16 f[N+1] = init_temp[0]
17
18 for i in range(nsteps+1):
19 f_mid[1:N+1] = f[1:N+1] +(prefactor/2)*(f[0:N]-2*f[1:N+1]+f[2:N+2])
20 f_mid[0] = f_mid[N]
21 f_mid[-1] = f_mid[1]
22
23 f[1:N+1] = f[1:N+1] + prefactor*(f_mid[0:N]-2*f_mid[1:N+1]+f_mid[2:N+2])
24 f[0] = f[N]
25 f[-1] = f[1]
26
27 index = np.where(np.round(x,2)==3.09)[0][0]
28 np.round(f[index],2)
Out[32]: 0.53
In [40]: 1 K = 0.3
2 L = 2*np.pi
3 N = 64+1
4 h = L/N
5 x = np.arange(0, L, h)
6 #x = np.linspace(0, L, N, endpoint=False)
7 tf = 1
8 dt = 0.001
9 nsteps = int(tf/dt)
10 prefactor = K*dt/h**2
11 init_temp = np.exp(-2*(x-np.pi)**2)
12 f = np.zeros(N+2)
13 f_mid = np.zeros(N+2)
14 f[1:N+1] = init_temp
15 f[0] = init_temp[-1]
16 f[N+1] = init_temp[0]
17
18 for i in range(nsteps+1):
19 f_mid[1:N+1] = f[1:N+1] +(prefactor/2)*(f[0:N]-2*f[1:N+1]+f[2:N+2])
20 f_mid[0] = f_mid[N]
21 f_mid[-1] = f_mid[1]
22
23 f[1:N+1] = f[1:N+1] + prefactor*(f_mid[0:N]-2*f_mid[1:N+1]+f_mid[2:N+2])
24 f[0] = f[N]
25 f[-1] = f[1]
26
27 index = np.where(np.round(x,2)==3.09)[0][0]
28 np.round(f[index],2)
Out[40]: 0.54
In [44]: 1 L = 2 * np.pi
2 N = 64
3 dx = L / N
4 dt = 0.001
5 T = 1.0
6 k = 0.3
7
8 initial_condition = lambda x : np.exp(-2 * (x - np.pi)**2)
9 #x = np.arange(0, L, dx)
10 x = np.linspace(0, L, N)
11
12 psi = initial_condition(x)
13 psi_new = np.zeros(N)
14
15 for t in np.arange(0, T, dt):
16 psi_xx = np.roll(psi, -1) - 2 * psi + np.roll(psi, 1)
17 k1 = k * dt * psi_xx / (dx**2)
18 k2 = k * dt * psi_xx / (dx**2)
19 psi_new = psi + 0.5 * k1 + 0.5 * k2
20 psi = psi_new.copy()
21
22 index = np.where(np.round(x,2)==3.09)[0][0]
23 np.round(psi[index],2) # N=256 | idx=126 || N=128 | idx=63 || N=64 | idx=31
Out[44]: 0.54
In [ ]: 1