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