Ordinary differential equations (ODEs) 1

Methods

  1. Discretize the independent variable into a grid
  2. Approximate derivatives with F.D. approximations (Taylor series).
  3. Solve

IVP: focus on single point methods (advance using only the previous point), as opposed to multi-step methods.

Explicit Euler method

$$\frac{dy}{dt} = f(y,t),$$

$$y(t=0) = y_0.$$ $$y_{k+1} = y_k + \Delta t f(y_k,t).$$

Example 1 (EE)

$$\frac{dy}{dt} = -ay,$$

$$y_0 = 1,$$

$$a=1.1.$$

This equation has the exact solution

$$y(t) = y_0e^{-at}.$$
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
from scipy.optimize import fsolve
def ode_EE(f, y0, t):
     
    ns = len(t)-1
    y = np.empty(ns+1)
    
    y[0] = y0
    for k in range(ns):
        Δt = t[k+1] - t[k]
        y[k+1] = y[k] + Δt*f(y[k],t[k])
    
    return y
def myfunc(y,t):
    return -1.1*y

#---------------

y0   = 1
tend = 6.0
t    = np.linspace(0, tend, 20)

y = ode_EE(myfunc, y0, t)

plt.rc("font", size=14)
plt.plot(t,y)
plt.plot(t, y0*np.exp(-1.1*t), 'r.')
plt.legend(['EE', 'Exact'], frameon=False)
plt.xlabel('t')
plt.ylabel('y');
EE

Implicit Euler method

$$ y_{k+1} = y_{k} + \Delta tf(y_{k+1},t_{k+1}).$$

Example 2 (IE)

y0 = 1
a  = 1.1

tend = 6.0

t = np.linspace(0.0, tend, 20)
ns = len(t) - 1
y = np.zeros(ns+1)
y[0] = y0

for k in range(ns):    # have n points, take n-1 steps
    Δt = t[k+1]-t[k]
    y[k+1] = y[k]/(1+a*Δt)

plt.rc("font", size=14)
plt.plot(t,y)
plt.plot(t, y0*np.exp(-a*t), 'r.')
plt.legend(['IE', 'Exact'], frameon=False)
plt.xlabel('t')
plt.ylabel('y')
Text(0, 0.5, 'y')
IE

Example 3 (EE, IE nonlinear)

def ode_IE(f, y0, t):
    
    ns = len(t) - 1
    y = np.empty(ns+1)
    y[0] = y0
    
    def F(ykp1):
        return ykp1-y[k]-Δt*f(ykp1,t[k+1])
    
    for k in range(ns):
        Δt = t[k+1]-t[k]
        y[k+1] = fsolve(F, y[k])[0]

    return y
def myfunc(y,t):
    return -y**0.8

#------------------

y0   = 1.0
tend = 3.0

t = np.linspace(0.0, tend, 20)
n = len(t)

yEE = ode_EE(myfunc,y0,t)
yIE = ode_IE(myfunc,y0,t)

#---------------------
    
plt.rc("font", size=14)
plt.plot(t,yEE,'b-')
plt.plot(t,yIE,'g-')
plt.plot(t, (1-0.2*t)**(1/0.2), 'r.')
plt.legend(['EE', 'IE', 'Exact'], frameon=False)
plt.xlabel('t')
plt.ylabel('y');
EE and IE