PyGSL might be a reasonable option. (CythonGSL, too, but I haven't tried it.)
I'm running Ubuntu 12.04 (64 bit), and for this installation, I am using the Anaconda
python distribution. (It might work fine with the default Python in Ubuntu,
but I didn't try.)
I have GSL 1.15 installed from source, and I just installed PyGSL 0.9.5 from
source by following the instructions in the README. That is, I ran
$ python setup.py build
$ python setup.py install
in the top directory of the extracted tar file. Like many python packages that
build C libraries, a lot of warnings are printed during the build step, but it
completed without errors.
Here's some code that demonstrates the use of the ODE solver in PyGSL:
#
# pendulum_demo.py
#
# Use PyGSL to solve the differential equations for a pendulum with
# friction. Plot the solution using matplotlib.
#
import numpy as np
import matplotlib.pyplot as plt
from pygsl import odeiv
def pendsys(t, y, args):
"""
The right-hand side of the first order system of differential equations.
"""
theta, v = y
g, b, L, m = args
f = np.zeros((2,))
f[0] = v
f[1] = -b * v / (m * L ** 2) - np.sin(theta) * g / L
return f
def pendjac(t, y, args):
"""
The Jacobian of the system.
"""
theta, v = y
g, b, L, m = args
jac = np.zeros((2, 2))
jac[0, 1] = 1.0
jac[1, 0] = -g / L * np.cos(theta)
jac[1, 1] = -b / (m * L ** 2)
dfdt = np.zeros((2,))
return jac, dfdt
# Pendulum parameter values
#
# Gravitational constant
g = 9.81
# Friction coefficient
b = 0.5
# Pendulum length
L = 1.0
# Pendulum bob mass
m = 2.0
# Initial conditions
theta0 = np.pi - 0.01
v0 = 0.0
y = [theta0, v0]
t = 0
# Solver control parameters.
abserr = 1e-11
relerr = 1e-9
stoptime = 12.0
# Create the GSL ODE solver
N = 2
step = odeiv.step_rk8pd(N, pendsys, pendjac, args=(g, b, L, m))
control = odeiv.control_y_new(step, abserr, relerr)
evolve = odeiv.evolve(step, control, N)
# h is the initial step size.
h = stoptime / 500.0
# The time values and points in the solution are saved in the lists
# tsol and ysol, respectively. The lists are initialized with
# the initial conditions.
tsol = [t]
ysol = [y]
# Call evolve.apply(...) until the solution reaches stoptime
while t < stoptime:
t, h, y = evolve.apply(t, stoptime, h, y)
tsol.append(t)
ysol.append(y)
tsol = np.array(tsol)
ysol = np.array(ysol)
plt.plot(tsol, ysol[:, 0], label=r'$\theta$')
plt.plot(tsol, ysol[:, 1], label='v')
plt.xlabel('t')
plt.grid(True)
plt.legend()
plt.title('Pendulum with Friction')
plt.show()
The resulting plot:
