changelog shortlog tags changeset files revisions annotate raw

src/DLD-FUNCTIONS/dasrt.cc

changeset 10289: 4b124317dc38
parent:40dfc0c99116
author: John W. Eaton <jwe@octave.org>
date: Tue Feb 09 20:58:55 2010 -0500 (28 minutes ago)
permissions: -rw-r--r--
description: base_properties::set_children: account for hidden children
1/*
2
3Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2009 John W. Eaton
4
5This file is part of Octave.
6
7Octave is free software; you can redistribute it and/or modify it
8under the terms of the GNU General Public License as published by the
9Free Software Foundation; either version 3 of the License, or (at your
10option) any later version.
11
12Octave is distributed in the hope that it will be useful, but WITHOUT
13ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along with Octave; see the file COPYING. If not, see
19<http://www.gnu.org/licenses/>.
20
21*/
22
23#ifdef HAVE_CONFIG_H
24#include <config.h>
25#endif
26
27#include <iostream>
28#include <string>
29
30#include "DASRT.h"
31#include "lo-mappers.h"
32
33#include "defun-dld.h"
34#include "error.h"
35#include "gripes.h"
36#include "oct-obj.h"
37#include "ov-fcn.h"
38#include "ov-cell.h"
39#include "pager.h"
40#include "parse.h"
41#include "unwind-prot.h"
42#include "utils.h"
43#include "variables.h"
44
45#include "DASRT-opts.cc"
46
47// Global pointers for user defined function required by dasrt.
48static octave_function *dasrt_f;
49static octave_function *dasrt_j;
50static octave_function *dasrt_cf;
51
52// Have we warned about imaginary values returned from user function?
53static bool warned_fcn_imaginary = false;
54static bool warned_jac_imaginary = false;
55static bool warned_cf_imaginary = false;
56
57// Is this a recursive call?
58static int call_depth = 0;
59
60static ColumnVector
61dasrt_user_f (const ColumnVector& x, const ColumnVector& xdot,
62 double t, octave_idx_type&)
63{
64 ColumnVector retval;
65
66 assert (x.capacity () == xdot.capacity ());
67
68 octave_value_list args;
69
70 args(2) = t;
71 args(1) = xdot;
72 args(0) = x;
73
74 if (dasrt_f)
75 {
76 octave_value_list tmp = dasrt_f->do_multi_index_op (1, args);
77
78 if (error_state)
79 {
80 gripe_user_supplied_eval ("dasrt");
81 return retval;
82 }
83
84 if (tmp.length () > 0 && tmp(0).is_defined ())
85 {
86 if (! warned_fcn_imaginary && tmp(0).is_complex_type ())
87 {
88 warning ("dasrt: ignoring imaginary part returned from user-supplied function");
89 warned_fcn_imaginary = true;
90 }
91
92 retval = ColumnVector (tmp(0).vector_value ());
93
94 if (error_state || retval.length () == 0)
95 gripe_user_supplied_eval ("dasrt");
96 }
97 else
98 gripe_user_supplied_eval ("dasrt");
99 }
100
101 return retval;
102}
103
104static ColumnVector
105dasrt_user_cf (const ColumnVector& x, double t)
106{
107 ColumnVector retval;
108
109 octave_value_list args;
110
111 args(1) = t;
112 args(0) = x;
113
114 if (dasrt_cf)
115 {
116 octave_value_list tmp = dasrt_cf->do_multi_index_op (1, args);
117
118 if (error_state)
119 {
120 gripe_user_supplied_eval ("dasrt");
121 return retval;
122 }
123
124 if (tmp.length () > 0 && tmp(0).is_defined ())
125 {
126 if (! warned_cf_imaginary && tmp(0).is_complex_type ())
127 {
128 warning ("dasrt: ignoring imaginary part returned from user-supplied constraint function");
129 warned_cf_imaginary = true;
130 }
131
132 retval = ColumnVector (tmp(0).vector_value ());
133
134 if (error_state || retval.length () == 0)
135 gripe_user_supplied_eval ("dasrt");
136 }
137 else
138 gripe_user_supplied_eval ("dasrt");
139 }
140
141 return retval;
142}
143
144static Matrix
145dasrt_user_j (const ColumnVector& x, const ColumnVector& xdot,
146 double t, double cj)
147{
148 Matrix retval;
149
150 assert (x.capacity () == xdot.capacity ());
151
152 octave_value_list args;
153
154 args(3) = cj;
155 args(2) = t;
156 args(1) = xdot;
157 args(0) = x;
158
159 if (dasrt_j)
160 {
161 octave_value_list tmp = dasrt_j->do_multi_index_op (1, args);
162
163 if (error_state)
164 {
165 gripe_user_supplied_eval ("dasrt");
166 return retval;
167 }
168
169 int tlen = tmp.length ();
170 if (tlen > 0 && tmp(0).is_defined ())
171 {
172 if (! warned_jac_imaginary && tmp(0).is_complex_type ())
173 {
174 warning ("dasrt: ignoring imaginary part returned from user-supplied jacobian function");
175 warned_jac_imaginary = true;
176 }
177
178 retval = tmp(0).matrix_value ();
179
180 if (error_state || retval.length () == 0)
181 gripe_user_supplied_eval ("dasrt");
182 }
183 else
184 gripe_user_supplied_eval ("dasrt");
185 }
186
187 return retval;
188}
189
190#define DASRT_ABORT \
191 return retval
192
193#define DASRT_ABORT1(msg) \
194 do \
195 { \
196 ::error ("dasrt: " msg); \
197 DASRT_ABORT; \
198 } \
199 while (0)
200
201#define DASRT_ABORT2(fmt, arg) \
202 do \
203 { \
204 ::error ("dasrt: " fmt, arg); \
205 DASRT_ABORT; \
206 } \
207 while (0)
208
209DEFUN_DLD (dasrt, args, nargout,
210 "-*- texinfo -*-\n\
211@deftypefn {Loadable Function} {[@var{x}, @var{xdot}, @var{t_out}, @var{istat}, @var{msg}] =} dasrt (@var{fcn} [, @var{g}], @var{x_0}, @var{xdot_0}, @var{t} [, @var{t_crit}])\n\
212Solve the set of differential-algebraic equations\n\
213@tex\n\
214$$ 0 = f (x, \\dot{x}, t) $$\n\
215with\n\
216$$ x(t_0) = x_0, \\dot{x}(t_0) = \\dot{x}_0 $$\n\
217@end tex\n\
218@ifnottex\n\
219\n\
220@example\n\
2210 = f (x, xdot, t)\n\
222@end example\n\
223\n\
224with\n\
225\n\
226@example\n\
227x(t_0) = x_0, xdot(t_0) = xdot_0\n\
228@end example\n\
229\n\
230@end ifnottex\n\
231with functional stopping criteria (root solving).\n\
232\n\
233The solution is returned in the matrices @var{x} and @var{xdot},\n\
234with each row in the result matrices corresponding to one of the\n\
235elements in the vector @var{t_out}. The first element of @var{t}\n\
236should be @math{t_0} and correspond to the initial state of the\n\
237system @var{x_0} and its derivative @var{xdot_0}, so that the first\n\
238row of the output @var{x} is @var{x_0} and the first row\n\
239of the output @var{xdot} is @var{xdot_0}.\n\
240\n\
241The vector @var{t} provides an upper limit on the length of the\n\
242integration. If the stopping condition is met, the vector\n\
243@var{t_out} will be shorter than @var{t}, and the final element of\n\
244@var{t_out} will be the point at which the stopping condition was met,\n\
245and may not correspond to any element of the vector @var{t}.\n\
246\n\
247The first argument, @var{fcn}, is a string, inline, or function handle\n\
248that names the function @math{f} to call to compute the vector of\n\
249residuals for the set of equations. It must have the form\n\
250\n\
251@example\n\
252@var{res} = f (@var{x}, @var{xdot}, @var{t})\n\
253@end example\n\
254\n\
255@noindent\n\
256in which @var{x}, @var{xdot}, and @var{res} are vectors, and @var{t} is a\n\
257scalar.\n\
258\n\
259If @var{fcn} is a two-element string array or a two-element cell array\n\
260of strings, inline functions, or function handles, the first element names\n\
261the function @math{f} described above, and the second element names a\n\
262function to compute the modified Jacobian\n\
263\n\
264@tex\n\
265$$\n\
266J = {\\partial f \\over \\partial x}\n\
267 + c {\\partial f \\over \\partial \\dot{x}}\n\
268$$\n\
269@end tex\n\
270@ifnottex\n\
271\n\
272@example\n\
273@group\n\
274 df df\n\
275jac = -- + c ------\n\
276 dx d xdot\n\
277@end group\n\
278@end example\n\
279\n\
280@end ifnottex\n\
281\n\
282The modified Jacobian function must have the form\n\
283\n\
284@example\n\
285@group\n\
286\n\
287@var{jac} = j (@var{x}, @var{xdot}, @var{t}, @var{c})\n\
288\n\
289@end group\n\
290@end example\n\
291\n\
292The optional second argument names a function that defines the\n\
293constraint functions whose roots are desired during the integration.\n\
294This function must have the form\n\
295\n\
296@example\n\
297@var{g_out} = g (@var{x}, @var{t})\n\
298@end example\n\
299\n\
300and return a vector of the constraint function values.\n\
301If the value of any of the constraint functions changes sign, @sc{Dasrt}\n\
302will attempt to stop the integration at the point of the sign change.\n\
303\n\
304If the name of the constraint function is omitted, @code{dasrt} solves\n\
305the same problem as @code{daspk} or @code{dassl}.\n\
306\n\
307Note that because of numerical errors in the constraint functions\n\
308due to roundoff and integration error, @sc{Dasrt} may return false\n\
309roots, or return the same root at two or more nearly equal values of\n\
310@var{T}. If such false roots are suspected, the user should consider\n\
311smaller error tolerances or higher precision in the evaluation of the\n\
312constraint functions.\n\
313\n\
314If a root of some constraint function defines the end of the problem,\n\
315the input to @sc{Dasrt} should nevertheless allow integration to a\n\
316point slightly past that root, so that @sc{Dasrt} can locate the root\n\
317by interpolation.\n\
318\n\
319The third and fourth arguments to @code{dasrt} specify the initial\n\
320condition of the states and their derivatives, and the fourth argument\n\
321specifies a vector of output times at which the solution is desired,\n\
322including the time corresponding to the initial condition.\n\
323\n\
324The set of initial states and derivatives are not strictly required to\n\
325be consistent. In practice, however, @sc{Dassl} is not very good at\n\
326determining a consistent set for you, so it is best if you ensure that\n\
327the initial values result in the function evaluating to zero.\n\
328\n\
329The sixth argument is optional, and may be used to specify a set of\n\
330times that the DAE solver should not integrate past. It is useful for\n\
331avoiding difficulties with singularities and points where there is a\n\
332discontinuity in the derivative.\n\
333\n\
334After a successful computation, the value of @var{istate} will be\n\
335greater than zero (consistent with the Fortran version of @sc{Dassl}).\n\
336\n\
337If the computation is not successful, the value of @var{istate} will be\n\
338less than zero and @var{msg} will contain additional information.\n\
339\n\
340You can use the function @code{dasrt_options} to set optional\n\
341parameters for @code{dasrt}.\n\
342@seealso{daspk, dasrt, lsode}\n\
343@end deftypefn")
344{
345 octave_value_list retval;
346
347 warned_fcn_imaginary = false;
348 warned_jac_imaginary = false;
349 warned_cf_imaginary = false;
350
351 unwind_protect frame;
352
353 frame.protect_var (call_depth);
354 call_depth++;
355
356 if (call_depth > 1)
357 DASRT_ABORT1 ("invalid recursive call");
358
359 int argp = 0;
360
361 int nargin = args.length ();
362
363 if (nargin < 4 || nargin > 6)
364 {
365 print_usage ();
366 return retval;
367 }
368
369 std::string fcn_name, fname, jac_name, jname;
370 dasrt_f = 0;
371 dasrt_j = 0;
372 dasrt_cf = 0;
373
374 // Check all the arguments. Are they the right animals?
375
376 // Here's where I take care of f and j in one shot:
377
378 octave_value f_arg = args(0);
379
380 if (f_arg.is_cell ())
381 {
382 Cell c = f_arg.cell_value ();
383 if (c.length() == 1)
384 f_arg = c(0);
385 else if (c.length() == 2)
386 {
387 if (c(0).is_function_handle () || c(0).is_inline_function ())
388 dasrt_f = c(0).function_value ();
389 else
390 {
391 fcn_name = unique_symbol_name ("__dasrt_fcn__");
392 fname = "function y = ";
393 fname.append (fcn_name);
394 fname.append (" (x, xdot, t) y = ");
395 dasrt_f = extract_function
396 (c(0), "dasrt", fcn_name, fname, "; endfunction");
397 }
398
399 if (dasrt_f)
400 {
401 if (c(1).is_function_handle () || c(1).is_inline_function ())
402 dasrt_j = c(1).function_value ();
403 else
404 {
405 jac_name = unique_symbol_name ("__dasrt_jac__");
406 jname = "function jac = ";
407 jname.append(jac_name);
408 jname.append (" (x, xdot, t, cj) jac = ");
409 dasrt_j = extract_function
410 (c(1), "dasrt", jac_name, jname, "; endfunction");
411
412 if (!dasrt_j)
413 {
414 if (fcn_name.length())
415 clear_function (fcn_name);
416 dasrt_f = 0;
417 }
418 }
419 }
420 }
421 else
422 DASRT_ABORT1 ("incorrect number of elements in cell array");
423 }
424
425 if (!dasrt_f && ! f_arg.is_cell())
426 {
427 if (f_arg.is_function_handle () || f_arg.is_inline_function ())
428 dasrt_f = f_arg.function_value ();
429 else
430 {
431 switch (f_arg.rows ())
432 {
433 case 1:
434 fcn_name = unique_symbol_name ("__dasrt_fcn__");
435 fname = "function y = ";
436 fname.append (fcn_name);
437 fname.append (" (x, xdot, t) y = ");
438 dasrt_f = extract_function
439 (f_arg, "dasrt", fcn_name, fname, "; endfunction");
440 break;
441
442 case 2:
443 {
444 string_vector tmp = args(0).all_strings ();
445
446 if (! error_state)
447 {
448 fcn_name = unique_symbol_name ("__dasrt_fcn__");
449 fname = "function y = ";
450 fname.append (fcn_name);
451 fname.append (" (x, xdot, t) y = ");
452 dasrt_f = extract_function
453 (tmp(0), "dasrt", fcn_name, fname, "; endfunction");
454
455 if (dasrt_f)
456 {
457 jac_name = unique_symbol_name ("__dasrt_jac__");
458 jname = "function jac = ";
459 jname.append(jac_name);
460 jname.append (" (x, xdot, t, cj) jac = ");
461 dasrt_j = extract_function
462 (tmp(1), "dasrt", jac_name, jname, "; endfunction");
463
464 if (! dasrt_j)
465 dasrt_f = 0;
466 }
467 }
468 }
469 break;
470
471 default:
472 DASRT_ABORT1
473 ("first arg should be a string or 2-element string array");
474 }
475 }
476 }
477
478 if (error_state || (! dasrt_f))
479 DASRT_ABORT;
480
481 DAERTFunc func (dasrt_user_f);
482
483 argp++;
484
485 if (args(1).is_function_handle() || args(1).is_inline_function())
486 {
487 dasrt_cf = args(1).function_value();
488
489 if (! dasrt_cf)
490 DASRT_ABORT1 ("expecting function name as argument 2");
491
492 argp++;
493
494 func.set_constraint_function (dasrt_user_cf);
495 }
496 else if (args(1).is_string ())
497 {
498 dasrt_cf = is_valid_function (args(1), "dasrt", true);
499 if (! dasrt_cf)
500 DASRT_ABORT1 ("expecting function name as argument 2");
501
502 argp++;
503
504 func.set_constraint_function (dasrt_user_cf);
505 }
506
507 ColumnVector state (args(argp++).vector_value ());
508
509 if (error_state)
510 DASRT_ABORT2 ("expecting state vector as argument %d", argp);
511
512 ColumnVector stateprime (args(argp++).vector_value ());
513
514 if (error_state)
515 DASRT_ABORT2
516 ("expecting time derivative of state vector as argument %d", argp);
517
518 ColumnVector out_times (args(argp++).vector_value ());
519
520 if (error_state)
521 DASRT_ABORT2
522 ("expecting output time vector as %s argument %d", argp);
523
524 double tzero = out_times (0);
525
526 ColumnVector crit_times;
527
528 bool crit_times_set = false;
529
530 if (argp < nargin)
531 {
532 crit_times = ColumnVector (args(argp++).vector_value ());
533
534 if (error_state)
535 DASRT_ABORT2
536 ("expecting critical time vector as argument %d", argp);
537
538 crit_times_set = true;
539 }
540
541 if (dasrt_j)
542 func.set_jacobian_function (dasrt_user_j);
543
544 DASRT_result output;
545
546 DASRT dae = DASRT (state, stateprime, tzero, func);
547
548 dae.set_options (dasrt_opts);
549
550 if (crit_times_set)
551 output = dae.integrate (out_times, crit_times);
552 else
553 output = dae.integrate (out_times);
554
555 if (fcn_name.length())
556 clear_function (fcn_name);
557 if (jac_name.length())
558 clear_function (jac_name);
559
560 if (! error_state)
561 {
562 std::string msg = dae.error_message ();
563
564 retval(4) = msg;
565 retval(3) = static_cast<double> (dae.integration_state ());
566
567 if (dae.integration_ok ())
568 {
569 retval(2) = output.times ();
570 retval(1) = output.deriv ();
571 retval(0) = output.state ();
572 }
573 else
574 {
575 retval(2) = Matrix ();
576 retval(1) = Matrix ();
577 retval(0) = Matrix ();
578
579 if (nargout < 4)
580 error ("dasrt: %s", msg.c_str ());
581 }
582 }
583
584 return retval;
585}