changelog shortlog tags changeset files revisions annotate raw

src/DLD-FUNCTIONS/daspk.cc

changeset 10289: 4b124317dc38
parent:40dfc0c99116
author: John W. Eaton <jwe@octave.org>
date: Tue Feb 09 20:58:55 2010 -0500 (66 minutes ago)
permissions: -rw-r--r--
description: base_properties::set_children: account for hidden children
1/*
2
3Copyright (C) 1996, 1997, 2002, 2003, 2004, 2005, 2006, 2007, 2009
4 John W. Eaton
5
6This file is part of Octave.
7
8Octave is free software; you can redistribute it and/or modify it
9under the terms of the GNU General Public License as published by the
10Free Software Foundation; either version 3 of the License, or (at your
11option) any later version.
12
13Octave is distributed in the hope that it will be useful, but WITHOUT
14ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16for more details.
17
18You should have received a copy of the GNU General Public License
19along with Octave; see the file COPYING. If not, see
20<http://www.gnu.org/licenses/>.
21
22*/
23
24#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
27
28#include <string>
29
30#include <iomanip>
31#include <iostream>
32
33#include "DASPK.h"
34
35#include "defun-dld.h"
36#include "error.h"
37#include "gripes.h"
38#include "oct-obj.h"
39#include "ov-fcn.h"
40#include "ov-cell.h"
41#include "pager.h"
42#include "unwind-prot.h"
43#include "utils.h"
44#include "variables.h"
45
46#include "DASPK-opts.cc"
47
48// Global pointer for user defined function required by daspk.
49static octave_function *daspk_fcn;
50
51// Global pointer for optional user defined jacobian function.
52static octave_function *daspk_jac;
53
54// Have we warned about imaginary values returned from user function?
55static bool warned_fcn_imaginary = false;
56static bool warned_jac_imaginary = false;
57
58// Is this a recursive call?
59static int call_depth = 0;
60
61ColumnVector
62daspk_user_function (const ColumnVector& x, const ColumnVector& xdot,
63 double t, octave_idx_type& ires)
64{
65 ColumnVector retval;
66
67 assert (x.capacity () == xdot.capacity ());
68
69 octave_value_list args;
70
71 args(2) = t;
72 args(1) = xdot;
73 args(0) = x;
74
75 if (daspk_fcn)
76 {
77 octave_value_list tmp = daspk_fcn->do_multi_index_op (1, args);
78
79 if (error_state)
80 {
81 gripe_user_supplied_eval ("daspk");
82 return retval;
83 }
84
85 int tlen = tmp.length ();
86 if (tlen > 0 && tmp(0).is_defined ())
87 {
88 if (! warned_fcn_imaginary && tmp(0).is_complex_type ())
89 {
90 warning ("daspk: ignoring imaginary part returned from user-supplied function");
91 warned_fcn_imaginary = true;
92 }
93
94 retval = ColumnVector (tmp(0).vector_value ());
95
96 if (tlen > 1)
97 ires = tmp(1).int_value ();
98
99 if (error_state || retval.length () == 0)
100 gripe_user_supplied_eval ("daspk");
101 }
102 else
103 gripe_user_supplied_eval ("daspk");
104 }
105
106 return retval;
107}
108
109Matrix
110daspk_user_jacobian (const ColumnVector& x, const ColumnVector& xdot,
111 double t, double cj)
112{
113 Matrix retval;
114
115 assert (x.capacity () == xdot.capacity ());
116
117 octave_value_list args;
118
119 args(3) = cj;
120 args(2) = t;
121 args(1) = xdot;
122 args(0) = x;
123
124 if (daspk_jac)
125 {
126 octave_value_list tmp = daspk_jac->do_multi_index_op (1, args);
127
128 if (error_state)
129 {
130 gripe_user_supplied_eval ("daspk");
131 return retval;
132 }
133
134 int tlen = tmp.length ();
135 if (tlen > 0 && tmp(0).is_defined ())
136 {
137 if (! warned_jac_imaginary && tmp(0).is_complex_type ())
138 {
139 warning ("daspk: ignoring imaginary part returned from user-supplied jacobian function");
140 warned_jac_imaginary = true;
141 }
142
143 retval = tmp(0).matrix_value ();
144
145 if (error_state || retval.length () == 0)
146 gripe_user_supplied_eval ("daspk");
147 }
148 else
149 gripe_user_supplied_eval ("daspk");
150 }
151
152 return retval;
153}
154
155#define DASPK_ABORT() \
156 return retval
157
158#define DASPK_ABORT1(msg) \
159 do \
160 { \
161 ::error ("daspk: " msg); \
162 DASPK_ABORT (); \
163 } \
164 while (0)
165
166#define DASPK_ABORT2(fmt, arg) \
167 do \
168 { \
169 ::error ("daspk: " fmt, arg); \
170 DASPK_ABORT (); \
171 } \
172 while (0)
173
174DEFUN_DLD (daspk, args, nargout,
175 "-*- texinfo -*-\n\
176@deftypefn {Loadable Function} {[@var{x}, @var{xdot}, @var{istate}, @var{msg}] =} daspk (@var{fcn}, @var{x_0}, @var{xdot_0}, @var{t}, @var{t_crit})\n\
177Solve the set of differential-algebraic equations\n\
178@tex\n\
179$$ 0 = f (x, \\dot{x}, t) $$\n\
180with\n\
181$$ x(t_0) = x_0, \\dot{x}(t_0) = \\dot{x}_0 $$\n\
182@end tex\n\
183@ifnottex\n\
184\n\
185@example\n\
1860 = f (x, xdot, t)\n\
187@end example\n\
188\n\
189with\n\
190\n\
191@example\n\
192x(t_0) = x_0, xdot(t_0) = xdot_0\n\
193@end example\n\
194\n\
195@end ifnottex\n\
196The solution is returned in the matrices @var{x} and @var{xdot},\n\
197with each row in the result matrices corresponding to one of the\n\
198elements in the vector @var{t}. The first element of @var{t}\n\
199should be @math{t_0} and correspond to the initial state of the\n\
200system @var{x_0} and its derivative @var{xdot_0}, so that the first\n\
201row of the output @var{x} is @var{x_0} and the first row\n\
202of the output @var{xdot} is @var{xdot_0}.\n\
203\n\
204The first argument, @var{fcn}, is a string, inline, or function handle\n\
205that names the function @math{f} to call to compute the vector of\n\
206residuals for the set of equations. It must have the form\n\
207\n\
208@example\n\
209@var{res} = f (@var{x}, @var{xdot}, @var{t})\n\
210@end example\n\
211\n\
212@noindent\n\
213in which @var{x}, @var{xdot}, and @var{res} are vectors, and @var{t} is a\n\
214scalar.\n\
215\n\
216If @var{fcn} is a two-element string array or a two-element cell array\n\
217of strings, inline functions, or function handles, the first element names\n\
218the function @math{f} described above, and the second element names a\n\
219function to compute the modified Jacobian\n\
220@tex\n\
221$$\n\
222J = {\\partial f \\over \\partial x}\n\
223 + c {\\partial f \\over \\partial \\dot{x}}\n\
224$$\n\
225@end tex\n\
226@ifnottex\n\
227\n\
228@example\n\
229@group\n\
230 df df\n\
231jac = -- + c ------\n\
232 dx d xdot\n\
233@end group\n\
234@end example\n\
235@end ifnottex\n\
236\n\
237The modified Jacobian function must have the form\n\
238\n\
239@example\n\
240@group\n\
241\n\
242@var{jac} = j (@var{x}, @var{xdot}, @var{t}, @var{c})\n\
243\n\
244@end group\n\
245@end example\n\
246\n\
247The second and third arguments to @code{daspk} specify the initial\n\
248condition of the states and their derivatives, and the fourth argument\n\
249specifies a vector of output times at which the solution is desired,\n\
250including the time corresponding to the initial condition.\n\
251\n\
252The set of initial states and derivatives are not strictly required to\n\
253be consistent. If they are not consistent, you must use the\n\
254@code{daspk_options} function to provide additional information so\n\
255that @code{daspk} can compute a consistent starting point.\n\
256\n\
257The fifth argument is optional, and may be used to specify a set of\n\
258times that the DAE solver should not integrate past. It is useful for\n\
259avoiding difficulties with singularities and points where there is a\n\
260discontinuity in the derivative.\n\
261\n\
262After a successful computation, the value of @var{istate} will be\n\
263greater than zero (consistent with the Fortran version of @sc{Daspk}).\n\
264\n\
265If the computation is not successful, the value of @var{istate} will be\n\
266less than zero and @var{msg} will contain additional information.\n\
267\n\
268You can use the function @code{daspk_options} to set optional\n\
269parameters for @code{daspk}.\n\
270@seealso{dassl}\n\
271@end deftypefn")
272{
273 octave_value_list retval;
274
275 warned_fcn_imaginary = false;
276 warned_jac_imaginary = false;
277
278 unwind_protect frame;
279
280 frame.protect_var (call_depth);
281 call_depth++;
282
283 if (call_depth > 1)
284 DASPK_ABORT1 ("invalid recursive call");
285
286 int nargin = args.length ();
287
288 if (nargin > 3 && nargin < 6)
289 {
290 std::string fcn_name, fname, jac_name, jname;
291 daspk_fcn = 0;
292 daspk_jac = 0;
293
294 octave_value f_arg = args(0);
295
296 if (f_arg.is_cell ())
297 {
298 Cell c = f_arg.cell_value ();
299 if (c.length() == 1)
300 f_arg = c(0);
301 else if (c.length() == 2)
302 {
303 if (c(0).is_function_handle () || c(0).is_inline_function ())
304 daspk_fcn = c(0).function_value ();
305 else
306 {
307 fcn_name = unique_symbol_name ("__daspk_fcn__");
308 fname = "function y = ";
309 fname.append (fcn_name);
310 fname.append (" (x, xdot, t) y = ");
311 daspk_fcn = extract_function
312 (c(0), "daspk", fcn_name, fname, "; endfunction");
313 }
314
315 if (daspk_fcn)
316 {
317 if (c(1).is_function_handle () || c(1).is_inline_function ())
318 daspk_jac = c(1).function_value ();
319 else
320 {
321 jac_name = unique_symbol_name ("__daspk_jac__");
322 jname = "function jac = ";
323 jname.append(jac_name);
324 jname.append (" (x, xdot, t, cj) jac = ");
325 daspk_jac = extract_function
326 (c(1), "daspk", jac_name, jname, "; endfunction");
327
328 if (!daspk_jac)
329 {
330 if (fcn_name.length())
331 clear_function (fcn_name);
332 daspk_fcn = 0;
333 }
334 }
335 }
336 }
337 else
338 DASPK_ABORT1 ("incorrect number of elements in cell array");
339 }
340
341 if (!daspk_fcn && ! f_arg.is_cell())
342 {
343 if (f_arg.is_function_handle () || f_arg.is_inline_function ())
344 daspk_fcn = f_arg.function_value ();
345 else
346 {
347 switch (f_arg.rows ())
348 {
349 case 1:
350 do
351 {
352 fcn_name = unique_symbol_name ("__daspk_fcn__");
353 fname = "function y = ";
354 fname.append (fcn_name);
355 fname.append (" (x, xdot, t) y = ");
356 daspk_fcn = extract_function
357 (f_arg, "daspk", fcn_name, fname, "; endfunction");
358 }
359 while (0);
360 break;
361
362 case 2:
363 {
364 string_vector tmp = f_arg.all_strings ();
365
366 if (! error_state)
367 {
368 fcn_name = unique_symbol_name ("__daspk_fcn__");
369 fname = "function y = ";
370 fname.append (fcn_name);
371 fname.append (" (x, xdot, t) y = ");
372 daspk_fcn = extract_function
373 (tmp(0), "daspk", fcn_name, fname, "; endfunction");
374
375 if (daspk_fcn)
376 {
377 jac_name = unique_symbol_name ("__daspk_jac__");
378 jname = "function jac = ";
379 jname.append(jac_name);
380 jname.append (" (x, xdot, t, cj) jac = ");
381 daspk_jac = extract_function
382 (tmp(1), "daspk", jac_name, jname,
383 "; endfunction");
384
385 if (!daspk_jac)
386 {
387 if (fcn_name.length())
388 clear_function (fcn_name);
389 daspk_fcn = 0;
390 }
391 }
392 }
393 }
394 }
395 }
396 }
397
398 if (error_state || ! daspk_fcn)
399 DASPK_ABORT ();
400
401 ColumnVector state = ColumnVector (args(1).vector_value ());
402
403 if (error_state)
404 DASPK_ABORT1 ("expecting state vector as second argument");
405
406 ColumnVector deriv (args(2).vector_value ());
407
408 if (error_state)
409 DASPK_ABORT1 ("expecting derivative vector as third argument");
410
411 ColumnVector out_times (args(3).vector_value ());
412
413 if (error_state)
414 DASPK_ABORT1 ("expecting output time vector as fourth argument");
415
416 ColumnVector crit_times;
417 int crit_times_set = 0;
418 if (nargin > 4)
419 {
420 crit_times = ColumnVector (args(4).vector_value ());
421
422 if (error_state)
423 DASPK_ABORT1 ("expecting critical time vector as fifth argument");
424
425 crit_times_set = 1;
426 }
427
428 if (state.capacity () != deriv.capacity ())
429 DASPK_ABORT1 ("x and xdot must have the same size");
430
431 double tzero = out_times (0);
432
433 DAEFunc func (daspk_user_function);
434 if (daspk_jac)
435 func.set_jacobian_function (daspk_user_jacobian);
436
437 DASPK dae (state, deriv, tzero, func);
438 dae.set_options (daspk_opts);
439
440 Matrix output;
441 Matrix deriv_output;
442
443 if (crit_times_set)
444 output = dae.integrate (out_times, deriv_output, crit_times);
445 else
446 output = dae.integrate (out_times, deriv_output);
447
448 if (fcn_name.length())
449 clear_function (fcn_name);
450 if (jac_name.length())
451 clear_function (jac_name);
452
453 if (! error_state)
454 {
455 std::string msg = dae.error_message ();
456
457 retval(3) = msg;
458 retval(2) = static_cast<double> (dae.integration_state ());
459
460 if (dae.integration_ok ())
461 {
462 retval(1) = deriv_output;
463 retval(0) = output;
464 }
465 else
466 {
467 retval(1) = Matrix ();
468 retval(0) = Matrix ();
469
470 if (nargout < 3)
471 error ("daspk: %s", msg.c_str ());
472 }
473 }
474 }
475 else
476 print_usage ();
477
478 return retval;
479}