GNU Octave  6.2.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-2021 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 <cinttypes>
31 #include <sstream>
32 
33 #include "DASRT.h"
34 #include "f77-fcn.h"
35 #include "lo-error.h"
36 #include "quit.h"
37 
38 typedef F77_INT (*dasrt_fcn_ptr) (const double&, const double*, const double*,
39  double*, F77_INT&, double*, F77_INT*);
40 
41 typedef F77_INT (*dasrt_jac_ptr) (const double&, const double*, const double*,
42  double*, const double&, double*, F77_INT*);
43 
44 typedef F77_INT (*dasrt_constr_ptr) (const F77_INT&, const double&,
45  const double*, const F77_INT&,
46  double*, double*, F77_INT*);
47 
48 extern "C"
49 {
50  F77_RET_T
52  F77_DBLE*, F77_DBLE*, const F77_DBLE&, F77_INT*,
53  const F77_DBLE*, const F77_DBLE*, F77_INT&,
54  F77_DBLE*, const F77_INT&, F77_INT*,
55  const F77_INT&, F77_DBLE*, F77_INT*,
57  F77_INT*);
58 }
59 
63 
64 static F77_INT nn;
65 
66 static F77_INT
67 ddasrt_f (const double& t, const double *state, const double *deriv,
68  double *delta, F77_INT& ires, double *, F77_INT *)
69 {
70  ColumnVector tmp_state (nn);
71  ColumnVector tmp_deriv (nn);
72 
73  for (F77_INT i = 0; i < nn; i++)
74  {
75  tmp_state(i) = state[i];
76  tmp_deriv(i) = deriv[i];
77  }
78 
79  octave_idx_type tmp_ires = ires;
80 
81  ColumnVector tmp_fval = (*user_fsub) (tmp_state, tmp_deriv, t, tmp_ires);
82 
83  ires = octave::to_f77_int (tmp_ires);
84 
85  if (tmp_fval.isempty ())
86  ires = -2;
87  else
88  {
89  for (F77_INT i = 0; i < nn; i++)
90  delta[i] = tmp_fval(i);
91  }
92 
93  return 0;
94 }
95 
96 F77_INT
97 ddasrt_j (const double& time, const double *state, const double *deriv,
98  double *pd, const double& cj, double *, F77_INT *)
99 {
100  // FIXME: would be nice to avoid copying the data.
101 
102  ColumnVector tmp_state (nn);
103  ColumnVector tmp_deriv (nn);
104 
105  for (F77_INT i = 0; i < nn; i++)
106  {
107  tmp_deriv.elem (i) = deriv[i];
108  tmp_state.elem (i) = state[i];
109  }
110 
111  Matrix tmp_pd = (*user_jsub) (tmp_state, tmp_deriv, time, cj);
112 
113  for (F77_INT j = 0; j < nn; j++)
114  for (F77_INT i = 0; i < nn; i++)
115  pd[nn * j + i] = tmp_pd.elem (i, j);
116 
117  return 0;
118 }
119 
120 static F77_INT
121 ddasrt_g (const F77_INT& neq, const double& t, const double *state,
122  const F77_INT& ng, double *gout, double *, F77_INT *)
123 {
124  F77_INT n = neq;
125 
126  ColumnVector tmp_state (n);
127  for (F77_INT i = 0; i < n; i++)
128  tmp_state(i) = state[i];
129 
130  ColumnVector tmp_fval = (*user_csub) (tmp_state, t);
131 
132  for (F77_INT i = 0; i < ng; i++)
133  gout[i] = tmp_fval(i);
134 
135  return 0;
136 }
137 
138 void
139 DASRT::integrate (double tout)
140 {
141  // I suppose this is the safe thing to do. If this is the first
142  // call, or if anything about the problem has changed, we should
143  // start completely fresh.
144 
145  if (! initialized || restart
146  || DAEFunc::reset || DAERTFunc::reset || DASRT_options::reset)
147  {
148  integration_error = false;
149 
150  initialized = true;
151 
152  info.resize (dim_vector (15, 1));
153 
154  for (F77_INT i = 0; i < 15; i++)
155  info(i) = 0;
156 
157  F77_INT n = octave::to_f77_int (size ());
158 
159  nn = n;
160 
161  // DAERTFunc
162 
164 
165  if (user_csub)
166  {
167  ColumnVector tmp = (*user_csub) (x, t);
168  ng = octave::to_f77_int (tmp.numel ());
169  }
170  else
171  ng = 0;
172 
173  F77_INT maxord = octave::to_f77_int (maximum_order ());
174  if (maxord >= 0)
175  {
176  if (maxord > 0 && maxord < 6)
177  {
178  info(8) = 1;
179  iwork(2) = maxord;
180  }
181  else
182  {
183  (*current_liboctave_error_handler)
184  ("dassl: invalid value for maximum order");
185  integration_error = true;
186  return;
187  }
188  }
189 
190  liw = 21 + n;
191  lrw = 50 + 9*n + n*n + 3*ng;
192 
193  iwork.resize (dim_vector (liw, 1));
194  rwork.resize (dim_vector (lrw, 1));
195 
196  info(0) = 0;
197 
198  if (stop_time_set)
199  {
200  info(3) = 1;
201  rwork(0) = stop_time;
202  }
203  else
204  info(3) = 0;
205 
206  restart = false;
207 
208  // DAEFunc
209 
212 
213  if (user_fsub)
214  {
215  octave_idx_type ires = 0;
216 
217  ColumnVector fval = (*user_fsub) (x, xdot, t, ires);
218 
219  if (fval.numel () != x.numel ())
220  {
221  (*current_liboctave_error_handler)
222  ("dasrt: inconsistent sizes for state and residual vectors");
223 
224  integration_error = true;
225  return;
226  }
227  }
228  else
229  {
230  (*current_liboctave_error_handler)
231  ("dasrt: no user supplied RHS subroutine!");
232 
233  integration_error = true;
234  return;
235  }
236 
237  info(4) = (user_jsub ? 1 : 0);
238 
239  DAEFunc::reset = false;
240 
241  jroot.resize (dim_vector (ng, 1), 1);
242 
243  DAERTFunc::reset = false;
244 
245  // DASRT_options
246 
247  double mss = maximum_step_size ();
248  if (mss >= 0.0)
249  {
250  rwork(1) = mss;
251  info(6) = 1;
252  }
253  else
254  info(6) = 0;
255 
256  double iss = initial_step_size ();
257  if (iss >= 0.0)
258  {
259  rwork(2) = iss;
260  info(7) = 1;
261  }
262  else
263  info(7) = 0;
264 
265  F77_INT sl = octave::to_f77_int (step_limit ());
266  if (sl >= 0)
267  {
268  info(11) = 1;
269  iwork(20) = sl;
270  }
271  else
272  info(11) = 0;
273 
274  abs_tol = absolute_tolerance ();
275  rel_tol = relative_tolerance ();
276 
277  F77_INT abs_tol_len = octave::to_f77_int (abs_tol.numel ());
278  F77_INT rel_tol_len = octave::to_f77_int (rel_tol.numel ());
279 
280  if (abs_tol_len == 1 && rel_tol_len == 1)
281  {
282  info.elem (1) = 0;
283  }
284  else if (abs_tol_len == n && rel_tol_len == n)
285  {
286  info.elem (1) = 1;
287  }
288  else
289  {
290  (*current_liboctave_error_handler)
291  ("dasrt: inconsistent sizes for tolerance arrays");
292 
293  integration_error = true;
294  return;
295  }
296 
297  DASRT_options::reset = false;
298  }
299 
300  double *px = x.fortran_vec ();
301  double *pxdot = xdot.fortran_vec ();
302 
303  F77_INT *pinfo = info.fortran_vec ();
304 
305  double *prel_tol = rel_tol.fortran_vec ();
306  double *pabs_tol = abs_tol.fortran_vec ();
307 
308  double *prwork = rwork.fortran_vec ();
309  F77_INT *piwork = iwork.fortran_vec ();
310 
311  F77_INT *pjroot = jroot.fortran_vec ();
312 
313  double *dummy = nullptr;
314  F77_INT *idummy = nullptr;
315 
316  F77_INT tmp_istate = octave::to_f77_int (istate);
317 
318  F77_XFCN (ddasrt, DDASRT, (ddasrt_f, nn, t, px, pxdot, tout, pinfo,
319  prel_tol, pabs_tol, tmp_istate, prwork, lrw,
320  piwork, liw, dummy, idummy, ddasrt_j,
321  ddasrt_g, ng, pjroot));
322 
323  istate = tmp_istate;
324 
325  switch (istate)
326  {
327  case 1: // A step was successfully taken in intermediate-output
328  // mode. The code has not yet reached TOUT.
329  case 2: // The integration to TOUT was successfully completed
330  // (T=TOUT) by stepping exactly to TOUT.
331  case 3: // The integration to TOUT was successfully completed
332  // (T=TOUT) by stepping past TOUT. Y(*) is obtained by
333  // interpolation. YPRIME(*) is obtained by interpolation.
334  t = tout;
335  break;
336 
337  case 4: // The integration was successfully completed
338  // by finding one or more roots of G at T.
339  break;
340 
341  case -1: // A large amount of work has been expended.
342  case -2: // The error tolerances are too stringent.
343  case -3: // The local error test cannot be satisfied because you
344  // specified a zero component in ATOL and the
345  // corresponding computed solution component is zero.
346  // Thus, a pure relative error test is impossible for
347  // this component.
348  case -6: // DDASRT had repeated error test failures on the last
349  // attempted step.
350  case -7: // The corrector could not converge.
351  case -8: // The matrix of partial derivatives is singular.
352  case -9: // The corrector could not converge. There were repeated
353  // error test failures in this step.
354  case -10: // The corrector could not converge because IRES was
355  // equal to minus one.
356  case -11: // IRES equal to -2 was encountered and control is being
357  // returned to the calling program.
358  case -12: // DASSL failed to compute the initial YPRIME.
359  case -33: // The code has encountered trouble from which it cannot
360  // recover. A message is printed explaining the trouble
361  // and control is returned to the calling program. For
362  // example, this occurs when invalid input is detected.
363  integration_error = true;
364  break;
365 
366  default:
367  integration_error = true;
368  (*current_liboctave_error_handler)
369  ("unrecognized value of istate (= %" OCTAVE_IDX_TYPE_FORMAT ") "
370  "returned from ddasrt", istate);
371  break;
372  }
373 }
374 
377 {
379 
380  Matrix x_out;
381  Matrix xdot_out;
382  ColumnVector t_out = tout;
383 
384  octave_idx_type n_out = tout.numel ();
385  F77_INT n = octave::to_f77_int (size ());
386 
387  if (n_out > 0 && n > 0)
388  {
389  x_out.resize (n_out, n);
390  xdot_out.resize (n_out, n);
391 
392  for (F77_INT i = 0; i < n; i++)
393  {
394  x_out(0,i) = x(i);
395  xdot_out(0,i) = xdot(i);
396  }
397 
398  for (octave_idx_type j = 1; j < n_out; j++)
399  {
400  integrate (tout(j));
401 
402  if (integration_error)
403  {
404  retval = DASRT_result (x_out, xdot_out, t_out);
405  return retval;
406  }
407 
408  if (istate == 4)
409  t_out(j) = t;
410  else
411  t_out(j) = tout(j);
412 
413  for (F77_INT i = 0; i < n; i++)
414  {
415  x_out(j,i) = x(i);
416  xdot_out(j,i) = xdot(i);
417  }
418 
419  if (istate == 4)
420  {
421  x_out.resize (j+1, n);
422  xdot_out.resize (j+1, n);
423  t_out.resize (j+1);
424  break;
425  }
426  }
427  }
428 
429  retval = DASRT_result (x_out, xdot_out, t_out);
430 
431  return retval;
432 }
433 
435 DASRT::integrate (const ColumnVector& tout, const ColumnVector& tcrit)
436 {
438 
439  Matrix x_out;
440  Matrix xdot_out;
441  ColumnVector t_outs = tout;
442 
443  octave_idx_type n_out = tout.numel ();
444  F77_INT n = octave::to_f77_int (size ());
445 
446  if (n_out > 0 && n > 0)
447  {
448  x_out.resize (n_out, n);
449  xdot_out.resize (n_out, n);
450 
451  octave_idx_type n_crit = tcrit.numel ();
452 
453  if (n_crit > 0)
454  {
455  octave_idx_type i_crit = 0;
456  octave_idx_type i_out = 1;
457  double next_crit = tcrit(0);
458  double next_out;
459  while (i_out < n_out)
460  {
461  bool do_restart = false;
462 
463  next_out = tout(i_out);
464  if (i_crit < n_crit)
465  next_crit = tcrit(i_crit);
466 
467  bool save_output = false;
468  double t_out;
469 
470  if (next_crit == next_out)
471  {
472  set_stop_time (next_crit);
473  t_out = next_out;
474  save_output = true;
475  i_out++;
476  i_crit++;
477  do_restart = true;
478  }
479  else if (next_crit < next_out)
480  {
481  if (i_crit < n_crit)
482  {
483  set_stop_time (next_crit);
484  t_out = next_crit;
485  save_output = false;
486  i_crit++;
487  do_restart = true;
488  }
489  else
490  {
491  clear_stop_time ();
492  t_out = next_out;
493  save_output = true;
494  i_out++;
495  }
496  }
497  else
498  {
499  set_stop_time (next_crit);
500  t_out = next_out;
501  save_output = true;
502  i_out++;
503  }
504 
505  integrate (t_out);
506 
507  if (integration_error)
508  {
509  retval = DASRT_result (x_out, xdot_out, t_outs);
510  return retval;
511  }
512 
513  if (istate == 4)
514  t_out = t;
515 
516  if (save_output)
517  {
518  for (F77_INT i = 0; i < n; i++)
519  {
520  x_out(i_out-1,i) = x(i);
521  xdot_out(i_out-1,i) = xdot(i);
522  }
523 
524  t_outs(i_out-1) = t_out;
525 
526  if (istate == 4)
527  {
528  x_out.resize (i_out, n);
529  xdot_out.resize (i_out, n);
530  t_outs.resize (i_out);
531  i_out = n_out;
532  }
533  }
534 
535  if (do_restart)
536  force_restart ();
537  }
538 
539  retval = DASRT_result (x_out, xdot_out, t_outs);
540  }
541  else
542  {
543  retval = integrate (tout);
544 
545  if (integration_error)
546  return retval;
547  }
548  }
549 
550  return retval;
551 }
552 
553 std::string
555 {
556  std::string retval;
557 
558  std::ostringstream buf;
559  buf << t;
560  std::string t_curr = buf.str ();
561 
562  switch (istate)
563  {
564  case 1:
565  retval = "a step was successfully taken in intermediate-output mode.";
566  break;
567 
568  case 2:
569  retval = "integration completed by stepping exactly to TOUT";
570  break;
571 
572  case 3:
573  retval = "integration to tout completed by stepping past TOUT";
574  break;
575 
576  case 4:
577  retval = "integration completed by finding one or more roots of G at T";
578  break;
579 
580  case -1:
581  retval = "a large amount of work has been expended (t =" + t_curr + ')';
582  break;
583 
584  case -2:
585  retval = "the error tolerances are too stringent";
586  break;
587 
588  case -3:
589  retval = "error weight became zero during problem. (t = " + t_curr +
590  "; solution component i vanished, and atol or atol(i) == 0)";
591  break;
592 
593  case -6:
594  retval = "repeated error test failures on the last attempted step (t = "
595  + t_curr + ')';
596  break;
597 
598  case -7:
599  retval = "the corrector could not converge (t = " + t_curr + ')';
600  break;
601 
602  case -8:
603  retval = "the matrix of partial derivatives is singular (t = " + t_curr +
604  ')';
605  break;
606 
607  case -9:
608  retval = "the corrector could not converge (t = " + t_curr +
609  "; repeated test failures)";
610  break;
611 
612  case -10:
613  retval = "corrector could not converge because IRES was -1 (t = "
614  + t_curr + ')';
615  break;
616 
617  case -11:
618  retval = "return requested in user-supplied function (t = " + t_curr +
619  ')';
620  break;
621 
622  case -12:
623  retval = "failed to compute consistent initial conditions";
624  break;
625 
626  case -33:
627  retval = "unrecoverable error (see printed message)";
628  break;
629 
630  default:
631  retval = "unknown error state";
632  break;
633  }
634 
635  return retval;
636 }
F77_INT(* dasrt_jac_ptr)(const double &, const double *, const double *, double *, const double &, double *, F77_INT *)
Definition: DASRT.cc:41
F77_RET_T F77_FUNC(ddasrt, DDASRT)(dasrt_fcn_ptr
F77_INT(* dasrt_fcn_ptr)(const double &, const double *, const double *, double *, F77_INT &, double *, F77_INT *)
Definition: DASRT.cc:38
static F77_INT nn
Definition: DASRT.cc:64
F77_INT(* dasrt_constr_ptr)(const F77_INT &, const double &, const double *, const F77_INT &, double *, double *, F77_INT *)
Definition: DASRT.cc:44
F77_RET_T const F77_INT F77_DBLE F77_DBLE F77_DBLE const F77_DBLE F77_INT const F77_DBLE const F77_DBLE F77_INT F77_DBLE const F77_INT F77_INT const F77_INT F77_DBLE F77_INT const F77_INT F77_INT *static DAEFunc::DAERHSFunc user_fsub
Definition: DASRT.cc:56
F77_INT ddasrt_j(const double &time, const double *state, const double *deriv, double *pd, const double &cj, double *, F77_INT *)
Definition: DASRT.cc:97
static DAERTFunc::DAERTConstrFunc user_csub
Definition: DASRT.cc:62
static F77_INT ddasrt_f(const double &t, const double *state, const double *deriv, double *delta, F77_INT &ires, double *, F77_INT *)
Definition: DASRT.cc:67
static F77_INT ddasrt_g(const F77_INT &neq, const double &t, const double *state, const F77_INT &ng, double *gout, double *, F77_INT *)
Definition: DASRT.cc:121
static DAEFunc::DAEJacFunc user_jsub
Definition: DASRT.cc:61
void resize(const dim_vector &dv, const T &rfv)
Size of the specified dimension.
Definition: Array.cc:1011
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:377
T & elem(octave_idx_type n)
Size of the specified dimension.
Definition: Array.h:499
const T * fortran_vec(void) const
Size of the specified dimension.
Definition: Array.h:583
bool isempty(void) const
Size of the specified dimension.
Definition: Array.h:572
void resize(octave_idx_type n, const double &rfv=0)
Definition: dColVector.h:109
DAEJacFunc jacobian_function(void) const
Definition: DAEFunc.h:85
bool reset
Definition: DAEFunc.h:104
Matrix(* DAEJacFunc)(const ColumnVector &x, const ColumnVector &xdot, double t, double cj)
Definition: DAEFunc.h:47
ColumnVector(* DAERHSFunc)(const ColumnVector &x, const ColumnVector &xdot, double t, octave_idx_type &ires)
Definition: DAEFunc.h:39
DAERHSFunc function(void) const
Definition: DAEFunc.h:76
ColumnVector(* DAERTConstrFunc)(const ColumnVector &x, double t)
Definition: DAERTFunc.h:38
DAERTConstrFunc constraint_function(void) const
Definition: DAERTFunc.h:71
bool reset
Definition: DAERTFunc.h:89
Array< double > abs_tol
Definition: DASRT.h:124
Array< octave_f77_int_type > iwork
Definition: DASRT.h:119
DASRT_result integrate(const ColumnVector &tout)
Definition: DASRT.cc:376
Array< octave_f77_int_type > jroot
Definition: DASRT.h:120
Array< double > rwork
Definition: DASRT.h:122
Array< octave_f77_int_type > info
Definition: DASRT.h:118
octave_f77_int_type lrw
Definition: DASRT.h:114
octave_f77_int_type liw
Definition: DASRT.h:113
std::string error_message(void) const
Definition: DASRT.cc:554
Array< double > rel_tol
Definition: DASRT.h:125
octave_f77_int_type ng
Definition: DASRT.h:116
bool initialized
Definition: DASRT.h:111
Definition: dMatrix.h:42
void resize(octave_idx_type nr, octave_idx_type nc, double rfv=0)
Definition: dMatrix.h:151
ColumnVector xdot
Definition: base-dae.h:80
bool restart
Definition: base-de.h:116
virtual void force_restart(void)
Definition: base-de.h:98
double t
Definition: base-de.h:110
bool integration_error
Definition: base-de.h:118
double stop_time
Definition: base-de.h:112
octave_idx_type size(void) const
Definition: base-de.h:79
octave_idx_type istate
Definition: base-de.h:120
ColumnVector x
Definition: base-de.h:108
void set_stop_time(double tt)
Definition: base-de.h:85
bool stop_time_set
Definition: base-de.h:114
void clear_stop_time(void)
Definition: base-de.h:92
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:95
subroutine ddasrt(RES, NEQ, T, Y, YPRIME, TOUT, INFO, RTOL, ATOL, IDID, RWORK, LRW, IWORK, LIW, RPAR, IPAR, JAC, G, NG, JROOT)
Definition: ddasrt.f:4
#define F77_XFCN(f, F, args)
Definition: f77-fcn.h:44
double F77_DBLE
Definition: f77-fcn.h:301
octave_f77_int_type F77_INT
Definition: f77-fcn.h:305
F77_RET_T(F77_CONST_CHAR_ARG_DECL, F77_CONST_CHAR_ARG_DECL, F77_CONST_CHAR_ARG_DECL, const F77_INT &, const F77_INT &, const F77_INT &, F77_INT &, F77_INT &, F77_DBLE *, const F77_INT &, F77_DBLE *, const F77_INT &, F77_DBLE *, F77_DBLE *, F77_DBLE *, const F77_INT &, F77_DBLE *, const F77_INT &, F77_DBLE *, const F77_INT &, F77_DBLE *, F77_INT *, F77_INT &F77_CHAR_ARG_LEN_DECL F77_CHAR_ARG_LEN_DECL F77_CHAR_ARG_LEN_DECL)
octave_idx_type n
Definition: mx-inlines.cc:753
static uint32_t state[624]
Definition: randmtzig.cc:190
octave_value::octave_value(const Array< char > &chm, char type) return retval
Definition: ov.cc:811