GNU Octave 7.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
daspk.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 1996-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 "DASPK.h"
34
35#include "defun.h"
36#include "error.h"
37#include "errwarn.h"
38#include "interpreter-private.h"
39#include "ovl.h"
40#include "ov-fcn.h"
41#include "ov-cell.h"
42#include "pager.h"
43#include "parse.h"
44#include "unwind-prot.h"
45#include "utils.h"
46#include "variables.h"
47
48#include "DASPK-opts.cc"
49
50OCTAVE_NAMESPACE_BEGIN
51
52// Global pointer for user defined function required by daspk.
54
55// Global pointer for optional user defined jacobian function.
57
58// Have we warned about imaginary values returned from user function?
59static bool warned_fcn_imaginary = false;
60static bool warned_jac_imaginary = false;
61
62// Is this a recursive call?
63static int call_depth = 0;
64
65static ColumnVector
67 double t, octave_idx_type& ires)
68{
69 ColumnVector retval;
70
71 assert (x.numel () == xdot.numel ());
72
74
75 args(2) = t;
76 args(1) = xdot;
77 args(0) = x;
78
79 if (daspk_fcn.is_defined ())
80 {
82
83 try
84 {
85 tmp = feval (daspk_fcn, args, 1);
86 }
87 catch (execution_exception& ee)
88 {
89 err_user_supplied_eval (ee, "daspk");
90 }
91
92 int tlen = tmp.length ();
93 if (tlen == 0 || ! tmp(0).is_defined ())
94 err_user_supplied_eval ("daspk");
95
96 if (! warned_fcn_imaginary && tmp(0).iscomplex ())
97 {
98 warning ("daspk: ignoring imaginary part returned from user-supplied function");
100 }
101
102 retval = tmp(0).vector_value ();
103
104 if (tlen > 1)
105 ires = tmp(1).idx_type_value ();
106
107 if (retval.isempty ())
108 err_user_supplied_eval ("daspk");
109 }
110
111 return retval;
112}
113
114static Matrix
116 double t, double cj)
117{
118 Matrix retval;
119
120 assert (x.numel () == xdot.numel ());
121
123
124 args(3) = cj;
125 args(2) = t;
126 args(1) = xdot;
127 args(0) = x;
128
129 if (daspk_jac.is_defined ())
130 {
132
133 try
134 {
135 tmp = feval (daspk_jac, args, 1);
136 }
137 catch (execution_exception& ee)
138 {
139 err_user_supplied_eval (ee, "daspk");
140 }
141
142 int tlen = tmp.length ();
143 if (tlen == 0 || ! tmp(0).is_defined ())
144 err_user_supplied_eval ("daspk");
145
146 if (! warned_jac_imaginary && tmp(0).iscomplex ())
147 {
148 warning ("daspk: ignoring imaginary part returned from user-supplied jacobian function");
150 }
151
152 retval = tmp(0).matrix_value ();
153
154 if (retval.isempty ())
155 err_user_supplied_eval ("daspk");
156 }
157
158 return retval;
159}
160
161DEFMETHOD (daspk, interp, args, nargout,
162 doc: /* -*- texinfo -*-
163@deftypefn {} {[@var{x}, @var{xdot}, @var{istate}, @var{msg}] =} daspk (@var{fcn}, @var{x_0}, @var{xdot_0}, @var{t}, @var{t_crit})
164Solve a set of differential-algebraic equations.
165
166@code{daspk} solves the set of equations
167@tex
168$$ 0 = f (x, \dot{x}, t) $$
169with
170$$ x(t_0) = x_0, \dot{x}(t_0) = \dot{x}_0 $$
171@end tex
172@ifnottex
173
174@example
1750 = f (x, xdot, t)
176@end example
177
178@noindent
179with
180
181@example
182x(t_0) = x_0, xdot(t_0) = xdot_0
183@end example
184
185@end ifnottex
186The solution is returned in the matrices @var{x} and @var{xdot},
187with each row in the result matrices corresponding to one of the
188elements in the vector @var{t}. The first element of @var{t}
189should be @math{t_0} and correspond to the initial state of the
190system @var{x_0} and its derivative @var{xdot_0}, so that the first
191row of the output @var{x} is @var{x_0} and the first row
192of the output @var{xdot} is @var{xdot_0}.
193
194The first argument, @var{fcn}, is a string, inline, or function handle
195that names the function @math{f} to call to compute the vector of
196residuals for the set of equations. It must have the form
197
198@example
199@var{res} = f (@var{x}, @var{xdot}, @var{t})
200@end example
201
202@noindent
203in which @var{x}, @var{xdot}, and @var{res} are vectors, and @var{t} is a
204scalar.
205
206If @var{fcn} is a two-element string array or a two-element cell array
207of strings, inline functions, or function handles, the first element names
208the function @math{f} described above, and the second element names a
209function to compute the modified Jacobian
210@tex
211$$
212J = {\partial f \over \partial x}
213 + c {\partial f \over \partial \dot{x}}
214$$
215@end tex
216@ifnottex
217
218@example
219@group
220 df df
221jac = -- + c ------
222 dx d xdot
223@end group
224@end example
225
226@end ifnottex
227
228The modified Jacobian function must have the form
229
230@example
231@group
232
233@var{jac} = j (@var{x}, @var{xdot}, @var{t}, @var{c})
234
235@end group
236@end example
237
238The second and third arguments to @code{daspk} specify the initial
239condition of the states and their derivatives, and the fourth argument
240specifies a vector of output times at which the solution is desired,
241including the time corresponding to the initial condition.
242
243The set of initial states and derivatives are not strictly required to
244be consistent. If they are not consistent, you must use the
245@code{daspk_options} function to provide additional information so
246that @code{daspk} can compute a consistent starting point.
247
248The fifth argument is optional, and may be used to specify a set of
249times that the DAE solver should not integrate past. It is useful for
250avoiding difficulties with singularities and points where there is a
251discontinuity in the derivative.
252
253After a successful computation, the value of @var{istate} will be
254greater than zero (consistent with the Fortran version of @sc{daspk}).
255
256If the computation is not successful, the value of @var{istate} will be
257less than zero and @var{msg} will contain additional information.
258
259You can use the function @code{daspk_options} to set optional
260parameters for @code{daspk}.
261@seealso{dassl}
262@end deftypefn */)
263{
264 int nargin = args.length ();
265
266 if (nargin < 4 || nargin > 5)
267 print_usage ();
268
269 warned_fcn_imaginary = false;
270 warned_jac_imaginary = false;
271
272 octave_value_list retval (4);
273
274 unwind_protect_var<int> restore_var (call_depth);
275 call_depth++;
276
277 if (call_depth > 1)
278 error ("daspk: invalid recursive call");
279
280 std::string fcn_name, fname, jac_name, jname;
281
284
285 octave_value f_arg = args(0);
286
287 std::list<std::string> fcn_param_names ({"x", "xdot", "t"});
288 std::list<std::string> jac_param_names ({"x", "xdot", "t", "cj"});
289
290 if (f_arg.iscell ())
291 {
292 Cell c = f_arg.cell_value ();
293 if (c.numel () == 1)
294 f_arg = c(0);
295 else if (c.numel () == 2)
296 {
297 daspk_fcn = get_function_handle (interp, c(0), fcn_param_names);
298
299 if (daspk_fcn.is_defined ())
300 {
301 daspk_jac = get_function_handle (interp, c(1), jac_param_names);
302
303 if (daspk_jac.is_undefined ())
305 }
306 }
307 else
308 error ("daspk: incorrect number of elements in cell array");
309 }
310
311 if (daspk_fcn.is_undefined () && ! f_arg.iscell ())
312 {
313 if (f_arg.is_function_handle () || f_arg.is_inline_function ())
314 daspk_fcn = f_arg;
315 else
316 {
317 switch (f_arg.rows ())
318 {
319 case 1:
320 daspk_fcn = get_function_handle (interp, f_arg, fcn_param_names);
321 break;
322
323 case 2:
324 {
325 string_vector tmp = f_arg.string_vector_value ();
326
327 daspk_fcn = get_function_handle (interp, tmp(0),
328 fcn_param_names);
329
330 if (daspk_fcn.is_defined ())
331 {
332 daspk_jac = get_function_handle (interp, tmp(1),
333 jac_param_names);
334
335 if (daspk_jac.is_undefined ())
337 }
338 }
339 break;
340
341 default:
342 error ("daspk: first arg should be a string or 2-element string array");
343 }
344 }
345 }
346
347 if (daspk_fcn.is_undefined ())
348 error ("daspk: FCN argument is not a valid function name or handle");
349
350 ColumnVector state = args(1).xvector_value ("daspk: initial state X_0 must be a vector");
351
352 ColumnVector deriv = args(2).xvector_value ("daspk: initial derivatives XDOT_0 must be a vector");
353
354 ColumnVector out_times = args(3).xvector_value ("daspk: output time variable T must be a vector");
355
356 ColumnVector crit_times;
357 int crit_times_set = 0;
358 if (nargin > 4)
359 {
360 crit_times = args(4).xvector_value ("daspk: list of critical times T_CRIT must be a vector");
361
362 crit_times_set = 1;
363 }
364
365 if (state.numel () != deriv.numel ())
366 error ("daspk: X_0 and XDOT_0 must have the same size");
367
368 double tzero = out_times (0);
369
371 if (daspk_jac.is_defined ())
373
374 DASPK dae (state, deriv, tzero, func);
375 dae.set_options (daspk_opts);
376
377 Matrix output;
378 Matrix deriv_output;
379
380 if (crit_times_set)
381 output = dae.integrate (out_times, deriv_output, crit_times);
382 else
383 output = dae.integrate (out_times, deriv_output);
384
385 std::string msg = dae.error_message ();
386
387 if (dae.integration_ok ())
388 {
389 retval(0) = output;
390 retval(1) = deriv_output;
391 }
392 else
393 {
394 if (nargout < 3)
395 error ("daspk: %s", msg.c_str ());
396
397 retval(0) = Matrix ();
398 retval(1) = Matrix ();
399 }
400
401 retval(2) = static_cast<double> (dae.integration_state ());
402 retval(3) = msg;
403
404 return retval;
405}
406
407OCTAVE_NAMESPACE_END
static DASPK_options daspk_opts
Definition: DASPK-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
Definition: DASPK.h:41
std::string error_message(void) const
Definition: DASPK.cc:695
Matrix integrate(const ColumnVector &tout, Matrix &xdot_out)
Definition: DASPK.cc:547
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
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: daspk.cc:63
static octave_value daspk_jac
Definition: daspk.cc:56
static Matrix daspk_user_jacobian(const ColumnVector &x, const ColumnVector &xdot, double t, double cj)
Definition: daspk.cc:115
static bool warned_jac_imaginary
Definition: daspk.cc:60
DEFMETHOD(daspk, interp, args, nargout, doc:)
Definition: daspk.cc:161
static ColumnVector daspk_user_function(const ColumnVector &x, const ColumnVector &xdot, double t, octave_idx_type &ires)
Definition: daspk.cc:66
static OCTAVE_NAMESPACE_BEGIN octave_value daspk_fcn
Definition: daspk.cc:53
static bool warned_fcn_imaginary
Definition: daspk.cc:59
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()) ? '\'' :'"'))