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
dasrt.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2002-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 <iostream>
28 #include <string>
29 
30 #include "DASRT.h"
31 #include "lo-mappers.h"
32 
33 #include "defun.h"
34 #include "error.h"
35 #include "errwarn.h"
36 #include "ovl.h"
37 #include "ov-fcn.h"
38 #include "ov-cell.h"
39 #include "pager.h"
40 #include "parse.h"
41 #include "unwind-prot.h"
42 #include "utils.h"
43 #include "variables.h"
44 
45 #include "DASRT-opts.cc"
46 
47 // Global pointers for user defined function required by dasrt.
51 
52 // Have we warned about imaginary values returned from user function?
53 static bool warned_fcn_imaginary = false;
54 static bool warned_jac_imaginary = false;
55 static bool warned_cf_imaginary = false;
56 
57 // Is this a recursive call?
58 static int call_depth = 0;
59 
60 static ColumnVector
61 dasrt_user_f (const ColumnVector& x, const ColumnVector& xdot,
62  double t, octave_idx_type&)
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 (dasrt_f)
75  {
77 
78  try
79  {
80  tmp = dasrt_f->do_multi_index_op (1, args);
81  }
82  catch (octave::execution_exception& e)
83  {
84  err_user_supplied_eval (e, "dasrt");
85  }
86 
87  if (tmp.empty () || ! tmp(0).is_defined ())
88  err_user_supplied_eval ("dasrt");
89 
90  if (! warned_fcn_imaginary && tmp(0).is_complex_type ())
91  {
92  warning ("dasrt: ignoring imaginary part returned from user-supplied function");
93  warned_fcn_imaginary = true;
94  }
95 
96  retval = tmp(0).vector_value ();
97 
98  if (retval.is_empty ())
99  err_user_supplied_eval ("dasrt");
100  }
101 
102  return retval;
103 }
104 
105 static ColumnVector
106 dasrt_user_cf (const ColumnVector& x, double t)
107 {
109 
111 
112  args(1) = t;
113  args(0) = x;
114 
115  if (dasrt_cf)
116  {
118 
119  try
120  {
121  tmp = dasrt_cf->do_multi_index_op (1, args);
122  }
123  catch (octave::execution_exception& e)
124  {
125  err_user_supplied_eval (e, "dasrt");
126  }
127 
128  if (tmp.empty () || ! tmp(0).is_defined ())
129  err_user_supplied_eval ("dasrt");
130 
131  if (! warned_cf_imaginary && tmp(0).is_complex_type ())
132  {
133  warning ("dasrt: ignoring imaginary part returned from user-supplied constraint function");
134  warned_cf_imaginary = true;
135  }
136 
137  retval = tmp(0).vector_value ();
138 
139  if (retval.is_empty ())
140  err_user_supplied_eval ("dasrt");
141  }
142 
143  return retval;
144 }
145 
146 static Matrix
148  double t, double cj)
149 {
150  Matrix retval;
151 
152  assert (x.numel () == xdot.numel ());
153 
155 
156  args(3) = cj;
157  args(2) = t;
158  args(1) = xdot;
159  args(0) = x;
160 
161  if (dasrt_j)
162  {
164 
165  try
166  {
167  tmp = dasrt_j->do_multi_index_op (1, args);
168  }
169  catch (octave::execution_exception& e)
170  {
171  err_user_supplied_eval (e, "dasrt");
172  }
173 
174  int tlen = tmp.length ();
175  if (tlen == 0 || ! tmp(0).is_defined ())
176  err_user_supplied_eval ("dasrt");
177 
178  if (! warned_jac_imaginary && tmp(0).is_complex_type ())
179  {
180  warning ("dasrt: ignoring imaginary part returned from user-supplied jacobian function");
181  warned_jac_imaginary = true;
182  }
183 
184  retval = tmp(0).matrix_value ();
185 
186  if (retval.is_empty ())
187  err_user_supplied_eval ("dasrt");
188  }
189 
190  return retval;
191 }
192 
193 DEFUN (dasrt, args, nargout,
194  doc: /* -*- texinfo -*-
195 @deftypefn {} {[@var{x}, @var{xdot}, @var{t_out}, @var{istat}, @var{msg}] =} dasrt (@var{fcn}, [], @var{x_0}, @var{xdot_0}, @var{t})
196 @deftypefnx {} {@dots{} =} dasrt (@var{fcn}, @var{g}, @var{x_0}, @var{xdot_0}, @var{t})
197 @deftypefnx {} {@dots{} =} dasrt (@var{fcn}, [], @var{x_0}, @var{xdot_0}, @var{t}, @var{t_crit})
198 @deftypefnx {} {@dots{} =} dasrt (@var{fcn}, @var{g}, @var{x_0}, @var{xdot_0}, @var{t}, @var{t_crit})
199 Solve the set of differential-algebraic equations
200 @tex
201 $$ 0 = f (x, \dot{x}, t) $$
202 with
203 $$ x(t_0) = x_0, \dot{x}(t_0) = \dot{x}_0 $$
204 @end tex
205 @ifnottex
206 
207 @example
208 0 = f (x, xdot, t)
209 @end example
210 
211 @noindent
212 with
213 
214 @example
215 x(t_0) = x_0, xdot(t_0) = xdot_0
216 @end example
217 
218 @end ifnottex
219 with functional stopping criteria (root solving).
220 
221 The solution is returned in the matrices @var{x} and @var{xdot},
222 with each row in the result matrices corresponding to one of the
223 elements in the vector @var{t_out}. The first element of @var{t}
224 should be @math{t_0} and correspond to the initial state of the
225 system @var{x_0} and its derivative @var{xdot_0}, so that the first
226 row of the output @var{x} is @var{x_0} and the first row
227 of the output @var{xdot} is @var{xdot_0}.
228 
229 The vector @var{t} provides an upper limit on the length of the
230 integration. If the stopping condition is met, the vector
231 @var{t_out} will be shorter than @var{t}, and the final element of
232 @var{t_out} will be the point at which the stopping condition was met,
233 and may not correspond to any element of the vector @var{t}.
234 
235 The first argument, @var{fcn}, is a string, inline, or function handle
236 that names the function @math{f} to call to compute the vector of
237 residuals for the set of equations. It must have the form
238 
239 @example
240 @var{res} = f (@var{x}, @var{xdot}, @var{t})
241 @end example
242 
243 @noindent
244 in which @var{x}, @var{xdot}, and @var{res} are vectors, and @var{t} is a
245 scalar.
246 
247 If @var{fcn} is a two-element string array or a two-element cell array
248 of strings, inline functions, or function handles, the first element names
249 the function @math{f} described above, and the second element names a
250 function to compute the modified Jacobian
251 
252 @tex
253 $$
254 J = {\partial f \over \partial x}
255  + c {\partial f \over \partial \dot{x}}
256 $$
257 @end tex
258 @ifnottex
259 
260 @example
261 @group
262  df df
263 jac = -- + c ------
264  dx d xdot
265 @end group
266 @end example
267 
268 @end ifnottex
269 
270 The modified Jacobian function must have the form
271 
272 @example
273 @group
274 
275 @var{jac} = j (@var{x}, @var{xdot}, @var{t}, @var{c})
276 
277 @end group
278 @end example
279 
280 The optional second argument names a function that defines the
281 constraint functions whose roots are desired during the integration.
282 This function must have the form
283 
284 @example
285 @var{g_out} = g (@var{x}, @var{t})
286 @end example
287 
288 @noindent
289 and return a vector of the constraint function values.
290 If the value of any of the constraint functions changes sign, @sc{dasrt}
291 will attempt to stop the integration at the point of the sign change.
292 
293 If the name of the constraint function is omitted, @code{dasrt} solves
294 the same problem as @code{daspk} or @code{dassl}.
295 
296 Note that because of numerical errors in the constraint functions
297 due to round-off and integration error, @sc{dasrt} may return false
298 roots, or return the same root at two or more nearly equal values of
299 @var{T}. If such false roots are suspected, the user should consider
300 smaller error tolerances or higher precision in the evaluation of the
301 constraint functions.
302 
303 If a root of some constraint function defines the end of the problem,
304 the input to @sc{dasrt} should nevertheless allow integration to a
305 point slightly past that root, so that @sc{dasrt} can locate the root
306 by interpolation.
307 
308 The third and fourth arguments to @code{dasrt} specify the initial
309 condition of the states and their derivatives, and the fourth argument
310 specifies a vector of output times at which the solution is desired,
311 including the time corresponding to the initial condition.
312 
313 The set of initial states and derivatives are not strictly required to
314 be consistent. In practice, however, @sc{dassl} is not very good at
315 determining a consistent set for you, so it is best if you ensure that
316 the initial values result in the function evaluating to zero.
317 
318 The sixth argument is optional, and may be used to specify a set of
319 times that the DAE solver should not integrate past. It is useful for
320 avoiding difficulties with singularities and points where there is a
321 discontinuity in the derivative.
322 
323 After a successful computation, the value of @var{istate} will be
324 greater than zero (consistent with the Fortran version of @sc{dassl}).
325 
326 If the computation is not successful, the value of @var{istate} will be
327 less than zero and @var{msg} will contain additional information.
328 
329 You can use the function @code{dasrt_options} to set optional
330 parameters for @code{dasrt}.
331 @seealso{dasrt_options, daspk, dasrt, lsode}
332 @end deftypefn */)
333 {
334  int nargin = args.length ();
335 
336  if (nargin < 4 || nargin > 6)
337  print_usage ();
338 
339  warned_fcn_imaginary = false;
340  warned_jac_imaginary = false;
341  warned_cf_imaginary = false;
342 
344 
346 
347  frame.protect_var (call_depth);
348  call_depth++;
349 
350  if (call_depth > 1)
351  error ("dasrt: invalid recursive call");
352 
353  int argp = 0;
354  std::string fcn_name, fname, jac_name, jname;
355  dasrt_f = 0;
356  dasrt_j = 0;
357  dasrt_cf = 0;
358 
359  // Check all the arguments. Are they the right animals?
360 
361  // Here's where I take care of f and j in one shot:
362 
363  octave_value f_arg = args(0);
364 
365  if (f_arg.is_cell ())
366  {
367  Cell c = f_arg.cell_value ();
368  if (c.numel () == 1)
369  f_arg = c(0);
370  else if (c.numel () == 2)
371  {
372  if (c(0).is_function_handle () || c(0).is_inline_function ())
373  dasrt_f = c(0).function_value ();
374  else
375  {
376  fcn_name = unique_symbol_name ("__dasrt_fcn__");
377  fname = "function y = ";
378  fname.append (fcn_name);
379  fname.append (" (x, xdot, t) y = ");
380  dasrt_f = extract_function (c(0), "dasrt", fcn_name, fname,
381  "; endfunction");
382  }
383 
384  if (dasrt_f)
385  {
386  if (c(1).is_function_handle () || c(1).is_inline_function ())
387  dasrt_j = c(1).function_value ();
388  else
389  {
390  jac_name = unique_symbol_name ("__dasrt_jac__");
391  jname = "function jac = ";
392  jname.append (jac_name);
393  jname.append (" (x, xdot, t, cj) jac = ");
394  dasrt_j = extract_function (c(1), "dasrt", jac_name, jname,
395  "; endfunction");
396 
397  if (! dasrt_j)
398  {
399  if (fcn_name.length ())
400  clear_function (fcn_name);
401  dasrt_f = 0;
402  }
403  }
404  }
405  }
406  else
407  error ("dasrt: incorrect number of elements in cell array");
408  }
409 
410  if (! dasrt_f && ! f_arg.is_cell ())
411  {
412  if (f_arg.is_function_handle () || f_arg.is_inline_function ())
413  dasrt_f = f_arg.function_value ();
414  else
415  {
416  switch (f_arg.rows ())
417  {
418  case 1:
419  fcn_name = unique_symbol_name ("__dasrt_fcn__");
420  fname = "function y = ";
421  fname.append (fcn_name);
422  fname.append (" (x, xdot, t) y = ");
423  dasrt_f = extract_function (f_arg, "dasrt", fcn_name, fname,
424  "; endfunction");
425  break;
426 
427  case 2:
428  {
429  string_vector tmp = args(0).string_vector_value ();
430 
431  fcn_name = unique_symbol_name ("__dasrt_fcn__");
432  fname = "function y = ";
433  fname.append (fcn_name);
434  fname.append (" (x, xdot, t) y = ");
435  dasrt_f = extract_function (tmp(0), "dasrt", fcn_name,
436  fname, "; endfunction");
437 
438  if (dasrt_f)
439  {
440  jac_name = unique_symbol_name ("__dasrt_jac__");
441  jname = "function jac = ";
442  jname.append (jac_name);
443  jname.append (" (x, xdot, t, cj) jac = ");
444  dasrt_j = extract_function (tmp(1), "dasrt", jac_name,
445  jname, "; endfunction");
446 
447  if (! dasrt_j)
448  dasrt_f = 0;
449  }
450  }
451  break;
452 
453  default:
454  error ("dasrt: first arg should be a string or 2-element string array");
455  }
456  }
457  }
458 
459  if (! dasrt_f)
460  return retval;
461 
462  DAERTFunc func (dasrt_user_f);
463 
464  argp++;
465 
466  if (args(1).is_function_handle () || args(1).is_inline_function ())
467  {
468  dasrt_cf = args(1).function_value ();
469 
470  if (! dasrt_cf)
471  error ("dasrt: invalid constraint function G");
472 
473  argp++;
474 
476  }
477  else if (args(1).is_string ())
478  {
479  dasrt_cf = is_valid_function (args(1), "dasrt", true);
480  if (! dasrt_cf)
481  error ("dasrt: invalid constraint function G");
482 
483  argp++;
484 
486  }
487 
488  ColumnVector state = args(argp).xvector_value ("dasrt: initial state X_0 must be a vector");
489 
490  ColumnVector stateprime = args(argp).xvector_value ("dasrt: initial derivatives XDOT_0 must be a vector");
491  argp++;
492 
493  ColumnVector out_times = args(argp).xvector_value ("dasrt: output time variable T must be a vector");
494  argp++;
495 
496  double tzero = out_times (0);
497 
498  ColumnVector crit_times;
499 
500  bool crit_times_set = false;
501 
502  if (argp < nargin)
503  {
504  crit_times = args(argp).xvector_value ("dasrt: list of critical times T_CRIT must be a vector");
505  argp++;
506 
507  crit_times_set = true;
508  }
509 
510  if (dasrt_j)
512 
513  DASRT_result output;
514 
515  DASRT dae = DASRT (state, stateprime, tzero, func);
516 
517  dae.set_options (dasrt_opts);
518 
519  if (crit_times_set)
520  output = dae.integrate (out_times, crit_times);
521  else
522  output = dae.integrate (out_times);
523 
524  if (fcn_name.length ())
525  clear_function (fcn_name);
526  if (jac_name.length ())
527  clear_function (jac_name);
528 
529  std::string msg = dae.error_message ();
530 
531  if (dae.integration_ok ())
532  {
533  retval(0) = output.state ();
534  retval(1) = output.deriv ();
535  retval(2) = output.times ();
536  }
537  else
538  {
539  if (nargout < 4)
540  error ("dasrt: %s", msg.c_str ());
541 
542  retval(0) = Matrix ();
543  retval(1) = Matrix ();
544  retval(2) = Matrix ();
545  }
546 
547  retval(3) = static_cast<double> (dae.integration_state ());
548  retval(4) = msg;
549 
550  return retval;
551 }
bool is_empty(void) const
Definition: Array.h:575
Definition: Cell.h:37
Definition: DASRT.h:70
Matrix state(void) const
Definition: DASRT.h:59
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
DAERTFunc & set_constraint_function(DAERTConstrFunc cf)
Definition: DAERTFunc.h:70
void protect_var(T &var)
void error(const char *fmt,...)
Definition: error.cc:570
static DASRT_options dasrt_opts
Definition: DASRT-opts.cc:20
static octave_function * dasrt_j
Definition: dasrt.cc:49
bool is_cell(void) const
Definition: ov.h:545
std::string error_message(void) const
Definition: DASRT.cc:564
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
Matrix deriv(void) const
Definition: DASRT.h:60
i e
Definition: data.cc:2724
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
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
static octave_function * dasrt_cf
Definition: dasrt.cc:50
int nargin
Definition: graphics.cc:10115
DEFUN(dasrt, args, nargout, doc:)
Definition: dasrt.cc:193
bool is_inline_function(void) const
Definition: ov.h:708
double tmp
Definition: data.cc:6300
octave_value retval
Definition: data.cc:6294
Definition: dMatrix.h:37
ColumnVector times(void) const
Definition: DASRT.h:61
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
DASRT_result integrate(const ColumnVector &tout)
Definition: DASRT.cc:386
static bool warned_cf_imaginary
Definition: dasrt.cc:55
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
static ColumnVector dasrt_user_f(const ColumnVector &x, const ColumnVector &xdot, double t, octave_idx_type &)
Definition: dasrt.cc:61
static ColumnVector dasrt_user_cf(const ColumnVector &x, double t)
Definition: dasrt.cc:106
void err_user_supplied_eval(const char *name)
Definition: errwarn.cc:142
static Matrix dasrt_user_j(const ColumnVector &x, const ColumnVector &xdot, double t, double cj)
Definition: dasrt.cc:147
bool empty(void) const
Definition: ovl.h:98
static bool warned_fcn_imaginary
Definition: dasrt.cc:53
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
octave_idx_type integration_state(void) const
Definition: base-de.h:100
octave_function * is_valid_function(const std::string &fcn_name, const std::string &warn_for, bool warn)
Definition: variables.cc:101
void set_options(const DASRT_options &opt)
Definition: DASRT-opts.h:71
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
static octave_function * dasrt_f
Definition: dasrt.cc:48
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
static int call_depth
Definition: dasrt.cc:58
static bool warned_jac_imaginary
Definition: dasrt.cc:54
DAEFunc & set_jacobian_function(DAEJacFunc j)
Definition: DAEFunc.h:84