%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
def dP_dt(P, t):
G = 1.0
M = 1.0
x, y, vx, vy = P
r3 = np.hypot(x, y)**3
ax = -G*M*x/r3
ay = -G*M*y/r3
return np.array([vx, vy, ax, ay])
Let $$\frac{d\vec{P}}{dt} = f(\vec{P}, t)$$
Then
$$\vec{P}(t + h) = \vec{P}(t) + hf(\vec{P}, t)$$The global error is O(h).
def euler_path(tmax, h, P0):
steps = int(tmax/h)
path = np.empty((steps+1, 4))
P = np.copy(P0)
path[0] = P
for i in range(steps):
P += h*dP_dt(P, i*h)
path[i+1] = P
return path
def plot_euler(tmax, h, P):
path = euler_path(tmax, h, P)
plt.plot(path[:,0], path[:,1])
plt.axis('equal')
plt.plot(0, 0, 'yo', ms=10)
where
$$\begin{cases} F_1 &= hf(\vec{P}, t) \\ F_2 &= hf(\vec{P} + F_1, t + h) \end{cases}$$The global error is O(h2).
def heun_path(tmax, h, P0):
steps = int(tmax/h)
path = np.empty((steps+1, 4))
P = np.copy(P0)
path[0] = P
for i in range(steps):
F1 = h*dP_dt(P, i*h)
F2 = h*dP_dt(P + F1, (i+1)*h)
P += (F1 + F2)/2.
path[i+1] = P
return path
def plot_heun(tmax, h, P):
path = heun_path(tmax, h, P)
plt.plot(path[:,0], path[:,1])
plt.axis('equal')
plt.plot(0, 0, 'yo', ms=10)
where
$$\begin{cases} F_1 &= hf(\vec{P}, t) \\ F_2 &= hf(\vec{P} + \frac{1}{2}F_1, t + \frac{1}{2}h) \\ F_3 &= hf(\vec{P} + \frac{1}{2}F_2, t + \frac{1}{2}h) \\ F_4 &= hf(\vec{P} + F_3, t + h) \end{cases}$$The global error is O(h4).
def rk4_path(tmax, h, P0):
steps = int(tmax/h)
path = np.empty((steps+1, 4))
P = np.copy(P0)
path[0] = P
for i in range(steps):
F1 = h*dP_dt(P, i*h)
F2 = h*dP_dt(P + F1/2, (i+0.5)*h)
F3 = h*dP_dt(P + F2/2, (i+0.5)*h)
F4 = h*dP_dt(P + F3, (i+1)*h)
P += (F1 + 2*F2 + 2*F3 + F4)/6.
path[i+1] = P
return path
def plot_rk4(tmax, h, P0, standalone=True):
path = rk4_path(tmax, h, P0)
plt.plot(path[:,0], path[:,1])
plt.axis('equal')
plt.plot(0, 0, 'yo', ms=10)
plt.figure(figsize=(6,6))
tmax = 10000
h = 0.1
P0 = np.array([1.,0.,0.,1.])
plot_heun(tmax, h, P0)
plot_rk4(tmax, h, P0)
plt.grid()
P0 = np.array([1., 0., 0.625, 0.625])
plt.figure(figsize=(15,5))
plt.subplot('131')
plot_euler(100, 0.01, P0)
plt.title("Euler's Method")
plt.subplot('132')
plot_heun(100, 0.01, P0)
plt.title("Heun's Method")
plt.subplot('133')
plot_rk4(100, 0.01, P0)
plt.title("Fourth-Order Runge-Kutta Method")
a = np.arange(12)*10
print(a)
a[[1, 4, 6]] ≡ [a[1], a[4], a[6]]
b = np.array([1, 4, 6])
print(a[b])
a[b] = 100
print(a)
c = np.array([[1, 3], [5, 6]])
print(c)
print(a[c])
%matplotlib
from matplotlib import animation
Note: If running this on a Mac:
tmax = 20
h = 0.01
P0 = np.array([1., 0., 0., .5])
path = rk4_path(tmax, h, P0)
frames = int(tmax/h)
fig, ax = plt.subplots(figsize=(8,8))
ax.set_aspect('equal')
planet, = plt.plot([], [], 'bo')
plt.plot(0, 0, 'yo', ms=8)
width = .25 + np.amax(np.abs(path[:,:2]))
plt.xlim(-width, width)
plt.ylim(-width, width)
def animate(frame, path, planet):
x, y = path[frame, :2]
planet.set_data(x, y)
return planet,
animation.FuncAnimation(fig, animate, frames=frames, fargs=(path, planet), interval=0, blit=True, repeat=True)
tmax = 20
h = 0.01
P0 = np.array([1., 0., 0., .5])
path = rk4_path(tmax, h, P0)
frames = int(tmax/h)
fig, ax = plt.subplots(figsize=(8,8))
ax.set_aspect('equal')
ax.set_facecolor('k')
planet, = plt.plot([], [], 'bo')
orbit, = plt.plot([], [], 'cyan', lw=1)
plt.plot(0, 0, 'yo', ms=8)
width = .25 + np.amax(np.abs(path[:,:2]))
plt.xlim(-width, width)
plt.ylim(-width, width)
def animate(frame, path, planet, orbit):
x, y = path[frame, :2]
planet.set_data(x, y)
orbit.set_data(path[:frame, 0], path[:frame, 1])
return orbit, planet,
animation.FuncAnimation(fig, animate, frames=frames, fargs=(path, planet, orbit), interval=0, blit=True, repeat=True)