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