GNU Octave  4.2.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
daspk.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1996-2017 John W. Eaton
4 
5 This file is part of Octave.
6 
7 Octave is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
20 
21 */
22 
23 #if defined (HAVE_CONFIG_H)
24 # include "config.h"
25 #endif
26 
27 #include <string>
28 
29 #include <iomanip>
30 #include <iostream>
31 
32 #include "DASPK.h"
33 
34 #include "defun.h"
35 #include "error.h"
36 #include "errwarn.h"
37 #include "ovl.h"
38 #include "ov-fcn.h"
39 #include "ov-cell.h"
40 #include "pager.h"
41 #include "unwind-prot.h"
42 #include "utils.h"
43 #include "variables.h"
44 
45 #include "DASPK-opts.cc"
46 
47 // Global pointer for user defined function required by daspk.
49 
50 // Global pointer for optional user defined jacobian function.
52 
53 // Have we warned about imaginary values returned from user function?
54 static bool warned_fcn_imaginary = false;
55 static bool warned_jac_imaginary = false;
56 
57 // Is this a recursive call?
58 static int call_depth = 0;
59 
62  double t, octave_idx_type& ires)
63 {
65 
66  assert (x.numel () == xdot.numel ());
67 
69 
70  args(2) = t;
71  args(1) = xdot;
72  args(0) = x;
73 
74  if (daspk_fcn)
75  {
77 
78  try
79  {
80  tmp = daspk_fcn->do_multi_index_op (1, args);
81  }
82  catch (octave::execution_exception& e)
83  {
84  err_user_supplied_eval (e, "daspk");
85  }
86 
87  int tlen = tmp.length ();
88  if (tlen == 0 || ! tmp(0).is_defined ())
89  err_user_supplied_eval ("daspk");
90 
91  if (! warned_fcn_imaginary && tmp(0).is_complex_type ())
92  {
93  warning ("daspk: ignoring imaginary part returned from user-supplied function");
94  warned_fcn_imaginary = true;
95  }
96 
97  retval = tmp(0).vector_value ();
98 
99  if (tlen > 1)
100  ires = tmp(1).idx_type_value ();
101 
102  if (retval.is_empty ())
103  err_user_supplied_eval ("daspk");
104  }
105 
106  return retval;
107 }
108 
109 Matrix
111  double t, double cj)
112 {
113  Matrix retval;
114 
115  assert (x.numel () == xdot.numel ());
116 
118 
119  args(3) = cj;
120  args(2) = t;
121  args(1) = xdot;
122  args(0) = x;
123 
124  if (daspk_jac)
125  {
127 
128  try
129  {
130  tmp = daspk_jac->do_multi_index_op (1, args);
131  }
132  catch (octave::execution_exception& e)
133  {
134  err_user_supplied_eval (e, "daspk");
135  }
136 
137  int tlen = tmp.length ();
138  if (tlen == 0 || ! tmp(0).is_defined ())
139  err_user_supplied_eval ("daspk");
140 
141  if (! warned_jac_imaginary && tmp(0).is_complex_type ())
142  {
143  warning ("daspk: ignoring imaginary part returned from user-supplied jacobian function");
144  warned_jac_imaginary = true;
145  }
146 
147  retval = tmp(0).matrix_value ();
148 
149  if (retval.is_empty ())
150  err_user_supplied_eval ("daspk");
151  }
152 
153  return retval;
154 }
155 
156 DEFUN (daspk, args, nargout,
157  doc: /* -*- texinfo -*-
158 @deftypefn {} {[@var{x}, @var{xdot}, @var{istate}, @var{msg}] =} daspk (@var{fcn}, @var{x_0}, @var{xdot_0}, @var{t}, @var{t_crit})
159 Solve the set of differential-algebraic equations
160 @tex
161 $$ 0 = f (x, \dot{x}, t) $$
162 with
163 $$ x(t_0) = x_0, \dot{x}(t_0) = \dot{x}_0 $$
164 @end tex
165 @ifnottex
166 
167 @example
168 0 = f (x, xdot, t)
169 @end example
170 
171 @noindent
172 with
173 
174 @example
175 x(t_0) = x_0, xdot(t_0) = xdot_0
176 @end example
177 
178 @end ifnottex
179 The solution is returned in the matrices @var{x} and @var{xdot},
180 with each row in the result matrices corresponding to one of the
181 elements in the vector @var{t}. The first element of @var{t}
182 should be @math{t_0} and correspond to the initial state of the
183 system @var{x_0} and its derivative @var{xdot_0}, so that the first
184 row of the output @var{x} is @var{x_0} and the first row
185 of the output @var{xdot} is @var{xdot_0}.
186 
187 The first argument, @var{fcn}, is a string, inline, or function handle
188 that names the function @math{f} to call to compute the vector of
189 residuals for the set of equations. It must have the form
190 
191 @example
192 @var{res} = f (@var{x}, @var{xdot}, @var{t})
193 @end example
194 
195 @noindent
196 in which @var{x}, @var{xdot}, and @var{res} are vectors, and @var{t} is a
197 scalar.
198 
199 If @var{fcn} is a two-element string array or a two-element cell array
200 of strings, inline functions, or function handles, the first element names
201 the function @math{f} described above, and the second element names a
202 function to compute the modified Jacobian
203 @tex
204 $$
205 J = {\partial f \over \partial x}
206  + c {\partial f \over \partial \dot{x}}
207 $$
208 @end tex
209 @ifnottex
210 
211 @example
212 @group
213  df df
214 jac = -- + c ------
215  dx d xdot
216 @end group
217 @end example
218 
219 @end ifnottex
220 
221 The modified Jacobian function must have the form
222 
223 @example
224 @group
225 
226 @var{jac} = j (@var{x}, @var{xdot}, @var{t}, @var{c})
227 
228 @end group
229 @end example
230 
231 The second and third arguments to @code{daspk} specify the initial
232 condition of the states and their derivatives, and the fourth argument
233 specifies a vector of output times at which the solution is desired,
234 including the time corresponding to the initial condition.
235 
236 The set of initial states and derivatives are not strictly required to
237 be consistent. If they are not consistent, you must use the
238 @code{daspk_options} function to provide additional information so
239 that @code{daspk} can compute a consistent starting point.
240 
241 The fifth argument is optional, and may be used to specify a set of
242 times that the DAE solver should not integrate past. It is useful for
243 avoiding difficulties with singularities and points where there is a
244 discontinuity in the derivative.
245 
246 After a successful computation, the value of @var{istate} will be
247 greater than zero (consistent with the Fortran version of @sc{daspk}).
248 
249 If the computation is not successful, the value of @var{istate} will be
250 less than zero and @var{msg} will contain additional information.
251 
252 You can use the function @code{daspk_options} to set optional
253 parameters for @code{daspk}.
254 @seealso{dassl}
255 @end deftypefn */)
256 {
257  int nargin = args.length ();
258 
259  if (nargin < 4 || nargin > 5)
260  print_usage ();
261 
262  warned_fcn_imaginary = false;
263  warned_jac_imaginary = false;
264 
266 
268 
269  frame.protect_var (call_depth);
270  call_depth++;
271 
272  if (call_depth > 1)
273  error ("daspk: invalid recursive call");
274 
275  std::string fcn_name, fname, jac_name, jname;
276  daspk_fcn = 0;
277  daspk_jac = 0;
278 
279  octave_value f_arg = args(0);
280 
281  if (f_arg.is_cell ())
282  {
283  Cell c = f_arg.cell_value ();
284  if (c.numel () == 1)
285  f_arg = c(0);
286  else if (c.numel () == 2)
287  {
288  if (c(0).is_function_handle () || c(0).is_inline_function ())
289  daspk_fcn = c(0).function_value ();
290  else
291  {
292  fcn_name = unique_symbol_name ("__daspk_fcn__");
293  fname = "function y = ";
294  fname.append (fcn_name);
295  fname.append (" (x, xdot, t) y = ");
296  daspk_fcn = extract_function (c(0), "daspk", fcn_name,
297  fname, "; endfunction");
298  }
299 
300  if (daspk_fcn)
301  {
302  if (c(1).is_function_handle () || c(1).is_inline_function ())
303  daspk_jac = c(1).function_value ();
304  else
305  {
306  jac_name = unique_symbol_name ("__daspk_jac__");
307  jname = "function jac = ";
308  jname.append (jac_name);
309  jname.append (" (x, xdot, t, cj) jac = ");
310  daspk_jac = extract_function (c(1), "daspk", jac_name,
311  jname, "; endfunction");
312 
313  if (! daspk_jac)
314  {
315  if (fcn_name.length ())
316  clear_function (fcn_name);
317  daspk_fcn = 0;
318  }
319  }
320  }
321  }
322  else
323  error ("daspk: incorrect number of elements in cell array");
324  }
325 
326  if (! daspk_fcn && ! f_arg.is_cell ())
327  {
328  if (f_arg.is_function_handle () || f_arg.is_inline_function ())
329  daspk_fcn = f_arg.function_value ();
330  else
331  {
332  switch (f_arg.rows ())
333  {
334  case 1:
335  do
336  {
337  fcn_name = unique_symbol_name ("__daspk_fcn__");
338  fname = "function y = ";
339  fname.append (fcn_name);
340  fname.append (" (x, xdot, t) y = ");
341  daspk_fcn = extract_function (f_arg, "daspk", fcn_name,
342  fname, "; endfunction");
343  }
344  while (0);
345  break;
346 
347  case 2:
348  {
350 
351  fcn_name = unique_symbol_name ("__daspk_fcn__");
352  fname = "function y = ";
353  fname.append (fcn_name);
354  fname.append (" (x, xdot, t) y = ");
355  daspk_fcn = extract_function (tmp(0), "daspk", fcn_name,
356  fname, "; endfunction");
357 
358  if (daspk_fcn)
359  {
360  jac_name = unique_symbol_name ("__daspk_jac__");
361  jname = "function jac = ";
362  jname.append (jac_name);
363  jname.append (" (x, xdot, t, cj) jac = ");
364  daspk_jac = extract_function (tmp(1), "daspk", jac_name,
365  jname, "; endfunction");
366 
367  if (! daspk_jac)
368  {
369  if (fcn_name.length ())
370  clear_function (fcn_name);
371  daspk_fcn = 0;
372  }
373  }
374  }
375  }
376  }
377  }
378 
379  if (! daspk_fcn)
380  return retval;
381 
382  ColumnVector state = args(1).xvector_value ("daspk: initial state X_0 must be a vector");
383 
384  ColumnVector deriv = args(2).xvector_value ("daspk: initial derivatives XDOT_0 must be a vector");
385 
386  ColumnVector out_times = args(3).xvector_value ("daspk: output time variable T must be a vector");
387 
388  ColumnVector crit_times;
389  int crit_times_set = 0;
390  if (nargin > 4)
391  {
392  crit_times = args(4).xvector_value ("daspk: list of critical times T_CRIT must be a vector");
393 
394  crit_times_set = 1;
395  }
396 
397  if (state.numel () != deriv.numel ())
398  error ("daspk: X_0 and XDOT_0 must have the same size");
399 
400  double tzero = out_times (0);
401 
403  if (daspk_jac)
405 
406  DASPK dae (state, deriv, tzero, func);
407  dae.set_options (daspk_opts);
408 
409  Matrix output;
410  Matrix deriv_output;
411 
412  if (crit_times_set)
413  output = dae.integrate (out_times, deriv_output, crit_times);
414  else
415  output = dae.integrate (out_times, deriv_output);
416 
417  if (fcn_name.length ())
418  clear_function (fcn_name);
419  if (jac_name.length ())
420  clear_function (jac_name);
421 
422  std::string msg = dae.error_message ();
423 
424  if (dae.integration_ok ())
425  {
426  retval(0) = output;
427  retval(1) = deriv_output;
428  }
429  else
430  {
431  if (nargout < 3)
432  error ("daspk: %s", msg.c_str ());
433 
434  retval(0) = Matrix ();
435  retval(1) = Matrix ();
436  }
437 
438  retval(2) = static_cast<double> (dae.integration_state ());
439  retval(3) = msg;
440 
441  return retval;
442 }
bool is_empty(void) const
Definition: Array.h:575
Definition: Cell.h:37
Matrix integrate(const ColumnVector &tout, Matrix &xdot_out)
Definition: DASPK.cc:547
fname
Definition: load-save.cc:754
virtual octave_value_list do_multi_index_op(int nargout, const octave_value_list &idx)
Definition: ov-base.cc:259
octave_idx_type rows(void) const
Definition: ov.h:489
bool integration_ok(void) const
Definition: base-de.h:98
OCTINTERP_API void print_usage(void)
Definition: defun.cc:52
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:363
octave_idx_type length(void) const
Definition: ovl.h:96
static octave_function * daspk_fcn
Definition: daspk.cc:48
void protect_var(T &var)
void error(const char *fmt,...)
Definition: error.cc:570
bool is_cell(void) const
Definition: ov.h:545
OCTAVE_EXPORT octave_value_list return the number of command line arguments passed to Octave If called with the optional argument the function t
Definition: ov-usr-fcn.cc:935
i e
Definition: data.cc:2724
static bool warned_fcn_imaginary
Definition: daspk.cc:54
bool is_function_handle(void) const
Definition: ov.h:702
std::string unique_symbol_name(const std::string &basename)
Definition: variables.cc:491
Cell cell_value(void) const
Definition: ov.cc:1687
void clear_function(const std::string &nm)
Definition: variables.cc:79
JNIEnv void * args
Definition: ov-java.cc:67
Matrix daspk_user_jacobian(const ColumnVector &x, const ColumnVector &xdot, double t, double cj)
Definition: daspk.cc:110
Definition: DASPK.h:32
OCTAVE_EXPORT octave_value_list return the number of command line arguments passed to Octave If called with the optional argument the function xample nargout(@histc)
Definition: ov-usr-fcn.cc:935
int nargin
Definition: graphics.cc:10115
bool is_inline_function(void) const
Definition: ov.h:708
void set_options(const DASPK_options &opt)
Definition: DASPK-opts.h:102
double tmp
Definition: data.cc:6300
octave_value retval
Definition: data.cc:6294
Definition: dMatrix.h:37
the sparsity preserving column transformation such that that defines the pivoting threshold can be given in which case it defines the c
Definition: lu.cc:138
string_vector string_vector_value(bool pad=false) const
Definition: ov.h:911
static uint32_t state[624]
Definition: randmtzig.cc:184
octave_function * function_value(bool silent=false) const
Definition: ov.cc:1705
void warning(const char *fmt,...)
Definition: error.cc:788
octave::unwind_protect frame
Definition: graphics.cc:11584
void err_user_supplied_eval(const char *name)
Definition: errwarn.cc:142
std::string error_message(void) const
Definition: DASPK.cc:695
octave_function * extract_function(const octave_value &arg, const std::string &warn_for, const std::string &fname, const std::string &header, const std::string &trailer)
Definition: variables.cc:145
static bool warned_jac_imaginary
Definition: daspk.cc:55
octave_idx_type integration_state(void) const
Definition: base-de.h:100
ColumnVector daspk_user_function(const ColumnVector &x, const ColumnVector &xdot, double t, octave_idx_type &ires)
Definition: daspk.cc:61
static octave_function * daspk_jac
Definition: daspk.cc:51
static DASPK_options daspk_opts
Definition: DASPK-opts.cc:20
static int call_depth
Definition: daspk.cc:58
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:854
F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_REAL const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T F77_REAL F77_REAL &F77_RET_T F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE * x
DEFUN(daspk, args, nargout, doc:)
Definition: daspk.cc:156
DAEFunc & set_jacobian_function(DAEJacFunc j)
Definition: DAEFunc.h:84