One of the earliest known differential equations, which Newton solved with series expansion in 1671 is: $$ \begin{align} y'(x) =1-3x+y+x^2+xy,\ y(0)=0 \label{eq:newton} \end{align} $$
Newton gave the following solution: $$ \begin{align} y(x) \approx x-x^2+\frac{x^3}{3}-\frac{x^4}{6}+ \frac{x^5}{30}-\frac{x^6}{45} \label{eq:newton_approx} \end{align} $$
Today it is possible to give the solution on closed form with known functions as follows, $$ \begin{align} y(x)=&3\sqrt{2\pi e}\cdot \exp\left[x\left(1+\frac{x}{2}\right)\right]\cdot \left[\text{erf}\left(\frac{\sqrt{2}}{2}(1+x)\right)-\text{erf}\left(\frac{\sqrt{2}}{2}\right)\right] + 4\cdot\left[1-\exp[x\left(1+\frac{x}{2}\right)\right]-x \label{eq:newton_analytical} \end{align} $$
Note the combination \( \sqrt{2\pi e} \).
Solve Eq. \eqref{eq:newton} using Euler's method. Plot and compare with Newton's solution Eq. \eqref{eq:newton_approx} and the analytical solution Eq. \eqref{eq:newton_analytical}. Plot between \( x=0 \) and \( x=1.5 \)
The function scipy.special.erf will be needed. See http://docs.scipy.org/doc/scipy-0.15.1/reference/generated/scipy.special.erf.html.
Figure should look something like this:
Figure 1: Problem 1 with 101 samplepoints between \( x=0 \) and \( x=1.5 \) .

# python_exercises/pexercise2/problem1.py
import numpy as np
import matplotlib.pylab as plt
from scipy.special import erf
def euler(func, y_0, time):
""" Generic implementation of the euler scheme for solution of systems of ODEs (note that x may be interchanged by e.g. x):
y0' = y1
y1' = y2
.
.
yN' = f(yN-1,..., y1, y0, t)
method:
y0^(n+1) = y0^(n) + h*y1
y1^(n+1) = y1^(n) + h*y2
.
.
yN^(n + 1) = yN^(n) + h*f(yN-1, .. y1, y0, t)
Args:
func(function): func(y, t) that returns y' at time t; [y1, y2,...,f(yn-1, .. y1, y0, t)]
y_0(array): initial conditions
time(array): array containing the time to be solved for
Returns:
y(array): array/matrix containing solution for y0 -> yN for all timesteps"""
y = np.zeros((np.size(time), np.size(y_0)))
y[0,:] = y_0
for i in range(len(time)-1):
h = time[i+1] - time[i]
y[i+1,:]=y[i,:] + np.asarray(func(y[i,:], time[i]))*h
return y
def newton_func(y, x):
""" function that returns the RHS of the Newton ODE:
y' = 1 - 3x + y + x^2 + xy
Args:
y(array): array [y0, y1] at distance x
x(float): current position
Returns:
dy(float): y'
"""
dy = 1 - 3*x + y + x**2 + x*y
return dy
x = np.linspace(0, 1.5, 101) #allocate Space
y_0 = 0
Y = euler(newton_func, y_0, x)
Y_newton = x - x**2 + x**3/3 - x**4/6 + x**5/30 - x**6/45
e = np.exp(1)
pi = np.pi
Y_analytical = 3*np.sqrt(2*pi*e)*np.exp(x*(1 + x/2))*(erf(np.sqrt(2)*(1 + x)/2) - erf(np.sqrt(2)/2)) + 4*(1-np.exp(x*(1 + x/2))) - x
plt.figure()
plt.plot(x, Y_analytical)
plt.plot(x, Y)
plt.plot(x, Y_newton)
plt.legend(['analytical', 'euler', 'Newton'], loc='best', frameon=False)
plt.xlabel('x')
plt.ylabel('y')
#plt.savefig('problem1.png', transparent=True)
plt.show()
Figure 2: Mathematical pendulum.

Figure 2 shows a mathematical pendulum. By modeling the friction forces acting on the pendulum as \( \mu \frac{d \theta}{dt} \), the motion can be described by the following ODE: $$ \begin{align} \frac{d ^2\theta}{dt^2} + \frac{\mu}{m} \frac{d \theta}{dt} + \frac{g}{l} \sin\theta &=0, \label{eq:1} \end{align} $$
where \( \mu \) is a friction coefficient, \( l \) is the length og the rod and \( m \) is the mass of the pendulum with initial conditions $$ \begin{align} &\theta(0) =\theta_0 \label{_auto1}\\ &\frac{d \theta}{dt}(0)=\dot\theta_0. \label{_auto2} \end{align} $$
Assume that the pendulum wire is a massless rod, such that \( -\pi \leq \theta_0 \leq \pi \). Unless stated otherwise, use \( \mu=1 \), \( m=1 \), \( g=9.81 \), \( l=1 \), \( \theta_0=85^o \) and \( \dot\theta_0=0 \).
Write a Python program that solves the ODE in \eqref{eq:1} with the specified initial conditions using Euler's method (remember to use radians). Experiment with different time steps \( \Delta t \), and friction coefficients \( \mu \). How do they affect the stability of the solution? Carry out the computation for a few cycles, and plot the amplitude as a functions of \( t \).
import numpy as np
import matplotlib.pylab as plt
from myanimation import animatePendulum
#### parameters ####
m = 1.
g = 9.81
L = 1.
mu = 1.
#### initial conditions ####
theta_0 = np.pi*85./180
dtheta_0 = 0.
#### arrays for time and solution vectors ####
t_start = 0
t_end = 10.
N = 1000
T = np.linspace(t_start, t_end, N + 1)
dt = T[1] - T[0]
Theta0 = np.zeros_like(T) # array to contain solutions for theta
Theta1 = np.zeros_like(T) # array to contain solutions for d(theta)/dt
Theta0[0] = theta_0 # set initial condition for theta
Theta1[0] = dtheta_0 # set initial condition for d(theta)/dt
#### solving loop for euler's method
for n, t in enumerate(T[:-1]):
f0 = Theta1[n]
f1 = -mu*Theta1[n]/m - g*np.sin(Theta0[n])/L
Theta0[n + 1] = Theta0[n] + dt*f0
Theta1[n + 1] = Theta1[n] + dt*f1
plt.figure()
plt.plot(T, Theta0)
plt.show()
E = 0.5*(Theta1**2 - dtheta_0**2) + np.cos(theta_0) - np.cos(Theta0)
animatePendulum(Theta0, T, l=1)
a) Solve Problem 2 using Heun's method.
b) Write a function that detects the amplitude peaks, and use this to calculate the period of the pendulum. Is it constant?
import numpy as np
import matplotlib.pylab as plt
#from myanimation import animatePendulum
def findPeaks(X, V):
peakList = []
for n, v in enumerate(V[:-1]):
if np.sign(v) != np.sign(V[ n + 1]):
peakList.append(X[n])
return np.array(peakList)
#### parameters ####
m = 1.
g = 9.81
L = 2.
mu = 1
#### initial conditions ####
theta_0 = np.pi*85./180
dtheta_0 = 0.
#### arrays for time and solution vectors ####
t_start = 0
t_end = 10.
N = 10000
T = np.linspace(t_start, t_end, N + 1)
dt = T[1] - T[0]
Theta0 = np.zeros_like(T) # array to contain solutions for theta
Theta1 = np.zeros_like(T) # array to contain solutions for d(theta)/dt
Theta0[0] = theta_0 # set initial condition for theta
Theta1[0] = dtheta_0 # set initial condition for d(theta)/dt
#### solving loop for heun's method
for n, t in enumerate(T[:-1]):
f0 = Theta1[n]
f1 = -mu*Theta1[n]/m - g*np.sin(Theta0[n])/L
theta0_p = Theta0[n] + dt*f0
theta1_p = Theta1[n] + dt*f1
f0_p = theta1_p
f1_p = -mu*theta1_p/m - g*np.sin(theta0_p)/L
Theta0[n + 1] = Theta0[n] + dt*(f0 + f0_p)/2.
Theta1[n + 1] = Theta1[n] + dt*(f1 + f1_p)/2.
plt.figure()
plt.plot(T, Theta0)
plt.plot(T, Theta1)
plt.plot(findPeaks(T, Theta1), np.zeros_like(findPeaks(T, Theta1)), 'o')
print findPeaks(T, Theta1)[1:] - findPeaks(T, Theta1)[:-1]
plt.show()
#animatePendulum(Theta0, T, l=1)
a) Solve Problem 2 using Midpoint method and Ralston's method. See: "See http://folk.ntnu.no/fredf/teaching/tkt4140/exercises/pythonExercises/pexercise2/TKT4140%20Lec%204%20RKmethods%20(1).pdf
c) create an animation similar to the one above.
import numpy as np
import matplotlib.pylab as plt
#from myanimation import animatePendulum
#### parameters ####
m = 1.
g = 9.81
L = 2.
mu = 1
#### initial conditions ####
theta_0 = np.pi*85./180
dtheta_0 = 0.
#### arrays for time and solution vectors ####
t_start = 0
t_end = 10.
N = 10000
T = np.linspace(t_start, t_end, N + 1)
dt = T[1] - T[0]
Theta0 = np.zeros_like(T) # array to contain solutions for theta
Theta1 = np.zeros_like(T) # array to contain solutions for d(theta)/dt
Theta0[0] = theta_0 # set initial condition for theta
Theta1[0] = dtheta_0 # set initial condition for d(theta)/dt
solvingScheme = 'midpoint'
if solvingScheme == 'midpoint':
#### solving loop for midpoint's method
for n, t in enumerate(T[:-1]):
K1_0 = Theta1[n]
K1_1 = -mu*Theta1[n]/m - g*np.sin(Theta0[n])/L
theta0_p = Theta0[n] + 0.5*dt*K1_0
theta1_p = Theta1[n] + 0.5*dt*K1_1
K2_0 = theta1_p
K2_1 = -mu*theta1_p/m - g*np.sin(theta0_p)/L
Theta0[n + 1] = Theta0[n] + dt*(K2_0)
Theta1[n + 1] = Theta1[n] + dt*(K2_1)
else:
#### solving loop for Ralston's method
for n, t in enumerate(T[:-1]):
K1_0 = Theta1[n]
K1_1 = -mu*Theta1[n]/m - g*np.sin(Theta0[n])/L
theta0_p = Theta0[n] + 0.75*dt*K1_0
theta1_p = Theta1[n] + 0.75*dt*K1_1
K2_0 = theta1_p
K2_1 = -mu*theta1_p/m - g*np.sin(theta0_p)/L
Theta0[n + 1] = Theta0[n] + dt*(K1_0/3. +2*K2_0/3.)
Theta1[n + 1] = Theta1[n] + dt*(K1_1/3. + 2*K2_1/3)
plt.figure()
plt.plot(T, Theta0)
plt.plot(T, Theta1)
plt.show()
#animatePendulum(Theta0, T, l=1)
# python_exercises/pexercise2/myanimation.py
import matplotlib.pyplot as plt
from math import sin, cos, pi
from matplotlib import animation
def animatePendulum(theta, t, l=1):
# set up figure and animation
fig = plt.figure()
ax = fig.add_subplot(111, aspect='equal', autoscale_on=False,
xlim=(-1.1, 1.1), ylim=(-1.1, 1.1))
#ax.grid()
line, = ax.plot([], [], '-o', lw=2)
time_text = ax.text(0.02, 0.95, '', transform=ax.transAxes)
theta_text = ax.text(0.02, 0.85, '', transform=ax.transAxes)
def init():
"""initialize animation"""
line.set_data([], [])
time_text.set_text('')
theta_text.set_text('')
return line, time_text
def animate(i):
"""perform animation step"""
x = l*sin(theta[i])
y = -l*cos(theta[i])
deg = theta[i]*180/pi
line.set_data([0, x], [0, y])
time_text.set_text('time = %.1f [-]' % t[i])
theta_text.set_text(r'$\theta$ = %.0f $^o$' % deg)
return line, time_text
# choose the interval based on dt and the time to animate one step
Npictures = len(t)
ani = animation.FuncAnimation(fig, animate,init_func=init,frames=Npictures,interval=1,blit=False)
#Writer = animation.writers['ffmpeg']
#writer = Writer(fps=30, metadata=dict(artist='Me'), bitrate=1800)
#ani.save('pendulum.mov', writer=writer)
plt.show()