GNU Octave 10.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-2025 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 "lo-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
266@tex
267$$
268J = {\partial f \over \partial x}
269 + c {\partial f \over \partial \dot{x}}
270$$
271@end tex
272@ifnottex
273
274@example
275@group
276 df df
277jac = -- + c ------
278 dx d xdot
279@end group
280@end example
281
282@end ifnottex
283
284The modified Jacobian function must have the form
285
286@example
287@group
288
289@var{jac} = j (@var{x}, @var{xdot}, @var{t}, @var{c})
290
291@end group
292@end example
293
294The optional second argument names a function that defines the
295constraint functions whose roots are desired during the integration.
296This function must have the form
297
298@example
299@var{g_out} = g (@var{x}, @var{t})
300@end example
301
302@noindent
303and return a vector of the constraint function values.
304If the value of any of the constraint functions changes sign, @sc{dasrt}
305will attempt to stop the integration at the point of the sign change.
306
307If the name of the constraint function is omitted, @code{dasrt} solves
308the same problem as @code{daspk} or @code{dassl}.
309
310Note that because of numerical errors in the constraint functions
311due to round-off and integration error, @sc{dasrt} may return false
312roots, or return the same root at two or more nearly equal values of
313@var{T}. If such false roots are suspected, the user should consider
314smaller error tolerances or higher precision in the evaluation of the
315constraint functions.
316
317If a root of some constraint function defines the end of the problem,
318the input to @sc{dasrt} should nevertheless allow integration to a
319point slightly past that root, so that @sc{dasrt} can locate the root
320by interpolation.
321
322The third and fourth arguments to @code{dasrt} specify the initial
323condition of the states and their derivatives, and the fourth argument
324specifies a vector of output times at which the solution is desired,
325including the time corresponding to the initial condition.
326
327The set of initial states and derivatives are not strictly required to
328be consistent. In practice, however, @sc{dassl} is not very good at
329determining a consistent set for you, so it is best if you ensure that
330the initial values result in the function evaluating to zero.
331
332The sixth argument is optional, and may be used to specify a set of
333times that the DAE solver should not integrate past. It is useful for
334avoiding difficulties with singularities and points where there is a
335discontinuity in the derivative.
336
337After a successful computation, the value of @var{istate} will be
338greater than zero (consistent with the Fortran version of @sc{dassl}).
339
340If the computation is not successful, the value of @var{istate} will be
341less than zero and @var{msg} will contain additional information.
342
343You can use the function @code{dasrt_options} to set optional
344parameters for @code{dasrt}.
345@seealso{dasrt_options, daspk, dasrt, lsode}
346@end deftypefn */)
347{
348 int nargin = args.length ();
349
350 if (nargin < 4 || nargin > 6)
351 print_usage ();
352
353 warned_fcn_imaginary = false;
354 warned_jac_imaginary = false;
355 warned_cf_imaginary = false;
356
357 octave_value_list retval (5);
358
359 unwind_protect_var<int> restore_var (call_depth);
360 call_depth++;
361
362 if (call_depth > 1)
363 error ("dasrt: invalid recursive call");
364
365 int argp = 0;
366 std::string fcn_name, fname, jac_name, jname;
367
368 dasrt_fcn = octave_value ();
369 dasrt_jac = octave_value ();
370 dasrt_cf = octave_value ();
371
372 // Check all the arguments. Are they the right animals?
373
374 // Here's where I take care of f and j in one shot:
375
376 octave_value f_arg = args(0);
377
378 std::list<std::string> fcn_param_names ({"x", "xdot", "t"});
379 std::list<std::string> jac_param_names ({"x", "xdot", "t", "cj"});
380
381 if (f_arg.iscell ())
382 {
383 Cell c = f_arg.cell_value ();
384 if (c.numel () == 1)
385 f_arg = c(0);
386 else if (c.numel () == 2)
387 {
388 dasrt_fcn = get_function_handle (interp, c(0), fcn_param_names);
389
390 if (dasrt_fcn.is_defined ())
391 {
392 dasrt_jac = get_function_handle (interp, c(1), jac_param_names);
393
394 if (dasrt_jac.is_undefined ())
395 dasrt_fcn = octave_value ();
396 }
397 }
398 else
399 error ("dasrt: incorrect number of elements in cell array");
400 }
401
402 if (dasrt_fcn.is_undefined () && ! f_arg.iscell ())
403 {
404 if (f_arg.is_function_handle () || f_arg.is_inline_function ())
405 dasrt_fcn = f_arg;
406 else
407 {
408 switch (f_arg.rows ())
409 {
410 case 1:
411 dasrt_fcn = get_function_handle (interp, f_arg, fcn_param_names);
412 break;
413
414 case 2:
415 {
416 string_vector tmp = f_arg.string_vector_value ();
417
418 dasrt_fcn = get_function_handle (interp, tmp(0),
419 fcn_param_names);
420
421 if (dasrt_fcn.is_defined ())
422 {
423 dasrt_jac = get_function_handle (interp, tmp(1),
424 jac_param_names);
425
426 if (dasrt_jac.is_undefined ())
427 dasrt_fcn = octave_value ();
428 }
429 }
430 break;
431
432 default:
433 error ("dasrt: first arg should be a string or 2-element string array");
434 }
435 }
436 }
437
438 if (dasrt_fcn.is_undefined ())
439 error ("dasrt: FCN argument is not a valid function name or handle");
440
441 DAERTFunc fcn (dasrt_user_f);
442
443 argp++;
444
445 if (args(1).isempty () && args(1).is_double_type ())
446 {
447 // Allow [] to skip constraint function. This feature is
448 // undocumented now, but was supported by earlier versions.
449
450 argp++;
451 }
452 else
453 {
454 if (args(1).is_function_handle () || args(1).is_inline_function ()
455 || args(1).is_string ())
456 {
457 std::list<std::string> cf_param_names ({"x", "t"});
458
459 dasrt_cf = get_function_handle (interp, args(1), cf_param_names);
460 }
461
462 if (dasrt_cf.is_defined ())
463 {
464 argp++;
465
466 fcn.set_constraint_function (dasrt_user_cf);
467 }
468 }
469
470 if (argp + 3 > nargin)
471 print_usage ();
472
473 ColumnVector state = args(argp++).xvector_value ("dasrt: initial state X_0 must be a vector");
474
475 ColumnVector stateprime = args(argp++).xvector_value ("dasrt: initial derivatives XDOT_0 must be a vector");
476
477 ColumnVector out_times = args(argp++).xvector_value ("dasrt: output time variable T must be a vector");
478
479 double tzero = out_times (0);
480
481 ColumnVector crit_times;
482
483 bool crit_times_set = false;
484
485 if (argp < nargin)
486 {
487 crit_times = args(argp).xvector_value ("dasrt: list of critical times T_CRIT must be a vector");
488 argp++;
489
490 crit_times_set = true;
491 }
492
493 if (dasrt_jac.is_defined ())
494 fcn.set_jacobian_function (dasrt_user_j);
495
496 DASRT_result output;
497
498 DASRT dae = DASRT (state, stateprime, tzero, fcn);
499
500 dae.set_options (dasrt_opts);
501
502 if (crit_times_set)
503 output = dae.integrate (out_times, crit_times);
504 else
505 output = dae.integrate (out_times);
506
507 std::string msg = dae.error_message ();
508
509 if (dae.integration_ok ())
510 {
511 retval(0) = output.state ();
512 retval(1) = output.deriv ();
513 retval(2) = output.times ();
514 }
515 else
516 {
517 if (nargout < 4)
518 error ("dasrt: %s", msg.c_str ());
519
520 retval(0) = Matrix ();
521 retval(1) = Matrix ();
522 retval(2) = Matrix ();
523 }
524
525 retval(3) = static_cast<double> (dae.integration_state ());
526 retval(4) = msg;
527
528 return retval;
529}
530
531OCTAVE_END_NAMESPACE(octave)
bool isempty() const
Size of the specified dimension.
Definition Array.h:652
octave_idx_type numel() const
Number of elements in the array.
Definition Array.h:418
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:768
bool is_undefined() const
Definition ov.h:595
bool is_inline_function() const
Definition ov.h:774
Cell cell_value() const
octave_idx_type rows() const
Definition ov.h:545
bool is_defined() const
Definition ov.h:592
bool iscell() const
Definition ov.h:604
string_vector string_vector_value(bool pad=false) const
Definition ov.h:986
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:1078
void error(const char *fmt,...)
Definition error.cc:1003
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)
F77_RET_T const F77_DBLE * x
#define panic_unless(cond)
Definition panic.h:59