Loading [MathJax]/jax/output/HTML-CSS/fonts/TeX/fontdata.js

Sunday, 5 January 2014

Numerical methods: ODE and Finite difference method

The goal of this post is show how solve an ordinary differential equation, numerically and using the finite difference method and compare the result with the analytic solution. The problem statement is as follow:

Numerically solve the ODE: m2yt2=byt that represents an object whose velocity at t=0 is equal to v0 and it is slowing due to a retardant force, which is proportional to its velocity.

The integration interval is 0t5 seconds. For simplicity, we take m=b=1.
Boundary conditions:

  • y(0)=0m
  • y(5)=1m

Analytic solution:
Y(t)=mv0b(1ebmt) where v0=1

Ordinary differential equation:
We will start solving the ordinary differential equation of second grade . I will explain the resolution step by step:

  • Step 1: Characteristic equation
  • Step 2: Finding constants of integration
m2yt2=bytmD2=bDD(mD+b)=0
Thus, we have two possible solutions: s1=0;s2=bm. As these two roots are real and distinct (s1s2) we can use the general solution for this specific case:

Y(x)=C1es1x+C2es2xY(t)=C1e0t+C2ebmt=C1+C2ebmt

Using the boundary conditions we can obtain the constants of integration C1 and C2:
Y(t=0)C1=C2
Y(t=5)C2+C2ebm5=1(1+ebm5)C2=1C2=1(1+ebm5)
Solution:
Y(t)=1(1+ebm5)+1(1+ebm5)ebmt

m=b=1Y(t)=1.006781.00678et

Finite difference method:
We use the centered difference at time t to obtain the central difference approximation in both equation sides.
y"=2yt2=Ui+12Ui+Ui1h2y=yt=Ui+1Ui12h
Now we can sustitude these above approximations in the initial expression:
mh2(Ui+12Ui+Ui1)=b2h(Ui+1Ui1) Isolate Ui:
Ui+12Ui+Ui1=b2h(Ui+1Ui1)h2m[bh2m(Ui+1Ui1)(Ui+1+Ui1)]12=Ui

Implementation:
For this simple example, we create a Python class called "ODE", which includes the analytic solution and the basic methodology based on the iterative scheme.

Iterations:

def solve(self, n, steps, m, b, h):
    v = np.zeros(n)
    #Boundary conditions
    #y(t = 0) = 0
    v[0] = 0
    #y(t = 5) = 1
    v[n - 1] = 1

    #Iterations
    for i in range(steps):
        for i in range(1, n - 1):
            a1 = (v[i - 1] - v[i + 1]) * (b * h / (2 * m))
            a2 = v[i + 1] + v[i - 1]
            v[i] = (a1 - a2) / (-2)
    return v
As shown, the first value in the array =0, first boundary condition (we start the loop in the position 1) and the last value = 1 (position n - 1). Finally, the function returns the complete array.

The attached chart shows how the result is approximated by finite difference as the number of iterations increases.



Code:
import numpy as np
import matplotlib.pyplot as plt


class ODE(object):

    def __init__(self, m, b, v0, t_min, t_max, n):
        self.t = np.linspace(t_min, t_max, n)
        #Analytic solution
        self.s = m * v0 / b * (1 - np.exp(- b / m * self.t))
        #ODE
        C2 = 1 / (- 1 + np.exp(- b / m * t_max))
        C1 = -C2
        self.f = C1 + C2 * np.exp(- b / m * self.t)

    def solve(self, n, steps, m, b, h):
        v = np.zeros(n)
        #Boundary conditions
        #y(t = 0) = 0
        v[0] = 0
        #y(t = 5) = 1
        v[n - 1] = 1

        #Iterations
        for i in range(steps):
            for i in range(1, n - 1):
                a1 = (v[i - 1] - v[i + 1]) * (b * h / (2 * m))
                a2 = v[i + 1] + v[i - 1]
                v[i] = (a1 - a2) / (-2)
        return v

#inputs and solution:
m = 1
b = 1
v0 = b / m
t_min = 0.0
t_max = 5.0
n = 100
h = t_max / n

vel = ODE(m, b, v0, t_min, t_max, n)
plt.plot(vel.t, vel.f, 'b.-', label='ODE')
plt.plot(vel.t, vel.s, 'g.-', label='Analytic solution')

for i in range(250, 3000, 500):
    sol_i = vel.solve(n, i, m, b, h)
    plt.plot(vel.t, sol_i, '-.', label=r'Iteration = %i' % i)

plt.ylabel('Distance (m)')
plt.xlabel('Time (s)')

plt.legend(loc=2, prop={'size': 9})
plt.show()

No comments:

Post a Comment