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