views:

587

answers:

3

Hi all,

I'm looking for a good library that will integrate stiff ODEs in Python. The issue is, scipy's odeint gives me good solutions sometimes, but the slightest change in the initial conditions causes it to fall down and give up. The same problem is solved quite happily by MATLAB's stiff solvers (ode15s and ode23s), but I can't use it (even from Python, because none of the Python bindings for the MATLAB C API implement callbacks, and I need to pass a function to the ODE solver). I'm trying PyGSL, but it's horrendously complex. Any suggestions would be greatly appreciated.

EDIT: The specific problem I'm having with PyGSL is choosing the right step function. There are several of them, but no direct analogues to ode15s or ode23s (bdf formula and modified Rosenbrock if that makes sense). So what is a good step function to choose for a stiff system? I have to solve this system for a really long time to ensure that it reaches steady-state, and the GSL solvers either choose a miniscule time-step or one that's too large.

A: 

I am currently studying a bit of ODE and its solvers, so your question is very interesting to me...

From what I have heard and read, for stiff problems the right way to go is to choose an implicit method as a step function (correct me if I am wrong, I am still learning the misteries of ODE solvers). I cannot cite you where I read this, because I don't remember, but here is a thread from gsl-help where a similar question was asked.

So, in short, seems like the bsimp method is worth taking a shot, although it requires a jacobian function. If you cannot calculate the Jacobian, I will try with rk2imp, rk4imp, or any of the gear methods.

YuppieNetworking
+3  A: 

Python can call C. The industry standard is LSODE in ODEPACK. It is public-domain. You can download the C version. These solvers are extremely tricky, so it's best to use some well-tested code.

Added: Be sure you really have a stiff system, i.e. if the rates (eigenvalues) differ by more than 2 or 3 orders of magnitude. Also, if the system is stiff, but you are only looking for a steady-state solution, these solvers give you the option of solving some of the equations algebraically. Otherwise, a good Runge-Kutta solver like DVERK will be a good, and much simpler, solution.

Added here because it would not fit in a comment: This is from the DLSODE header doc:

C     T     :INOUT  Value of the independent variable.  On return it
C                   will be the current value of t (normally TOUT).
C
C     TOUT  :IN     Next point where output is desired (.NE. T).

Also, yes Michaelis-Menten kinetics is nonlinear. The Aitken acceleration works with it, though. (If you want a short explanation, first consider the simple case of Y being a scalar. You run the system to get 3 Y(T) points. Fit an exponential curve through them (simple algebra). Then set Y to the asymptote and repeat. Now just generalize to Y being a vector. Assume the 3 points are in a plane - it's OK if they're not.) Besides, unless you have a forcing function (like a constant IV drip), the MM elimination will decay away and the system will approach linearity. Hope that helps.

Mike Dunlavey
Thanks for the LSODE tip. I found that someone has already written a Python interface for it at http://www.cs.uiuc.edu/homes/mrgates2/ode/. Will try this out tomorrow and accept your answer if it works.
Chinmay Kanchi
@Chinmay: Bingo! Hope it works for you.
Mike Dunlavey
I know I really do have a stiff system, but looking at the LSODE sources, I realised I have a possible bug in my program. The scipy.integrate.odeint solver is based on LSODA, and like all the LS* solvers, it takes a vector of time points at which to compute the solution. Turns out, I'm computing this time vector to be far too coarse. I switched to Python from MATLAB and thought that numpy.arange would work similarly to i=t0:tn in MATLAB. It doesn't. So I've been solving only for integer times all the while...
Chinmay Kanchi
@Chinmay: It takes a vector of time points? In my experience you run it from the first time to the second, at which point you can make discontinuous changes in the state if you want to, and then run to the third, and so on. That's how we do all our pharmacometric modeling. BTW, I forgot to mention if your ODE system is linear (constant Jacobian) you can use DGPADM - it's fast and never has a stiffness problem. Also, if the system is linear, you can solve for the steady-state solution algebraically.
Mike Dunlavey
... I forgot to mention, since you said you are looking for the steady-state, I use a method called Aitken Acceleration (for which the system does not have to be linear). Basically, the idea is you assume it will converge in some roughly exponential way to an asymptote. So you take 3 points on the trajectory, predict where the asymptote will be, set your system there, and repeat. It converges very quickly.
Mike Dunlavey
I'm afraid the system is horribly non-linear (Michaelis-Menten-type equations with modifications that make them _more_ non-linear). Will look into Aitken acceleration. From the odeint docs: `t : arrayA sequence of time points for which to solve for y. The initial value point should be the first element of this sequence.`
Chinmay Kanchi
+1  A: 

If you can solve your problem with Matlab's ode15s, you should be able to solve it with the vode solver of scipy. To simulate ode15s, I use the following settings:

ode15s = scipy.integrate.ode(f)
ode15s.set_integrator('vode', method='bdf', order=15, nsteps=3000)
ode15s.set_initial_value(u0, t0)

and then you can happily solve your problem with ode15s.integrate(t_final). It should work pretty well on a stiff problem.

(See also http://www.scipy.org/NumPy_for_Matlab_Users)

Olivier
Nice! Thanks for that. I arrived at more or less a similar solution in the end, using `vode`.
Chinmay Kanchi