Euler Method
Euler Method
html
Forward Euler
The formula for the forward Euler method is given by equation (8.2) in the lecture note
for week 8, as
yi+1 = yi + f (xi , yi )h . (1)
where f (xi , yi ) is the differential equation evaluated at xi and yi .
The first step is to calculate dy/dx = f (xi , yi ) at xi and yi . Evaluating differential equations
dy/dx is done by using feval function. In Matlab, the feval function is already provided
as a built-in function. However, in Python we have to manually define or create this
function. For example, we name the function “feval” and return the evaluated function
using the Python’s built-in command eval, as follows:
def feval ( funcName , * args ) :
return eval ( funcName ) ( * args )
We have briefly learned in lecture 7 on how to pass arguments using the asterisk symbol.
See file “withArgs firstOrderMethods.py”.
To test this function/method, create a .py file (name the file, for example: “example feval.py”).
See an example of this file in lecture 7.
import numpy as np
import math
a = feval ( ’ np . cos ’ , np . pi )
1
Dr Vivi Andasari http://people.bu.edu/andasari/courses/numericalpython/python.html
def myFunc ( x ) :
return x ** 2
cin = 9 . 0
c = feval ( ’ myFunc ’ , cin )
print ( " If x = " , str ( cin ) , " then x ** 2 = " , c )
The next step is to solve for yi+1 by directly implementing the above equation (1). We
create a function to implement the forward method. The function takes in several input
arguments to be used in calculating yi+1 . The input arguments consist of the ODE(s) to
be solved (we refer to it as func), initial condition(s) of the ODE(s) (yinit), the range of
interval where the ODE(s) to be evaluated (x range), and the step size (h). The function
definition with the input arguments mentioned above can be written as follows,
def forwardEuler ( func , yinit , x_range , h ) :
We have to make the function as general as possible, and that includes the ability to solve
a system of ODEs. The function needs to know how many ODEs to be solved and we
do this by calculating the length of yinit using the command len. The interval x range
also needs to be divided into smaller subintervals whose length is fixed and defined by the
step size h. The number of subintervals, along with the number of ODEs to be solved, all
will be used in identifying the number of iterations, hence, they must be of integer values.
After the function definition, we add the following lines:
numOfODEs = len ( yinit )
sub_intervals = int (( x_range [ - 1 ] - x_range [ 0 ] ) / h )
Next, we initialize variables x and y and fill them with the values from inputs passed in
the function definition,
x = x_range [ 0 ]
y = yinit
We also need to initialize other variables, xsol and ysol, which will be used as containers
to save the results of calculation of x and y after each iteration. The first element of each
of these containers is filled with the initial values of x and y, respectively,
2
Dr Vivi Andasari http://people.bu.edu/andasari/courses/numericalpython/python.html
xsol = [ x ]
ysol = [ y [ 0 ] ]
After initializations of all variables required in the calculation are done, the next thing do
is to calculate the derivative f (xi , yi ). As has been explained above, the derivative can be
evaluated using the feval function as follows,
yprime = feval ( func , x , y )
Then we increase the position of x and store the new value in xsol,
x += h
xsol . append ( x )
The new value of y (which is the yi+1 ) is also stored in ysol. If there are multiple ODEs,
m
the value of each yi+1 (where m is the number of ODEs) that has been solved is stored one
after the other, such as [y11 , y12 , y13 , · · · , y21 , y22 , y23 , · · · ]. Likewise is the arrangement in ysol,
hence our algorithm needs to access each value of y and uses the following commands,
for r in range ( len ( y ) ) :
ysol . append ( y [ r ] )
and this completes one cycle of iteration. The calculation starts over again from the initial
loop, and so on. Our function returns the values of calculated x and y stored in xsol and
ysol.
The full implementation of the forward method can be done as follows (see “ex1 forwardEuler.py”),
def forwardEuler ( func , yinit , x_range , h ) :
’’’
This method performs the forward Euler method steps .
’’’
numOfODEs = len ( yinit ) # Number of ODEs
sub_intervals = int (( x_range [ - 1 ] - x_range [ 0 ] ) / h ) # Number of sub -
intervals
3
Dr Vivi Andasari http://people.bu.edu/andasari/courses/numericalpython/python.html
When using Numpy, there are little changes such as the following (see “ex1 forwardEuler Numpy.py”):
and ysol,
ysol = np . append ( ysol , y [ r ] )
Backward Euler
The formula for the backward Euler method is given by equation (8.19) in the lecture note,
4
Dr Vivi Andasari http://people.bu.edu/andasari/courses/numericalpython/python.html
which is a bit tricky because at present (at i) we obviously don’t have the future value (at
i + 1) of yi+1 . Hence, the backward method is referred to as being implicit. To solve this
problem, we do calculation by hand using an example equation,
dy
= 3(1 + x) − y . (4)
dx
0
In Python, the implementation of yi+1 can be represented by
yprime = feval ( func , x +h , y )
yp = mult ( yprime , 1 / ( 1 + h ) )
0
where, the formulation of yp is equal to yi+1 . Here we use a function called mult to perform
element-wise multiplication operation of yprime (which is a vector or Python’s list of single
value) and (1/(1+h)) (which is a scalar). The function mult is defined as follows,
def mult ( vector , scalar ) :
newvector = [ 0 ] * len ( vector )
for i in range ( len ( vector ) ) :
newvector [ i ] = vector [ i ] * scalar
return newvector
5
Dr Vivi Andasari http://people.bu.edu/andasari/courses/numericalpython/python.html
Without defining and using the mult function, direct multiplication (using the asterisk) of
list and scalar will result in repetition of the whole list, such as
>>> a = [ 1 . 0 ]
>>> b = 3 * a
>>> b
[ 1 .0 , 1 .0 , 1 . 0 ]
However, when using Numpy, the product of vector/array/list and scalar is straight for-
ward, hence there is no need to involve the mult function,
yprime = feval ( func , x +h , y )
yp = yprime * ( 1 / ( 1 + h ) )
x = x_range [ 0 ]
y = yinit
xsol = [ x ]
ysol = [ y [ 0 ] ]
yp = mult ( yprime , ( 1 / ( 1 + h ) ) )
x += h
xsol . append ( x )
6
Dr Vivi Andasari http://people.bu.edu/andasari/courses/numericalpython/python.html
Heun’s Method
h h 0
yi+1 = yi + f (xi , yi ) + f (xi+1 , yi+1 ), (9)
2 2
where
0
yi+1 = yi + f (xi , yi )h . (10)
To break it down, in our Python code the derivative f (xi , yi ) is represented by,
y0prime = feval ( func , x , y )
while the second term on the right hand side of equation (10) or multiplication of f (xi , yi )
and h is represented by
k1 = mult ( y0prime , h )
0
the derivative with predictor equation f (xi+1 , yi+1 ) is represented by,
y1prime = feval ( func , x +h , ypredictor )
x = x_range [ 0 ]
y = yinit
xsol = [ x ]
ysol = [ y [ 0 ] ]
7
Dr Vivi Andasari http://people.bu.edu/andasari/courses/numericalpython/python.html
k1 = mult ( y0prime , h )
x += h
xsol . append ( x )
Midpoint Method
where
h
yi+ 1 = yi + f (xi , yi ) . (12)
2 2
8
Dr Vivi Andasari http://people.bu.edu/andasari/courses/numericalpython/python.html
x = x_range [ 0 ]
y = yinit
xsol = [ x ]
ysol = [ y [ 0 ] ]
k1 = mult ( y0prime , h / 2 )
x += h
xsol . append ( x )