Numeric Analysis 3 - ODE¶
from math import *
import matplotlib.pyplot as plt
%matplotlib inline
First-Order ODEs¶
Initial value problem
y′=f(x,y),y(x0)=y0
at the equidistant points on the x-axis
where the step size h is a fixed number, for instance, 0.2 or 0.1 or 0.01
We compute approximate numeric values of y(x)
y1,y2,y3,⋯
By the Taylor series
For small h the higher powers h2,h3,⋯ are very small.
The Euler method is
yn+1=yn+hf(xn,yn)(n=0,1,⋯)
[ Example ] Obtain numerical solution with h=0.2
y′=y+x,y(0)=0The exact solution is y=ex−x−1
from math import *
def f(x,y): # y'
return y + x
h = 0.2
N = 6
x = [0]*N
y = [0]*N # initial value y[0] = 0
# print(x,y)
for n in range(N-1): # n = 0, 1, 2, ... 4
x[n] = n*h
x[n+1] = (n+1)*h
y[n+1] = y[n] + h * f( x[n], y[n] )
print(x,y)
yEuler = y # 나중에 비교를 위해서 보관
Improved Euler Method. Predictor, Corrector¶
The predictor is calculated by
y∗n+1=yn+hf(xn,yn)
The corrector is then calculated by
yn+1=yn+12h[f(xn,yn)+f(xn+1,y∗n+1)]
[ Example ] Obtain numerical solution with h=0.2
y′=y+x,y(0)=0The exact solution is y=ex−x−1
from math import *
def f(x,y): # y'
return y + x
h = 0.2
N = 6
x = [0]*N
y = [0]*N # initial value y[0] = 0
ypre = [0]*N
for n in range(N-1):
x[n] = n*h
ypre[n+1] = y[n] + h * f( x[n], y[n] ) # predictor
x[n+1] = (n+1)*h
y[n+1] = y[n] + h/2 *( f(x[n],y[n]) + f(x[n+1],ypre[n+1]) ) # corrector
# 비교
print('수치해를 정답과 비교 \n')
print(' x Euler Improved Euler Exact')
for n in range(N):
yexact = exp(x[n]) - x[n] - 1
print('%9.6f %9.6f %9.6f %9.6f' %( x[n], yEuler[n], y[n], yexact ) )
yImEuler = y
Runge–Kutta Method¶
# Runge-Kutta method
from math import *
def f(x,y): # y'
return y + x
h = 0.2
N = 6
x = [0]*N
y = [0]*N # initial value y[0] = 0
for n in range(N-1):
x[n] = n*h
k1 = h* f( x[n], y[n] )
k2 = h* f( x[n]+h/2, y[n]+k1/2 )
k3 = h* f( x[n]+h/2, y[n]+k2/2 )
k4 = h* f( x[n]+h, y[n]+k3 )
x[n+1] = (n+1)*h
y[n+1] = y[n] + 1/6 *( k1 + 2*k2 + 2*k3 + k4 )
# 비교
print('수치해를 정답과 비교 \n')
print(' x Improved Euler Runge-Kutta Exact')
for n in range(N):
yexact = exp(x[n]) - x[n] - 1
print('%9.6f %9.6f %9.6f %9.6f' %( x[n], yImEuler[n], y[n], yexact ) )
Methods for Systems and Higher Order ODEs¶
Initial value problems for first-order systems of ODEs
Initial value problem for an m th-order ODE
with initial conditions y(x0)=K1,y′(x0)=K2,⋯,y(m−1)(x0)=Km
The higher-order ODE can be rewritten as a system of the first-order ODEs by setting
Then we obtain the system of first-order ODEs
y′1=y2 y′2=y3 ⋮ y′m−1=ym y′m=f(x,y1,y2,y3,⋯,ym)
with initial conditions y1(x0)=K1,y2(x0)=K2,⋯,ym(x0)=Km
Euler Method for Systems¶
This method will not be accurate enough for practical purposes.
For first-order systems of ODEs, the Euler method prescribes
yn+1=yn+hf(xn,yn)in components y1,n+1=y1,n+hf1(x,y1,n,y2,n,⋯,ym,n), y2,n+1=y2,n+hf2(x,y1,n,y2,n,⋯,ym,n), ⋮⋮ ym,n+1=ym,n+hfm(x,y1,n,y2,n,⋯,ym,n),
[Example] Second-Order ODE. Mass–Spring System
y″+2y′+0.75y=0,y(0)=3,y′(0)=−2.5Obtain the numerical solution with step h=0.2
(exact solution) y=2e−0.5x+e−1.5x
We let y1=y,y2=y′
The the second-order ODE becomes
# Euler method
from math import *
def f1(x,y1,y2): # y1' = f1(x,y1,y2)
return y2
def f2(x,y1,y2): # y2' = f2(x,y1,y2)
return -2*y2 - 0.75*y1
h = 0.2
N = 6
x = [0]*N
y1 = [0]*N
y2 = [0]*N
# initial value
y1[0] = 3
y2[0] = -2.5
for n in range(N-1): # n = 0,1,2, ... 4
x[n] = n*h
x[n+1] = (n+1)*h
y1[n+1] = y1[n] + h* f1( x[n], y1[n], y2[n] )
y2[n+1] = y2[n] + h* f2( x[n], y1[n], y2[n] )
# 비교
print('수치해를 정답과 비교 \n')
print(' x Euler Exact')
for n in range(N):
yexact = 2*exp(-0.5*x[n]) + exp(-1.5*x[n])
print('%9.6f %9.6f %9.6f' %( x[n], y1[n], yexact ) )
yEuler = y1 # 나중을 위해 저장
Runge–Kutta Methods for Systems¶
At each step n, four auxiliary quantities are calculated
k1=hf(xn,yn)k2=hf(xn+12h,yn+12k1)k3=hf(xn+12h,yn+12k2)k4=hf(xn+h,yn+k3)New values at the next step n+1 are calculated by
yn+1=yn+16(k1+2k2+2k3+k4)
[Example] Second-Order ODE. Mass–Spring System
y″+2y′+0.75y=0,y(0)=3,y′(0)=−2.5Obtain the numerical solution with step h=0.2
(exact solution) y=2e−0.5x+e−1.5x
# Runge-Kutta method
from math import *
def f1(x,y1,y2): # y1' = f1(x,y1,y2)
return y2
def f2(x,y1,y2): # y2' = f2(x,y1,y2)
return -2*y2 - 0.75*y1
h = 0.2
N = 6
x = [0]*N
y1 = [0]*N
y2 = [0]*N
# initial value
y1[0] = 3
y2[0] = -2.5
for n in range(N-1): # n = 0,1,2, ... 4
x[n] = n*h
x[n+1] = (n+1)*h
k11 = h* f1( x[n], y1[n], y2[n] )
k12 = h* f2( x[n], y1[n], y2[n] )
k21 = h* f1( x[n]+h/2, y1[n]+k11/2, y2[n]+k12/2 )
k22 = h* f2( x[n]+h/2, y1[n]+k11/2, y2[n]+k12/2 )
k31 = h* f1( x[n]+h/2, y1[n]+k21/2, y2[n]+k22/2 )
k32 = h* f2( x[n]+h/2, y1[n]+k21/2, y2[n]+k22/2 )
k41 = h* f1( x[n]+h, y1[n]+k31, y2[n]+k32 )
k42 = h* f2( x[n]+h, y1[n]+k31, y2[n]+k32 )
y1[n+1] = y1[n] + 1/6 *( k11 + 2*k21 + 2*k31 + k41 )
y2[n+1] = y2[n] + 1/6 *( k12 + 2*k22 + 2*k32 + k42 )
# 비교
print('수치해를 정답과 비교 \n')
print(' x Euler Runge-Kutta Exact')
for n in range(N):
yexact = 2*exp(-0.5*x[n]) + exp(-1.5*x[n])
print('%9.6f %9.6f %9.6f %9.6f' %( x[n], yEuler[n], y1[n], yexact ) )
댓글 없음:
댓글 쓰기