1
/* This file should be included in the multipack module */
2
/* $Revision: 2055 $ */
4
{"odeint", (PyCFunction) odepack_odeint, METH_VARARGS|METH_KEYWORDS, doc_odeint},
6
/* link libraries: (should be listed in separate lines)
12
/* python files: (to be appended to Multipack.py)
17
#if defined(NO_APPEND_FORTRAN)
26
void ode_function(int *n, double *t, double *y, double *ydot)
28
ydot[0] = -0.04*y[0] + 1e4*y[1]*y[2];
29
ydot[2] = 3e7*y[1]*y[1];
30
ydot[1] = -ydot[0] - ydot[2];
35
void ode_function(int *n, double *t, double *y, double *ydot)
37
/* This is the function called from the Fortran code it should
38
-- use call_python_function to get a multiarrayobject result
39
-- check for errors and return -1 if any
40
-- otherwise place result of calculation in ydot
43
PyArrayObject *result_array = NULL;
44
PyObject *arg1, *arglist;
46
/* Append t to argument list */
47
if ((arg1 = PyTuple_New(1)) == NULL) {
52
PyTuple_SET_ITEM(arg1, 0, PyFloat_FromDouble(*t));
53
/* arg1 now owns newly created reference */
54
if ((arglist = PySequence_Concat( arg1, multipack_extra_arguments)) == NULL) {
60
Py_DECREF(arg1); /* arglist has reference */
62
result_array = (PyArrayObject *)call_python_function(multipack_python_function, *n, y, arglist, 1, odepack_error);
63
if (result_array == NULL) {
68
memcpy(ydot, result_array->data, (*n)*sizeof(double));
69
Py_DECREF(result_array);
75
int ode_jacobian_function(int *n, double *t, double *y, int *ml, int *mu, double *pd, int *nrowpd)
77
/* This is the function called from the Fortran code it should
78
-- use call_python_function to get a multiarrayobject result
79
-- check for errors and return -1 if any (though this is ignored
81
-- otherwise place result of calculation in pd
84
PyArrayObject *result_array;
85
PyObject *arglist, *arg1;
87
/* Append t to argument list */
88
if ((arg1 = PyTuple_New(1)) == NULL) {
93
PyTuple_SET_ITEM(arg1, 0, PyFloat_FromDouble(*t));
94
/* arg1 now owns newly created reference */
95
if ((arglist = PySequence_Concat( arg1, multipack_extra_arguments)) == NULL) {
101
Py_DECREF(arg1); /* arglist has reference */
103
result_array = (PyArrayObject *)call_python_function(multipack_python_jacobian, *n, y, arglist, 2, odepack_error);
104
if (result_array == NULL) {
108
if (multipack_jac_transpose == 1)
109
MATRIXC2F(pd, result_array->data, *n, *nrowpd)
111
memcpy(pd, result_array->data, (*n)*(*nrowpd)*sizeof(double));
114
Py_DECREF(result_array);
119
int setup_extra_inputs(PyArrayObject **ap_rtol, PyObject *o_rtol, PyArrayObject **ap_atol, PyObject *o_atol, PyArrayObject **ap_tcrit, PyObject *o_tcrit, int *numcrit, int neq)
122
double tol=1.49012e-8;
125
/* Setup tolerances */
126
if (o_rtol == NULL) {
127
*ap_rtol = (PyArrayObject *)PyArray_FromDims(1,&one,PyArray_DOUBLE);
128
if (*ap_rtol == NULL) PYERR2(odepack_error,"Error constructing relative tolerance.");
129
*(double *)(*ap_rtol)->data = tol; /* Default */
132
*ap_rtol = (PyArrayObject *)PyArray_ContiguousFromObject(o_rtol,PyArray_DOUBLE,0,1);
133
if (*ap_rtol == NULL) PYERR2(odepack_error,"Error converting relative tolerance.");
134
if ((*ap_rtol)->nd == 0); /* rtol is scalar */
135
else if ((*ap_rtol)->dimensions[0] == neq)
136
itol |= 2; /* Set rtol array flag */
138
PYERR(odepack_error,"Tolerances must be an array of the same length as the\n number of equations or a scalar.");
141
if (o_atol == NULL) {
142
*ap_atol = (PyArrayObject *)PyArray_FromDims(1,&one,PyArray_DOUBLE);
143
if (*ap_atol == NULL) PYERR2(odepack_error,"Error constructing absolute tolerance");
144
*(double *)(*ap_atol)->data = tol;
147
*ap_atol = (PyArrayObject *)PyArray_ContiguousFromObject(o_atol,PyArray_DOUBLE,0,1);
148
if (*ap_atol == NULL) PYERR2(odepack_error,"Error converting absolute tolerance.");
149
if ((*ap_atol)->nd == 0); /* atol is scalar */
150
else if ((*ap_atol)->dimensions[0] == neq)
151
itol |= 1; /* Set atol array flag */
153
PYERR(odepack_error,"Tolerances must be an array of the same length as the\n number of equations or a scalar.");
155
itol++; /* increment to get correct value */
158
/* Setup t-critical */
159
if (o_tcrit != NULL) {
160
*ap_tcrit = (PyArrayObject *)PyArray_ContiguousFromObject(o_tcrit,PyArray_DOUBLE,0,1);
161
if (*ap_tcrit == NULL) PYERR2(odepack_error,"Error constructing critical times.");
162
*numcrit = PyArray_Size((PyObject *)(*ap_tcrit));
166
fail: /* Needed for use of PYERR */
171
int compute_lrw_liw(int *lrw, int *liw, int neq, int jt, int ml, int mu, int mxordn, int mxords)
173
int lrn, lrs, nyh, lmat;
175
if (jt == 1 || jt == 2)
177
else if (jt == 4 || jt == 5)
178
lmat = (2*ml + mu + 1)*neq + 2;
179
else PYERR(odepack_error,"Incorrect value for jt");
181
if (mxordn < 0) PYERR(odepack_error,"Incorrect value for mxordn");
182
if (mxords < 0) PYERR(odepack_error,"Incorrect value for mxords");
185
lrn = 20 + nyh*(mxordn+1) + 3*neq;
186
lrs = 20 + nyh*(mxords+1) + 3*neq + lmat;
188
*lrw = NPY_MAX(lrn,lrs);
196
static char doc_odeint[] = "[y,{infodict,}istate] = odeint(fun, y0, t, args=(), Dfun=None, col_deriv=0, ml=, mu=, full_output=0, rtol=, atol=, tcrit=, h0=0.0, hmax=0.0, hmin=0.0, ixpr=0.0, mxstep=0.0, mxhnil=0, mxordn=0, mxords=0)\n yprime = fun(y,t,...)";
198
static PyObject *odepack_odeint(PyObject *dummy, PyObject *args, PyObject *kwdict) {
199
PyObject *fcn, *y0, *p_tout, *o_rtol=NULL, *o_atol=NULL;
200
PyArrayObject *ap_y = NULL, *ap_yout= NULL;
201
PyArrayObject *ap_rtol=NULL, *ap_atol=NULL;
202
PyArrayObject *ap_tout = NULL;
203
PyObject *extra_args = NULL;
204
PyObject *Dfun = Py_None;
205
int neq, itol=1, itask=1, istate=1, iopt=0, lrw, *iwork, liw, jt=4;
206
double *y, t, *tout, *rtol, *atol, *rwork;
207
double h0=0.0, hmax=0.0, hmin=0.0;
208
int ixpr=0, mxstep=0, mxhnil=0, mxordn=12, mxords=5, ml=-1, mu=-1;
209
PyObject *o_tcrit=NULL;
210
PyArrayObject *ap_tcrit=NULL;
211
PyArrayObject *ap_hu=NULL, *ap_tcur=NULL, *ap_tolsf=NULL, *ap_tsw=NULL;
212
PyArrayObject *ap_nst=NULL, *ap_nfe=NULL, *ap_nje=NULL, *ap_nqu=NULL;
213
PyArrayObject *ap_mused=NULL;
214
int imxer=0, lenrw=0, leniw=0, out_sz=0, col_deriv = 0;
215
int k, dims[2], ntimes, crit_ind=0;
216
int allocated = 0, full_output = 0, numcrit=0;
217
double *yout, *yout_ptr, *tout_ptr, *tcrit;
219
static char *kwlist[] = {"fun","y0","t","args","Dfun","col_deriv","ml","mu","full_output","rtol","atol","tcrit","h0","hmax","hmin","ixpr","mxstep","mxhnil","mxordn","mxords",NULL};
223
if (!PyArg_ParseTupleAndKeywords(args, kwdict, "OOO|OOiiiiOOOdddiiiii", kwlist, &fcn, &y0, &p_tout, &extra_args, &Dfun, &col_deriv, &ml, &mu, &full_output, &o_rtol, &o_atol, &o_tcrit, &h0, &hmax, &hmin, &ixpr, &mxstep, &mxhnil, &mxordn, &mxords)) return NULL;
225
if (o_tcrit == Py_None) {
228
if (o_rtol == Py_None) {
231
if (o_atol == Py_None) {
236
INIT_JAC_FUNC(fcn,Dfun,extra_args,col_deriv,odepack_error);
238
/* Set up jt, ml, and mu */
239
if (Dfun == Py_None) jt++; /* set jt for internally generated */
240
if (ml < 0 && mu < 0) jt -= 3; /* neither ml nor mu given,
241
mark jt for full jacobian */
242
if (ml < 0) ml = 0; /* if one but not both are given */
245
/* Initial input vector */
246
ap_y = (PyArrayObject *)PyArray_ContiguousFromObject(y0, PyArray_DOUBLE, 0, 1);
247
if (ap_y == NULL) goto fail;
248
y = (double *) ap_y->data;
249
neq = PyArray_Size((PyObject *)ap_y);
252
/* Set of output times for integration */
253
ap_tout = (PyArrayObject *)PyArray_ContiguousFromObject(p_tout, PyArray_DOUBLE, 0, 1);
254
if (ap_tout == NULL) goto fail;
255
tout = (double *)ap_tout->data;
256
ntimes = PyArray_Size((PyObject *)ap_tout);
260
/* Setup array to hold the output evaluations*/
261
ap_yout= (PyArrayObject *)PyArray_FromDims(2,dims,PyArray_DOUBLE);
262
if (ap_yout== NULL) goto fail;
263
yout = (double *) ap_yout->data;
264
/* Copy initial vector into first row of output */
265
memcpy(yout, y, neq*sizeof(double)); /* copy intial value to output */
266
yout_ptr = yout + neq; /* set output pointer to next position */
268
itol = setup_extra_inputs(&ap_rtol, o_rtol, &ap_atol, o_atol, &ap_tcrit, o_tcrit, &numcrit, neq);
269
if (itol < 0 ) goto fail; /* Something didn't work */
270
rtol = (double *) ap_rtol->data;
271
atol = (double *) ap_atol->data;
272
if (o_tcrit != NULL) tcrit = (double *)(ap_tcrit->data);
274
/* Find size of working arrays*/
275
if (compute_lrw_liw(&lrw, &liw, neq, jt, ml, mu, mxordn, mxords) < 0) goto fail;
277
if ((wa = (double *)malloc(lrw*sizeof(double) + liw*sizeof(int)))==NULL) {
283
iwork = (int *)(wa + lrw);
285
iwork[0] = ml; iwork[1] = mu; /* ignored if not needed */
287
if (h0 != 0.0 || hmax != 0.0 || hmin != 0.0 || ixpr != 0 || mxstep != 0 || mxhnil != 0 || mxordn != 0 || mxords != 0) {
288
rwork[4] = h0; rwork[5] = hmax; rwork[6] = hmin;
289
iwork[4] = ixpr; iwork[5] = mxstep; iwork[6] = mxhnil;
290
iwork[7] = mxordn; iwork[8] = mxords;
296
/* If full output make some useful output arrays */
299
ap_hu = (PyArrayObject *)PyArray_FromDims(1,&out_sz,PyArray_DOUBLE);
300
ap_tcur = (PyArrayObject *)PyArray_FromDims(1,&out_sz,PyArray_DOUBLE);
301
ap_tolsf = (PyArrayObject *)PyArray_FromDims(1,&out_sz,PyArray_DOUBLE);
302
ap_tsw = (PyArrayObject *)PyArray_FromDims(1,&out_sz,PyArray_DOUBLE);
303
ap_nst = (PyArrayObject *)PyArray_FromDims(1,&out_sz,PyArray_INT);
304
ap_nfe = (PyArrayObject *)PyArray_FromDims(1,&out_sz,PyArray_INT);
305
ap_nje = (PyArrayObject *)PyArray_FromDims(1,&out_sz,PyArray_INT);
306
ap_nqu = (PyArrayObject *)PyArray_FromDims(1,&out_sz,PyArray_INT);
307
ap_mused = (PyArrayObject *)PyArray_FromDims(1,&out_sz,PyArray_INT);
308
if (ap_hu == NULL || ap_tcur == NULL || ap_tolsf == NULL || ap_tsw == NULL || ap_nst == NULL || ap_nfe == NULL || ap_nje == NULL || ap_nqu == NULL || ap_mused == NULL) goto fail;
311
if (o_tcrit != NULL) {itask = 4; rwork[0] = *tcrit;} /* There are critical points */
312
while (k < ntimes && istate > 0) { /* loop over desired times */
315
/* Use tcrit if relevant */
316
if (itask == 4 && *tout_ptr > *(tcrit + crit_ind)) {crit_ind++; rwork[0] = *(tcrit+crit_ind);}
317
if (crit_ind >= numcrit) itask = 1; /* No more critical values */
319
LSODA(ode_function, &neq, y, &t, tout_ptr, &itol, rtol, atol, &itask, &istate, &iopt, rwork, &lrw, iwork, &liw, ode_jacobian_function, &jt);
321
*((double *)ap_hu->data + (k-1)) = rwork[10];
322
*((double *)ap_tcur->data + (k-1)) = rwork[12];
323
*((double *)ap_tolsf->data + (k-1)) = rwork[13];
324
*((double *)ap_tsw->data + (k-1)) = rwork[14];
325
*((int *)ap_nst->data + (k-1)) = iwork[10];
326
*((int *)ap_nfe->data + (k-1)) = iwork[11];
327
*((int *)ap_nje->data + (k-1)) = iwork[12];
328
*((int *)ap_nqu->data + (k-1)) = iwork[13];
332
*((int *)ap_mused->data + (k-1)) = iwork[18];
334
if (PyErr_Occurred()) goto fail;
335
memcpy(yout_ptr, y, neq*sizeof(double)); /* copy integration result to output*/
336
yout_ptr += neq; k++;
341
Py_DECREF(extra_args);
344
Py_XDECREF(ap_tcrit);
351
return Py_BuildValue("N{s:N,s:N,s:N,s:N,s:N,s:N,s:N,s:N,s:i,s:i,s:i,s:N}i",PyArray_Return(ap_yout),"hu",PyArray_Return(ap_hu),"tcur",PyArray_Return(ap_tcur),"tolsf",PyArray_Return(ap_tolsf),"tsw",PyArray_Return(ap_tsw),"nst",PyArray_Return(ap_nst),"nfe",PyArray_Return(ap_nfe),"nje",PyArray_Return(ap_nje),"nqu",PyArray_Return(ap_nqu),"imxer",imxer,"lenrw",lenrw,"leniw",leniw,"mused",PyArray_Return(ap_mused),istate);
354
return Py_BuildValue("Ni",PyArray_Return(ap_yout),istate);
359
Py_XDECREF(extra_args);
363
Py_XDECREF(ap_tcrit);
366
if (allocated) free(wa);
370
Py_XDECREF(ap_tolsf);
376
Py_XDECREF(ap_mused);