0

I solve a set of couples ODEs which I solve using the GSL ODE solver similar to this example. Currently this is automates by writing a file in python e.g

text = """
#include <stdio.h>
#include <gsl/gsl_errno.h>

...

"""

Then replacing strings in text with the relevant words and writing to a file script.c. I then using os.system to run it e.g

os.system("gcc -Wall -I/usr/local/include -c script.c")
os.system("gcc -static script.o -lgsl -lgslcblas -lm")
os.system("./a.out >  %s" % (file_name) )

All of this very inelegant and so I have been reading about alternatives and have stumbled PyGSL, CythonGSL so far. These seem to lack proper documentation and I'm not really smart enough to work out how they work!

Any advise would be appreciated.

Greg
  • 11,654
  • 3
  • 44
  • 50

2 Answers2

4

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:

plot of the solution generated by pygsl

Warren Weckesser
  • 110,654
  • 19
  • 194
  • 214
  • Great answer very well thought out. I now have this and Cython_GSL running just need to decide which is better/easier. Thanks for your help – Greg May 06 '13 at 21:19
1

If you can write a C library which takes parameters instead of using string substitution of C code from your Python code, then you can compile the C library seperately and call functions in it from your Python code using CFFI.

How complicated/dynamic are these substitutions?

r3m0t
  • 1,850
  • 16
  • 21
  • This looks promising, especially as it has demos. I make two types of subs, those that simply replace variable such as t1=float and those that change the 'structure' of the program such as directly changing the ODE equations, or the way to end the program (either time > t1 or some number smaller than another). And hopefully it will get more complex than this in future. – Greg Apr 29 '13 at 09:15
  • In that case, you should use SciPy Weave, which I think does exactly what you want. – r3m0t Apr 29 '13 at 13:35