First Order Initial Value Problem#
The more general form of a first order Ordinary Differential Equation is:
This can be solved analytically by integrating both sides but this is not straight forward for most problems. Numerical methods can be used to approximate the solution at discrete points.
Euler method#
The simplest one step numerical method is the Euler Method named after the most prolific of mathematicians Leonhard Euler (15 April 1707 – 18 September 1783) .
The general Euler formula for the first order differential equation
approximates the derivative at time point
where
This substitution changes the differential equation into a difference equation of the form
Assuming uniform stepsize
This can be read as the future
## Library
import numpy as np
import math
import pandas as pd
%matplotlib inline
import matplotlib.pyplot as plt # side-stepping mpl backend
import matplotlib.gridspec as gridspec # subplots
import warnings
warnings.filterwarnings("ignore")
Population growth#
The general form of the population growth differential equation is:
where
Integrating gives the general analytic (exact) solution:
We will use this equation to illustrate the application of the Euler method.
Discrete Interval#
The continuous time
Here the interval is
this gives the 21 discrete points:
This is generalised to
The plot below shows the discrete time steps.
### Setting up time
t_end=2.0
t_start=0
N=20
h=(t_end-t_start)/(N)
time=np.arange(t_start,t_end+0.01,h)
fig = plt.figure(figsize=(10,4))
plt.plot(time,0*time,'o:',color='red')
plt.xlim((0,2))
plt.title('Illustration of discrete time points for h=%s'%(h))
plt.plot();

Initial Condition#
To get a specify solution to a first order initial value problem, an initial condition is required.
For our population problem the intial condition is:
This gives the analytic solution
Growth rate#
Let the growth rate
giving the analytic solution.
The plot below shows the exact solution on the discrete time steps.
## Analytic Solution y
y=10*np.exp(0.5*time)
fig = plt.figure(figsize=(10,4))
plt.plot(time,y,'o:',color='black')
plt.xlim((0,2))
plt.xlabel('time')
plt.ylabel('y')
plt.title('Analytic (Exact) solution')
plt.plot();

Numerical approximation of Population growth#
The differential equation is transformed using the Euler method into a difference equation of the form
This approximates a series of of values
w=np.zeros(N+1)
w[0]=10
for i in range (0,N):
w[i+1]=w[i]+h*(0.5)*w[i]
fig = plt.figure(figsize=(10,4))
plt.plot(time,y,'o:',color='black',label='exact')
plt.plot(time,w,'s:',color='blue',label='Euler')
plt.xlim((0,2))
plt.xlabel('time')
plt.legend(loc='best')
plt.title('Analytic and Euler solution')
plt.plot();

Numerical Error#
With a numerical solution there are two types of error:
local truncation error at one time step;
global error which is the propagation of local error.
Derivation of Euler Local truncation error#
The left hand side of a initial value problem
Rearranging and letting
From this the local truncation error is
where
Derivation of Euler Local truncation error for the Population Growth#
In most cases
From this a maximum upper limit can be calculated for
The plot below shows the exact local truncation error
fig = plt.figure(figsize=(10,4))
plt.plot(time[0:2],np.abs(w[0:2]-y[0:2]),'^:'
,color='red',label='Error |y-w|')
plt.plot(time[0:2],0.1*2.63/2*np.ones(2),'v:'
,color='black',label='Upper Local Truncation')
plt.xlim((0,.15))
plt.xlabel('time')
plt.legend(loc='best')
plt.title('Local Truncation Error')
plt.plot();

Global Error#
The error does not stay constant accross the time this is illustrated in the figure below for the population growth equation. The actual error (red triangles) increases over time while the local truncation error (black v) remains constant.
fig = plt.figure(figsize=(10,4))
plt.plot(time,np.abs(w-y),'^:'
,color='red',label='Error |y-w|')
plt.plot(time,0.1*2.63/2*np.ones(N+1),'v:'
,color='black',label='Upper Local Truncation')
plt.xlim((0,2))
plt.xlabel('time')
plt.legend(loc='best')
plt.title('Why Local Truncation does not extend to global')
plt.plot();

Theorems#
The theorem below proves an upper limit of the global truncation error.
Euler Global Error#
Theorem Global Error
Suppose
Let
and
Theorems about Ordinary Differential Equations#
Definition
A function
whenever
Theorem
Suppose
then
Global truncation error for the population equation#
For the population equation specific values
In this case
on
Specific Theorem Global Error
Let
and
The figure below shows the exact error
fig = plt.figure(figsize=(10,4))
plt.plot(time,np.abs(w-y),'^:'
,color='red',label='Error |y-w|')
plt.plot(time,0.1*6.8*(np.exp(0.5*time)-1),'x:'
,color='black',label='Upper Global Truncation')
plt.xlim((0,2))
plt.xlabel('time')
plt.legend(loc='best')
plt.title('Global Truncation Error')
plt.plot();

Table#
The table below shows the iteration
d = {'time t_i': time[0:10], 'Euler (w_i) ':w[0:10],'Exact (y)':y[0:10],'Exact Error (|y_i-w_i|)':np.round(np.abs(w[0:10]-y[0:10]),10),r'Global Error ':np.round(0.1*6.8*(np.exp(0.5*time[0:10])-1),20)}
df = pd.DataFrame(data=d)
df
time t_i | Euler (w_i) | Exact (y) | Exact Error (|y_i-w_i|) | Global Error | |
---|---|---|---|---|---|
0 | 0.0 | 10.000000 | 10.000000 | 0.000000 | 0.000000 |
1 | 0.1 | 10.500000 | 10.512711 | 0.012711 | 0.034864 |
2 | 0.2 | 11.025000 | 11.051709 | 0.026709 | 0.071516 |
3 | 0.3 | 11.576250 | 11.618342 | 0.042092 | 0.110047 |
4 | 0.4 | 12.155062 | 12.214028 | 0.058965 | 0.150554 |
5 | 0.5 | 12.762816 | 12.840254 | 0.077439 | 0.193137 |
6 | 0.6 | 13.400956 | 13.498588 | 0.097632 | 0.237904 |
7 | 0.7 | 14.071004 | 14.190675 | 0.119671 | 0.284966 |
8 | 0.8 | 14.774554 | 14.918247 | 0.143693 | 0.334441 |
9 | 0.9 | 15.513282 | 15.683122 | 0.169840 | 0.386452 |