GNU Octave 11.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
dasrt.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 2002-2026 The Octave Project Developers
4//
5// See the file COPYRIGHT.md in the top-level directory of this
6// distribution or <https://octave.org/copyright/>.
7//
8// This file is part of Octave.
9//
10// Octave is free software: you can redistribute it and/or modify it
11// under the terms of the GNU General Public License as published by
12// the Free Software Foundation, either version 3 of the License, or
13// (at your option) any later version.
14//
15// Octave is distributed in the hope that it will be useful, but
16// WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18// GNU General Public License for more details.
19//
20// You should have received a copy of the GNU General Public License
21// along with Octave; see the file COPYING. If not, see
22// <https://www.gnu.org/licenses/>.
23//
24////////////////////////////////////////////////////////////////////////
25
26#if defined (HAVE_CONFIG_H)
27# include "config.h"
28#endif
29
30#include <list>
31#include <string>
32
33#include "DASRT.h"
34#include "mappers.h"
35
36#include "defun.h"
37#include "error.h"
38#include "errwarn.h"
39#include "interpreter-private.h"
40#include "interpreter.h"
41#include "ovl.h"
42#include "ov-fcn.h"
43#include "ov-cell.h"
44#include "pager.h"
45#include "unwind-prot.h"
46#include "utils.h"
47#include "variables.h"
48
49#include "DASRT-opts.cc"
50
52
53// Global pointers for user defined function required by dasrt.
54static octave_value dasrt_fcn;
55static octave_value dasrt_jac;
56static octave_value dasrt_cf;
57
58// Have we warned about imaginary values returned from user function?
59static bool warned_fcn_imaginary = false;
60static bool warned_jac_imaginary = false;
61static bool warned_cf_imaginary = false;
62
63// Is this a recursive call?
64static int call_depth = 0;
65
66static ColumnVector
67dasrt_user_f (const ColumnVector& x, const ColumnVector& xdot,
68 double t, octave_idx_type&)
69{
70 ColumnVector retval;
71
72 panic_unless (x.numel () == xdot.numel ());
73
75
76 args(2) = t;
77 args(1) = xdot;
78 args(0) = x;
79
80 if (dasrt_fcn.is_defined ())
81 {
83
84 try
85 {
87
88 tmp = interp.feval (dasrt_fcn, args, 1);
89 }
90 catch (execution_exception& ee)
91 {
92 err_user_supplied_eval (ee, "dasrt");
93 }
94
95 if (tmp.empty () || ! tmp(0).is_defined ())
96 err_user_supplied_eval ("dasrt");
97
98 if (! warned_fcn_imaginary && tmp(0).iscomplex ())
99 {
100 warning ("dasrt: ignoring imaginary part returned from user-supplied function");
101 warned_fcn_imaginary = true;
102 }
103
104 retval = tmp(0).vector_value ();
105
106 if (retval.isempty ())
107 err_user_supplied_eval ("dasrt");
108 }
109
110 return retval;
111}
112
113static ColumnVector
114dasrt_user_cf (const ColumnVector& x, double t)
115{
116 ColumnVector retval;
117
119
120 args(1) = t;
121 args(0) = x;
122
123 if (dasrt_cf.is_defined ())
124 {
126
127 try
128 {
129 interpreter& interp = __get_interpreter__ ();
130
131 tmp = interp.feval (dasrt_cf, args, 1);
132 }
133 catch (execution_exception& ee)
134 {
135 err_user_supplied_eval (ee, "dasrt");
136 }
137
138 if (tmp.empty () || ! tmp(0).is_defined ())
139 err_user_supplied_eval ("dasrt");
140
141 if (! warned_cf_imaginary && tmp(0).iscomplex ())
142 {
143 warning ("dasrt: ignoring imaginary part returned from user-supplied constraint function");
144 warned_cf_imaginary = true;
145 }
146
147 retval = tmp(0).vector_value ();
148
149 if (retval.isempty ())
150 err_user_supplied_eval ("dasrt");
151 }
152
153 return retval;
154}
155
156static Matrix
157dasrt_user_j (const ColumnVector& x, const ColumnVector& xdot,
158 double t, double cj)
159{
160 Matrix retval;
161
162 panic_unless (x.numel () == xdot.numel ());
163
165
166 args(3) = cj;
167 args(2) = t;
168 args(1) = xdot;
169 args(0) = x;
170
171 if (dasrt_jac.is_defined ())
172 {
174
175 try
176 {
177 interpreter& interp = __get_interpreter__ ();
178
179 tmp = interp.feval (dasrt_jac, args, 1);
180 }
181 catch (execution_exception& ee)
182 {
183 err_user_supplied_eval (ee, "dasrt");
184 }
185
186 int tlen = tmp.length ();
187 if (tlen == 0 || ! tmp(0).is_defined ())
188 err_user_supplied_eval ("dasrt");
189
190 if (! warned_jac_imaginary && tmp(0).iscomplex ())
191 {
192 warning ("dasrt: ignoring imaginary part returned from user-supplied jacobian function");
193 warned_jac_imaginary = true;
194 }
195
196 retval = tmp(0).matrix_value ();
197
198 if (retval.isempty ())
199 err_user_supplied_eval ("dasrt");
200 }
201
202 return retval;
203}
204
205DEFMETHOD (dasrt, interp, args, nargout,
206 doc: /* -*- texinfo -*-
207@deftypefn {} {[@var{x}, @var{xdot}, @var{t_out}, @var{istat}, @var{msg}] =} dasrt (@var{fcn}, @var{g}, @var{x_0}, @var{xdot_0}, @var{t})
208@deftypefnx {} {@dots{} =} dasrt (@var{fcn}, @var{g}, @var{x_0}, @var{xdot_0}, @var{t}, @var{t_crit})
209@deftypefnx {} {@dots{} =} dasrt (@var{fcn}, @var{x_0}, @var{xdot_0}, @var{t})
210@deftypefnx {} {@dots{} =} dasrt (@var{fcn}, @var{x_0}, @var{xdot_0}, @var{t}, @var{t_crit})
211Solve a set of differential-algebraic equations.
212
213@code{dasrt} solves the set of equations
214@tex
215$$ 0 = f (x, \dot{x}, t) $$
216with
217$$ x(t_0) = x_0, \dot{x}(t_0) = \dot{x}_0 $$
218@end tex
219@ifnottex
220
221@example
2220 = f (x, xdot, t)
223@end example
224
225@noindent
226with
227
228@example
229x(t_0) = x_0, xdot(t_0) = xdot_0
230@end example
231
232@end ifnottex
233with functional stopping criteria (root solving).
234
235The solution is returned in the matrices @var{x} and @var{xdot},
236with each row in the result matrices corresponding to one of the
237elements in the vector @var{t_out}. The first element of @var{t}
238should be @math{t_0} and correspond to the initial state of the
239system @var{x_0} and its derivative @var{xdot_0}, so that the first
240row of the output @var{x} is @var{x_0} and the first row
241of the output @var{xdot} is @var{xdot_0}.
242
243The vector @var{t} provides an upper limit on the length of the
244integration. If the stopping condition is met, the vector
245@var{t_out} will be shorter than @var{t}, and the final element of
246@var{t_out} will be the point at which the stopping condition was met,
247and may not correspond to any element of the vector @var{t}.
248
249The first argument, @var{fcn}, is a string, inline, or function handle
250that names the function @math{f} to call to compute the vector of
251residuals for the set of equations. It must have the form
252
253@example
254@var{res} = f (@var{x}, @var{xdot}, @var{t})
255@end example
256
257@noindent
258in which @var{x}, @var{xdot}, and @var{res} are vectors, and @var{t} is a
259scalar.
260
261If @var{fcn} is a two-element string array or a two-element cell array
262of strings, inline functions, or function handles, the first element names
263the function @math{f} described above, and the second element names a
264function to compute the modified Jacobian
265@tex
266$$
267J = {\partial f \over \partial x}
268 + c {\partial f \over \partial \dot{x}}
269$$
270@end tex
271@ifnottex
272
273@example
274@group
275 df df
276jac = -- + c ------
277 dx d xdot
278@end group
279@end example
280
281@end ifnottex
282
283The modified Jacobian function must have the form
284
285@example
286@group
287
288@var{jac} = j (@var{x}, @var{xdot}, @var{t}, @var{c})
289
290@end group
291@end example
292
293The optional second argument names a function that defines the
294constraint functions whose roots are desired during the integration.
295This function must have the form
296
297@example
298@var{g_out} = g (@var{x}, @var{t})
299@end example
300
301@noindent
302and return a vector of the constraint function values.
303If the value of any of the constraint functions changes sign, @sc{dasrt}
304will attempt to stop the integration at the point of the sign change.
305
306If the name of the constraint function is omitted, @code{dasrt} solves
307the same problem as @code{daspk} or @code{dassl}.
308
309Note that because of numerical errors in the constraint functions
310due to round-off and integration error, @sc{dasrt} may return false
311roots, or return the same root at two or more nearly equal values of
312@var{T}. If such false roots are suspected, the user should consider
313smaller error tolerances or higher precision in the evaluation of the
314constraint functions.
315
316If a root of some constraint function defines the end of the problem,
317the input to @sc{dasrt} should nevertheless allow integration to a
318point slightly past that root, so that @sc{dasrt} can locate the root
319by interpolation.
320
321The third and fourth arguments to @code{dasrt} specify the initial
322condition of the states and their derivatives, and the fourth argument
323specifies a vector of output times at which the solution is desired,
324including the time corresponding to the initial condition.
325
326The set of initial states and derivatives are not strictly required to
327be consistent. In practice, however, @sc{dassl} is not very good at
328determining a consistent set for you, so it is best if you ensure that
329the initial values result in the function evaluating to zero.
330
331The sixth argument is optional, and may be used to specify a set of
332times that the DAE solver should not integrate past. It is useful for
333avoiding difficulties with singularities and points where there is a
334discontinuity in the derivative.
335
336After a successful computation, the value of @var{istate} will be
337greater than zero (consistent with the Fortran version of @sc{dassl}).
338
339If the computation is not successful, the value of @var{istate} will be
340less than zero and @var{msg} will contain additional information.
341
342You can use the function @code{dasrt_options} to set optional
343parameters for @code{dasrt}.
344@seealso{dasrt_options, daspk, dasrt, lsode}
345@end deftypefn */)
346{
347 int nargin = args.length ();
348
349 if (nargin < 4 || nargin > 6)
350 print_usage ();
351
352 warned_fcn_imaginary = false;
353 warned_jac_imaginary = false;
354 warned_cf_imaginary = false;
355
356 octave_value_list retval (5);
357
358 unwind_protect_var<int> restore_var (call_depth);
359 call_depth++;
360
361 if (call_depth > 1)
362 error ("dasrt: invalid recursive call");
363
364 int argp = 0;
365 std::string fcn_name, fname, jac_name, jname;
366
367 dasrt_fcn = octave_value ();
368 dasrt_jac = octave_value ();
369 dasrt_cf = octave_value ();
370
371 // Check all the arguments. Are they the right animals?
372
373 // Here's where I take care of f and j in one shot:
374
375 octave_value f_arg = args(0);
376
377 std::list<std::string> fcn_param_names ({"x", "xdot", "t"});
378 std::list<std::string> jac_param_names ({"x", "xdot", "t", "cj"});
379
380 if (f_arg.iscell ())
381 {
382 Cell c = f_arg.cell_value ();
383 if (c.numel () == 1)
384 f_arg = c(0);
385 else if (c.numel () == 2)
386 {
387 dasrt_fcn = get_function_handle (interp, c(0), fcn_param_names);
388
389 if (dasrt_fcn.is_defined ())
390 {
391 dasrt_jac = get_function_handle (interp, c(1), jac_param_names);
392
393 if (dasrt_jac.is_undefined ())
394 dasrt_fcn = octave_value ();
395 }
396 }
397 else
398 error ("dasrt: incorrect number of elements in cell array");
399 }
400
401 if (dasrt_fcn.is_undefined () && ! f_arg.iscell ())
402 {
403 if (f_arg.is_function_handle () || f_arg.is_inline_function ())
404 dasrt_fcn = f_arg;
405 else
406 {
407 switch (f_arg.rows ())
408 {
409 case 1:
410 dasrt_fcn = get_function_handle (interp, f_arg, fcn_param_names);
411 break;
412
413 case 2:
414 {
415 string_vector tmp = f_arg.string_vector_value ();
416
417 dasrt_fcn = get_function_handle (interp, tmp(0),
418 fcn_param_names);
419
420 if (dasrt_fcn.is_defined ())
421 {
422 dasrt_jac = get_function_handle (interp, tmp(1),
423 jac_param_names);
424
425 if (dasrt_jac.is_undefined ())
426 dasrt_fcn = octave_value ();
427 }
428 }
429 break;
430
431 default:
432 error ("dasrt: first arg should be a string or 2-element string array");
433 }
434 }
435 }
436
437 if (dasrt_fcn.is_undefined ())
438 error ("dasrt: FCN argument is not a valid function name or handle");
439
440 DAERTFunc fcn (dasrt_user_f);
441
442 argp++;
443
444 if (args(1).isempty () && args(1).is_double_type ())
445 {
446 // Allow [] to skip constraint function. This feature is
447 // undocumented now, but was supported by earlier versions.
448
449 argp++;
450 }
451 else
452 {
453 if (args(1).is_function_handle () || args(1).is_inline_function ()
454 || args(1).is_string ())
455 {
456 std::list<std::string> cf_param_names ({"x", "t"});
457
458 dasrt_cf = get_function_handle (interp, args(1), cf_param_names);
459 }
460
461 if (dasrt_cf.is_defined ())
462 {
463 argp++;
464
465 fcn.set_constraint_function (dasrt_user_cf);
466 }
467 }
468
469 if (argp + 3 > nargin)
470 print_usage ();
471
472 ColumnVector state = args(argp++).xvector_value ("dasrt: initial state X_0 must be a vector");
473
474 ColumnVector stateprime = args(argp++).xvector_value ("dasrt: initial derivatives XDOT_0 must be a vector");
475
476 ColumnVector out_times = args(argp++).xvector_value ("dasrt: output time variable T must be a vector");
477
478 double tzero = out_times (0);
479
480 ColumnVector crit_times;
481
482 bool crit_times_set = false;
483
484 if (argp < nargin)
485 {
486 crit_times = args(argp).xvector_value ("dasrt: list of critical times T_CRIT must be a vector");
487 argp++;
488
489 crit_times_set = true;
490 }
491
492 if (dasrt_jac.is_defined ())
493 fcn.set_jacobian_function (dasrt_user_j);
494
495 DASRT_result output;
496
497 DASRT dae = DASRT (state, stateprime, tzero, fcn);
498
499 dae.set_options (dasrt_opts);
500
501 if (crit_times_set)
502 output = dae.integrate (out_times, crit_times);
503 else
504 output = dae.integrate (out_times);
505
506 std::string msg = dae.error_message ();
507
508 if (dae.integration_ok ())
509 {
510 retval(0) = output.state ();
511 retval(1) = output.deriv ();
512 retval(2) = output.times ();
513 }
514 else
515 {
516 if (nargout < 4)
517 error ("dasrt: %s", msg.c_str ());
518
519 retval(0) = Matrix ();
520 retval(1) = Matrix ();
521 retval(2) = Matrix ();
522 }
523
524 retval(3) = static_cast<double> (dae.integration_state ());
525 retval(4) = msg;
526
527 return retval;
528}
529
530OCTAVE_END_NAMESPACE(octave)
bool isempty() const
Size of the specified dimension.
Definition Array-base.h:674
octave_idx_type numel() const
Number of elements in the array.
Definition Array-base.h:440
Definition Cell.h:41
DAEFunc & set_jacobian_function(DAEJacFunc j)
Definition DAEFunc.h:85
DAERTFunc & set_constraint_function(DAERTConstrFunc cf)
Definition DAERTFunc.h:72
Matrix deriv() const
Definition DASRT.h:64
Matrix state() const
Definition DASRT.h:63
ColumnVector times() const
Definition DASRT.h:65
Definition DASRT.h:75
DASRT_result integrate(const ColumnVector &tout)
Definition DASRT.cc:376
std::string error_message() const
Definition DASRT.cc:554
octave_idx_type integration_state() const
Definition base-de.h:101
bool integration_ok() const
Definition base-de.h:99
octave_value_list feval(const char *name, const octave_value_list &args=octave_value_list(), int nargout=0)
Evaluate an Octave function (built-in or interpreted) and return the list of result values.
bool empty() const
Definition ovl.h:113
octave_idx_type length() const
Definition ovl.h:111
bool is_function_handle() const
Definition ov.h:766
bool is_undefined() const
Definition ov.h:593
bool is_inline_function() const
Definition ov.h:772
Cell cell_value() const
octave_idx_type rows() const
Definition ov.h:543
bool is_defined() const
Definition ov.h:590
bool iscell() const
Definition ov.h:602
string_vector string_vector_value(bool pad=false) const
Definition ov.h:984
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value dasrt_fcn
void print_usage()
Definition defun-int.h:72
#define DEFMETHOD(name, interp_name, args_name, nargout_name, doc)
Macro to define a builtin method.
Definition defun.h:111
void warning(const char *fmt,...)
Definition error.cc:1083
void error(const char *fmt,...)
Definition error.cc:1008
void err_user_supplied_eval(const char *name)
Definition errwarn.cc:152
interpreter & __get_interpreter__()
octave_value get_function_handle(interpreter &interp, const octave_value &arg, const std::string &parameter_name)
#define panic_unless(cond)
Definition panic.h:59
F77_RET_T const F77_DBLE * x