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