A finite difference solution of an ODE is stable if it produces a bounded solution for a stable ODE.
To avoid instability, we need $|y_{n+1}/y_n|\le 1$, so $$|1-\alpha\Delta t|\le 1,$$
$$-1\le 1-\alpha\Delta t\le 1.$$import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
from scipy.optimize import fsolve
def odeEE(f, y0, t):
ns = len(t)-1
y = np.zeros(ns+1)
y[0] = y0
for k in range(ns):
h = t[k+1]-t[k]
y[k+1] = y[k] + h*f(y[k],t[k])
return y
#---------------------------
def odeIE(f, y0, t):
ns = len(t)-1
y = np.zeros(ns+1)
y[0] = y0
def F(ynext):
return ynext - y[k] - h*f(ynext, t[k+1])
for k in range(ns):
h = t[k+1]-t[k]
y[k+1] = fsolve(F, y[k-1])[0]
return y
def f(y, t):
α = 1; return -α*y
#---------------------------
y0 = 1
tend = 10
Δt = 0.1 * 1
t = np.arange(0,tend+Δt, Δt)
yex = y0*np.exp(-t)
yee = odeEE(f, y0, t)
yie = odeIE(f, y0, t)
#---------------------------
plt.rc('font', size=14)
plt.plot(t,yex, 'k:'); plt.plot(t,yee); plt.plot(t,yie)
plt.xlabel('t'); plt.ylabel('y')
plt.legend(['exact', 'EE', 'IE'], frameon=False);
t = np.linspace(0,5,10000)
y = -2*np.exp(-1000*t) + t + 2
plt.subplot(2,1,1)
plt.plot(t,y)
plt.xlim([0,5])
plt.ylabel('y'); plt.xlabel('t')
plt.subplot(2,1,2)
plt.plot(t,y)
plt.xlim([0,0.005])
plt.ylim([0,2.5]); plt.ylabel('y'); plt.xlabel('t')
plt.tight_layout()
def f(y,t):
alpha = 100
return -alpha*(y-t-2.0) + 1.0
y0 = 0 # try with 0 and 2
tend = 4.5
tEX = np.linspace(0,tend,10000)
yEX = -2*np.exp(-100*tEX) + tEX + 2
fac = 0.90 # try values: 0.1, 0.5, 0.9, 1.1
dt = 2.0/100*fac # 2/alpha is the stability limit, * a factor to adjust up or down
t = np.arange(0,tend+dt, dt)
yEE = odeEE(f, y0, t)
#----------------------
print(f'n steps = {len(t)-1}')
plt.subplot(2,1,1)
plt.plot(tEX,yEX); plt.plot(t, yEE)
plt.subplot(2,1,2)
plt.plot(tEX,yEX); plt.plot(t, yEE)
plt.xlim([0,0.05])
plt.tight_layout();
n steps = 250
fac = 2.1 # try values: 0.1, 0.5, 0.9, 1.1, 10
dt = 2.0/100*fac
t = np.arange(0,tend+dt, dt)
yIE = odeIE(f, y0, t)
#----------------------
print(f'n steps = {len(t)-1}')
plt.subplot(2,1,1)
plt.plot(tEX,yEX); plt.plot(t, yIE)
plt.subplot(2,1,2)
plt.plot(tEX,yEX); plt.plot(t, yIE)
plt.xlim([0,0.05])
plt.tight_layout();
n steps = 108