1 import logging
2 logger = logging.getLogger('daskr')
3
4 import scipy
5
6 import SloppyCell._daskr as _daskr
7 import SloppyCell.Utility as Utility
8
9
10
11
14
15
16 _msgs = {0: "Unexepected status code. (IDID=0)",
17 1: "Integration successful. Call the code again to continue the \
18 integration another step in the direction of TOUT. (IDID=1)",
19 2: "Integration successful. Define a new TOUT and call the code \
20 again. TOUT must be different from T. You cannot change the \
21 direction of integration without restarting. (IDID=2)",
22 3: "Integration successful. Define a new TOUT and call the code again.\
23 TOUT must be different from T. You cannot change the direction of \
24 integration without restarting. (IDID=3)",
25 4: "Reset INFO(11) = 0 and call the code again to begin the \
26 integration. (If you leave INFO(11) > 0 and INFO(14) = 1, you may \
27 generate an infinite loop.) In this situation, the next call to \
28 DDASKR is considered to be the first call for the problem in that all \
29 initializations are done. (IDID=4)",
30 5: "Call the code again to continue the integration in the direction \
31 of TOUT. You may change the functions Ri defined by RT after a return \
32 with IDID = 5, but the number of constraint functions NRT must remain \
33 the same. If you wish to change the functions in RES or in RT, then \
34 you must restart the code. (IDID=5)",
35 -1: "The code has taken more steps than max_steps (default = \
36 500). If you want to continue, call the function again with a higher \
37 value for max_steps. (IDID=-1)",
38 -2: "The error tolerances RTOL, ATOL have been increased to values \
39 the code estimates appropriate for continuing. You may want to change \
40 them yourself. If you are sure you want to continue with relaexed \
41 error tolerances, set INFO(1) = 1 and call the code again. (IDID=-2)",
42 -3: "A solution component is zero and you set the corresponding \
43 component of ATOL to zero. If you are sure you want to continue, you \
44 must first alter the error criterion to use positive values of ATOL \
45 for those components corresponding to zero solution components, then \
46 set INFO(1) = 1 and call the code again. (IDID=-3)",
47 -5: "Your JAC routine failed with the Krylov method. Check for errors \
48 in JAC and restart the integration. (IDID=-5)",
49 -6: "Repeated error test failures occurred on the last attempted step \
50 in DDASKR. A singularity in thesolution may be present. If you are \
51 absolutely certain you want to continue, you should restart the \
52 integration. (Provide initial values of Y and YPRIME which are \
53 consistent.) (IDID=-6)",
54 -7: "Repeated convergence test failures occured on the last attempted \
55 step in DASKR. An inaccurate or ill-conditioned Jacobian or \
56 preconditioner may be the problem. If you are absolutely certain you \
57 want to continue, you should restart the integration. (IDID=-7)",
58 -8: "The matrix of partial derivatives is singular, with the use of \
59 the direct methods. Some of your equations may be redundant. DDASKR \
60 cannot solve the problem as stated. It is possible that the redundant \
61 equations could be removed, and then DDASKR could solve the problem. \
62 It is also possible that a solution to your problem either does not \
63 exist or is not unique. (IDID=-8)",
64 -9: "DDASKR has multiple convergence test failures, preceded by \
65 multiple error test failures, on the last attempted step. It is \
66 possible that your problem is ill-posed and cannot be solved using \
67 this code. Or, there may be a discontinuity or a singularity in the \
68 solution. If you are absolutely certain you want to continue, you \
69 should restart the integration. (IDID=-9)",
70 -10: "DDASKR had multiple convergence test failures because IRES was \
71 equal to -1. If you are absolutely certain you want to continue, you \
72 should restart the integration. (IDID=-10)",
73 -11: "There was an unrecoverable error (IRES=-2) from RES inside the \
74 nonlinear system solver. Determine the cause before trying again. \
75 (IDID=-11)",
76 -12: "DDASKR failed to compute the initial Y and YPRIME vectors. \
77 This could happed because the initial approximation to Y or YPRIME \
78 was not very good, or because no consistent values of these vectors \
79 exist. The problem could also be caused by an inaccurate or singular \
80 iteration matrix, or a poor preconditioner. (IDID=-12)",
81 -13: "There was an unrecoverable error encountered inside your PSOL \
82 routine. Determine the cause before trying again. (IDID=-13)",
83 -14: "The Krylove linear solver failed to achieve convergence. \
84 (IDID=-14)",
85 -33: "You cannot continue the solution of this problem. An attempt to \
86 do so will result in your run being terminated. (IDID=-33)",
87 }
88
89 redir = Utility.Redirector()
90
93
94
95 -def daeint(res, t, y0, yp0, rtol, atol, nrt = 0, rt = None, jac = None,
96 tstop=None, intermediate_output=False, ineq_constr=False,
97 calculate_ic=False, var_types=None, redir_output=True,
98 max_steps=500, rpar=None, hmax=None):
99 """Integrate a system of ordinary differential algebraic equations with or
100 without events.
101
102 Description:
103
104 Solve a system of ordinary differential algebraic equations using the
105 FORTRAN library DDASKR.
106
107 Uses the backward differentiation formulas of orders one through five
108 to solve a system of the form G(T,Y,Y') = 0 where Y can be a vector.
109
110 Values for Y and Y' at the initial time must be given as input. These
111 values should be consistent, that is, if t0, y0, yp0 are the given
112 initial values, they should satisfy G(t0,y0,yp0) = 0. However, if
113 consistent values are not known, in many cases you can have DDASKR
114 solve for them if the appropriate option in the info array is set.
115
116 Normally, DDASKR solves the system from some intial t0 to a specified
117 tout. This wrapper takes a list of times t as input, and then solves
118 the system for the range of times. In the interval mode of operation,
119 only the solution values at time points in t will be returned.
120 Intermediate results can also be obtained easily by specifying info(3).
121
122 While integrating the given DAE system, DDASKR also searches for roots
123 of the given constraint functions Ri(T,Y,Y') given by RT. If DDASKR
124 detects a sign change in any Ri(T,Y,Y'), it will return the intermediate
125 value of T and Y for which Ri(T,Y,Y') = 0.
126
127 Caution: If some Ri has a root at or very near the initial time, DDASKR
128 may fail to find it, or may find extraneous roots there, because it does
129 not yet have a sufficient history of the solution.
130
131 Inputs:
132
133 res -- res(t, y, ...) computes the residual function for the
134 differential/algebraic system to be solved.
135 t -- a sequence of time points for which to solve for y. The intial
136 value of the dependent variable(s) y should correspond to the
137 first time in this sequence.
138 y0 -- this array must contain the initial values of the NEQ solution
139 components at the initial time point (note NEQ is defined as the
140 length of this array).
141 yp0 -- this array must contain the initial values of the NEQ first
142 derivatives of the solution components at the initial time point.
143 jac -- this is the name of a routine that you may supply that relates to
144 the Jacobian matrix of the nonlinear system that the code must
145 solve at each time step.
146 rtol -- array of relative error tolerances (must be non-negative).
147 atol -- array of absolute error tolerances (must be non-negative).
148 rt -- this is the name of the subroutine for defining the vector
149 Ri(T, Y, Y') of constraint functions.
150 nrt -- the number of constraint functions Ri(T, Y, Y').
151 jac -- the name of a routine that you may supply (optionally) that
152 relactes to the Jacobian matrix of the nonlinear system that the
153 code must solve at each time step. If no Jacobian is passed then
154 the system will automatically use a numerical Jacobian.
155 args -- parameter for passing extra information to the wrapper.
156 tstop -- sometimes it is not possible to integrate past some point tstop
157 because the equation changes there or it is not defined past
158 tstop. if tstop is set the integrator will not integrate past
159 tstop. NOTE: If you select a tstop, the integrator may skip
160 some points in your list of time points, t. This is because it
161 may pass tstop before hitting all the points in the list of times
162 for an integration that is progressing quickly.
163 intermediate_output -- True to have all output returned.
164 ineq_constr -- True to have inequality constraint checking on.
165 If True, the code will check for non-negativity in Y during the
166 integration (not during initial condition calculations).
167 calculate_ic -- True to have the DDASKR automatically calculate
168 consistent initial conditions. Given Y_d, the code will
169 calculate Y_a and Y'_d (note: you must also pass var_types
170 to indicate which variables are algebraic and which are
171 differential). We do not use the functionality of daskr
172 that allows calculation of Y given Y'.
173 var_types -- this list tells whether each variable in the system is
174 differential or algebraic. Vor a variable Yi, var_types[i] = +1 if
175 Yi is differential, and var_types[i] = -1 if it is algebraic.
176 redir_output -- False to have print statements from DASKR printed to the
177 standard output. If redir_output is True, the output will be
178 redirected.
179 max_steps -- set this if you want the integrator to be able to take more
180 than 500 steps between time points when you're not in
181 "intermediate output" mode. If intermediate_output = True then
182 every time step is considered an output point so there are never
183 multiple steps between time points. If intermediate_output =
184 False (default) then the integrator will stop after taking 500
185 steps unless max_steps is set > 500. The default value for
186 max_steps is 500.
187 rpar -- If not None, this sequence is passed to the function being
188 evaluated and can be used to pass additional arguments.
189 hmax -- If not None, this sets an upper limit to the step sizes that
190 ddaskr will take during the integration. Setting this can help
191 integration for difficult systems, but it can also slow things
192 down.
193
194 Outputs: (yout, tout, ypout, t_root, y_root, i_root)
195
196 yout -- the numerically calculated list of solution points corresponding
197 to the times in tout.
198 tout -- the list of time points corresponding to yout.
199 ypout -- the numerically calculated list of solution points corresponding
200 to the times in tout.
201 t_root -- the time of a terminating event.
202 y_root -- the system state at time t_root.
203 i_root -- tells which event(s) fired and how they fired.
204 If i_root(i) = 0, then event i did not fire. If nonzero,
205 i_root(i) shows the direction of the sign change in Ri.
206 i_root(i) = 1 means Ri changed from negative to positive.
207 i_root(i) = -1 means Ri changed from positive to negative.
208
209 """
210
211 if scipy.isscalar(rpar):
212 raise ValueError('rpar must be a sequence.')
213
214 if rpar is None or len(rpar) == 0:
215
216 rpar = scipy.empty(1)
217
218 y = y0
219 yp = yp0
220 ires = 0
221
222
223
224
225 neq = len(y0)
226
227 ipar = [neq, len(rpar)]
228
229
230
231
232 MAXORD = 5
233 BASEr = 60+max(MAXORD+4,7)*neq+3*nrt
234 BASEi = 40
235
236 LRW = BASEr + (neq**2)
237 LIW = BASEi + 2*neq
238
239
240
241 rwork = scipy.zeros(LRW, scipy.float64)
242 iwork = scipy.zeros(LIW, scipy.int32)
243
244
245
246
247 info = scipy.zeros(20, scipy.int32)
248
249
250
251
252
253 info[0] = 0
254
255
256
257 info[1] = 1
258
259
260 if scipy.isscalar(rtol) or len(rtol) != neq:
261 raise ValueError('rtol must be an array or a vector with same length '
262 'as number of equations.')
263 if scipy.isscalar(atol) or len(atol) != neq:
264 raise ValueError('atol must be an array or a vector with same length '
265 'as number of equations.')
266
267
268
269 if intermediate_output == False:
270 info[2] = 0
271 elif intermediate_output == True:
272 info[2] = 1
273 else:
274 raise ValueError('int_output must be True or False.')
275
276
277
278 if tstop == None:
279 info[3] = 0
280 else:
281
282
283 if tstop < t[-1]:
284 raise ValueError('tstop must be greater than or equal to the '
285 'final time point requested.')
286 info[3] = 1
287 rwork[0] = tstop
288
289
290
291
292 EVENT_INT_BUG_WORKAROUND = False
293 if intermediate_output and nrt:
294 EVENT_INT_BUG_WORKAROUND = True
295
296
297
298 if jac == None:
299 info[4] = 0
300 jac = dummy_func
301 else:
302 info[4] = 1
303
304
305 if hmax is not None:
306 info[7] = 1
307 rwork[2] = hmax
308
309
310
311
312
313
314
315
316 LID = 0
317 if ineq_constr == False:
318 info[9] = 0
319 LID = 40
320
321
322
323 elif ineq_constr == True:
324 info[9] = 2
325 LID = 40
326
327
328
329 else:
330 raise ValueError, 'ineq_constr must be True or False.'
331
332
333
334 if calculate_ic == False:
335 info[10] = 0
336
337
338 elif calculate_ic == True:
339 info[10] = 1
340
341 if var_types == None:
342 raise ValueError('if calculate_ic = 1, the var_types array '
343 'must be passed.')
344 elif len(var_types) != len(y0):
345 raise ValueError('var_types must be of length len(y0)')
346 else:
347
348
349 for ii in range(len(var_types)):
350 if var_types[ii] == +1:
351 iwork[LID+ii] = +1
352 elif var_types[ii] == -1:
353 iwork[LID+ii] = -1
354 else:
355 raise ValueError('the var_types array may only contain '
356 'entries of +1 or -1.')
357
358
359
360
361
362
363
364
365
366
367 info[13] = 1
368
369
370
371
372
373 info[15] = 0
374
375
376
377
378 info[16] = 0
379
380
381
382
383 if rt == None:
384 rt = dummy_func
385
386
387 psol = dummy_func
388
389
390
391 idid = 1
392 t0, tindex = t[0], 1
393 tout, yout = t0, y0
394 t_root, y_root, i_root = [], [], []
395
396
397 tout_l = []
398 yout_l = []
399 ypout_l= []
400
401
402
403 if calculate_ic == False:
404 tout_l.append(t0)
405 yout_l.append(y0)
406 ypout_l.append(yp0)
407
408
409 tcurrent = t0
410
411
412
413 step_count = 0
414
415 if redir_output == True:
416 redir.start()
417
418 if hasattr(res, '_cpointer'):
419 res = res._cpointer
420 if hasattr(jac, '_cpointer'):
421 jac = jac._cpointer
422 if hasattr(rt, '_cpointer'):
423 rt = rt._cpointer
424
425 try:
426 while tcurrent < t[-1]:
427
428 twanted = t[tindex]
429 if EVENT_INT_BUG_WORKAROUND:
430 info[3] = 1
431 if tstop and tstop < twanted:
432 rwork[0] = tstop
433 else:
434 rwork[0] = twanted
435
436
437 treached, y, yp, idid, jroot = \
438 _daskr.ddaskr(res, tcurrent, y, yp, twanted,
439 info, rtol, atol,
440 rwork, iwork,
441 rpar, ipar,
442 jac, psol, rt, nrt)
443
444
445
446 if idid <= 0:
447
448 info[0]=1
449
450 if idid < -1:
451 messages = redir.stop()
452
453 if messages is not None:
454 logger.warn(messages)
455 logger.warn(_msgs[idid])
456
457
458
459 elif idid == -1:
460
461
462
463 if max_steps > step_count:
464 step_count += 500
465 continue
466 elif max_steps <= step_count:
467 messages = redir.stop()
468
469 if messages is not None:
470 logger.warn(messages)
471 logger.warn(_msgs[idid])
472
473
474
475
476
477
478
479
480
481 if len(yout_l) == 0:
482 yout_l = scipy.zeros((0, len(y0)), scipy.float_)
483 ypout_l = scipy.zeros((0, len(y0)), scipy.float_)
484 outputs = (scipy.array(yout_l), scipy.array(tout_l),
485 scipy.array(ypout_l),
486 t_root, y_root, i_root)
487 raise daeintException(_msgs[idid], outputs)
488
489
490
491 else:
492
493
494 step_count = 0
495
496
497
498
499
500 tout_l.append(treached)
501 yout_l.append(y)
502 ypout_l.append(yp)
503
504
505 tcurrent = treached
506
507
508 if treached == t[tindex]:
509
510 tindex += 1
511
512
513 if idid == 2:
514 break
515
516
517
518
519
520 if idid == 4:
521 info[13] = 0
522 calculate_ic = False
523
524
525
526 elif idid == 5:
527 t_root = tcurrent
528 y_root = y
529 i_root = jroot
530
531
532 break
533
534
535
536 tout_l = scipy.array(tout_l)
537 yout_l = scipy.array(yout_l)
538 ypout_l = scipy.array(ypout_l)
539
540
541 outputs = (yout_l, tout_l, ypout_l, t_root, y_root, i_root)
542
543 return outputs
544
545 finally:
546 messages = redir.stop()
547