Fix one minor typo in patch.
[maxima.git] / share / odepack / dlsode-interface.lisp
blob3db5c6de6be35e72b261b6391058e367f98d12bd
1 (in-package #:maxima)
3 ;; Initialize for DLSODE. This must be called before running DLSODE_STEP.
4 ;;
5 ;; Parameters:
6 ;; f - list of differential equations to be solved
7 ;; vars - list of the independent variable and the dependent
8 ;; variables. The order of the dependent variables must be
9 ;; in the same order as the equations in f.
11 ;; mf - method to be used. It should be one of the following
12 ;; values:
14 ;; 10 Nonstiff (Adams) method, no Jacobian used.
15 ;; 21 Stiff (BDF) method, user-supplied full Jacobian.
16 ;; 22 Stiff method, internally generated full
17 ;; Jacobian.
18 ;; The Fortran version of DLSODE supports additional
19 ;; methods, but these are not supported here.
20 ;; Output:
21 ;; A state object is created that should be used as the state
22 ;; parameter in DLSODE_STEP. The user must not modify these. The
23 ;; output includes the equations, the set of variables, the mf
24 ;; parameter, and various work arrays that must be modified between
25 ;; calls to dlsode_step.
26 (defmfun $dlsode_init (f vars mf)
27 ;; Verify values of mf.
28 (unless (member mf '(10 21 22) :test #'eql)
29 (merror "MF must be 10, 21, or 22"))
30 (let* ((neq (length (cdr f)))
31 (lrw (ecase mf
32 (10
33 (+ 20 (* 16 neq)))
34 ((21 22)
35 (+ 22 (* 9 neq) (* neq neq)))))
36 (rwork (make-array lrw :element-type 'flonum))
37 (liw (ecase mf
38 (10
39 20)
40 ((21 22)
41 (+ 20 neq))))
42 (iwork (make-array liw :element-type 'f2cl-lib:integer4))
43 (fjac (when (= mf 21)
44 ;; Jacobian is needed only for mf = 21, so compute only then.
45 (compile nil
46 (coerce-float-fun
47 (meval `(($jacobian) ,f ,(list* '(mlist) (cddr vars))))
48 vars)))))
49 ;; Make sure neq is consistent with the number of elements in f
50 ;; and vars
51 (unless (= (1+ neq) ($length vars))
52 (merror "Expected ~M variables but got ~M: ~M"
53 (1+ neq) ($length vars) vars))
54 (make-mlist
55 (make-mlist '$f (compile nil (coerce-float-fun f vars)))
56 (make-mlist '$vars vars)
57 (make-mlist '$mf mf)
58 (make-mlist '$neq neq)
59 (make-mlist '$lrw lrw)
60 (make-mlist '$liw liw)
61 (make-mlist '$rwork rwork)
62 (make-mlist '$iwork iwork)
63 (make-mlist '$fjac fjac))))
65 ;; Main DLSODE routine to compute each output point. Must be called
66 ;; after DLSODE_INIT.
68 ;; For full details see comments in fortran/dlsode.f
70 ;; Parameters:
72 ;; init-y - For the first call (when istate = 1), the initial values
73 ;; tt - Value of the independent value
74 ;; tout - Next point where output is desired (/= tt)
75 ;; rtol - relative tolerance parameter
77 ;; atol - Absolute tolerance parameter, scalar of vector. If
78 ;; scalar, it applies to all dependent variables.
79 ;; Otherwise it must be the tolerance for each dependent
80 ;; variable.
82 ;; Use rtol = 0 for pure absolute error and use atol = 0
83 ;; for pure relative error.
84 ;;
85 ;; istate - 1 for the first call to dlsode, 2 for subsequent calls.
86 ;; state - state returned by dlsode-init.
88 ;; Output:
89 ;; A list consisting of the following items:
90 ;; t - independent variable value
91 ;; y - list of values of the dependent variables at time t.
92 ;; istate - Integration status:
93 ;; 1 - no work because tout = tt
94 ;; 2 - successful result
95 ;; -1 - Excess work done on this call
96 ;; -2 - Excess accuracy requested
97 ;; -3 - Illegal input detected
98 ;; -4 - Repeated error test failures
99 ;; -5 - Repeated convergence failures (perhaps bad
100 ;; Jacobian or wrong choice of mf or tolerances)
101 ;; -6 - Error weight because zero during problem
102 ;; (solution component i vanishded and atol(i) = 0.
103 ;; info - association list of various bits of information:
104 ;; n_steps - total steps taken thus far
105 ;; n_f_eval - total number of function evals
106 ;; n_j_eval - total number of Jacobian evals
107 ;; method_order - method order
108 ;; len_rwork - Actual length used for real work array
109 ;; len_iwork - Actual length used for integer work array
111 (defmfun $dlsode_step (init-y tt tout rtol atol istate state)
112 (let ((f ($assoc '$f state))
113 (vars ($assoc '$vars state))
114 (mf ($assoc '$mf state))
115 (neq ($assoc '$neq state))
116 (lrw ($assoc '$lrw state))
117 (liw ($assoc '$liw state))
118 (rwork ($assoc '$rwork state))
119 (iwork ($assoc '$iwork state))
120 (fjac ($assoc '$fjac state)))
121 ;; Verify that we got something from state. (Do we need more validation?)
122 (unless (and f vars mf neq lrw liw rwork iwork)
123 (merror "State appears to be invalid"))
124 (let* ((ff f)
125 (itol (if (listp atol)
128 (y-array (make-array (1- (length init-y))
129 :element-type 'double-float
130 :initial-contents (cdr ($float init-y)))))
131 #+nil
132 (progn
133 (format t "vars = ~S~%" vars)
134 (format t "ff = ~S~%" ff)
135 (format t "fjac = ~S~%" fjac))
136 (flet ((fex (neq tt y ydot)
137 (declare (type double-float tt)
138 (type (cl:array double-float (*)) y ydot)
139 (ignore neq))
140 (let* ((y-list (coerce y 'list))
141 (yval (cl:apply ff tt y-list)))
142 #+nil
143 (progn
144 (format t "fex: t = ~S; y = ~S~%" tt y)
145 (format t " yval = ~S~%" yval)
146 (format t " ydot = ~S~%" ydot))
147 (replace ydot (cdr yval))))
148 (jex (neq tt y ml mu pd nrpd)
149 (declare (type f2cl-lib:integer4 ml mu nrpd)
150 (type double-float tt)
151 (type (cl:array double-float (*)) y)
152 (type (cl:array double-float *) pd)
153 (ignore neq ml mu))
154 #+nil
155 (progn
156 (format t "jex: tt = ~S; y = ~S~%" tt y)
157 (format t " ml, mu = ~S ~S~%" ml mu)
158 (format t " pd = ~S~%" pd)
159 (format t " nrpd = ~S~%" nrpd)
160 (format t " fjac = ~S~%" fjac))
161 (let* ((y-list (coerce y 'list))
162 (j (cl:apply fjac tt y-list))
163 (row 1))
164 #+nil
165 (progn
166 (format t " y-list = ~S~%" y-list)
167 (format t " j = ~S~%" j))
168 (dolist (r (cdr j))
169 (let ((col 1))
170 (dolist (c (cdr r))
171 (setf (f2cl-lib:fref pd (row col) ((1 nrpd) (1)))
173 (incf col)))
174 (incf row))
175 #+nil
176 (format t "pd = ~S~%" pd))))
178 (multiple-value-bind (ign-0 ign-1 ign-2
179 ret-tout
180 ign-5 ign-6 ign-7 ign-8 ign-9
181 ret-istate)
182 (odepack:dlsode #'fex
183 (make-array 1 :element-type 'f2cl-lib:integer4
184 :initial-element neq)
185 y-array
187 tout
188 itol
189 (make-array 1 :element-type 'double-float
190 :initial-element ($float rtol))
191 (if (listp atol)
192 (make-array (1- (length atol))
193 :element-type 'double-float
194 :initial-contents (rest ($float atol)))
195 (make-array 1 :element-type 'double-float
196 :initial-element ($float atol)))
197 1 ;; itask
198 istate
199 0 ;; iopt
200 rwork
202 iwork
204 #'jex
206 (declare (ignore ign-0 ign-1 ign-2 ign-5 ign-6 ign-7 ign-8 ign-9))
208 (list '(mlist)
209 ret-tout
210 (list* '(mlist)
211 (coerce y-array 'list))
212 ret-istate
213 (make-mlist
214 (make-mlist '$n_steps (aref iwork 10))
215 (make-mlist '$n_f_eval (aref iwork 11))
216 (make-mlist '$n_j_eval (aref iwork 12))
217 (make-mlist '$method_order (aref iwork 13))
218 (make-mlist '$len_rwork (aref iwork 16))
219 (make-mlist '$len_iwork (aref iwork 17)))))))))
221 (defmfun $dlsode (f yvars inity trange rtol atol mf)
222 (let* ((tvar (elt trange 1))
223 (tstart ($float (elt trange 2)))
224 (tend ($float (elt trange 3)))
225 (tstep ($float (elt trange 4)))
226 (vars ($cons tvar yvars))
227 (state ($dlsode_init f vars mf))
228 result)
229 (loop for tout from tstart upto tend by tstep
231 (let ((r ($dlsode_step inity tstart tout rtol atol 1 state)))
232 (when (minusp (elt r 3))
233 ;; See dlsode.f for the definitions for these values.
234 (merror "Error ~M: ~M"
235 (elt r 3)
236 (ecase (elt r 3)
238 "Excess work done on this call (perhaps wrong MF")
240 "Excess accuracy requested (tolerances too small)")
242 "Illegal input detected (see printed message)")
244 "Repeated error test failures (check all inputs)")
246 "Repeated convergence failures (perhaps bad Jacobian supplied or wrong choice of MF or tolerances)")
248 "Error weight became zero during problem (solution component i vanished, and ATOL or ATOL(i) = 0.)"))))
249 (push ($cons (elt r 1) (elt r 2))
250 result)))
251 (list* '(mlist)
252 (nreverse result))))