GNU Octave 10.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
DASSL.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 1993-2025 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
39typedef F77_INT (*dassl_fcn_ptr) (const double&, const double *,
40 const double *, double *, F77_INT&,
41 double *, F77_INT *);
42
43typedef F77_INT (*dassl_jac_ptr) (const double&, const double *,
44 const double *, double *, const double&,
45 double *, F77_INT *);
46
47extern "C"
48{
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
58static DAEFunc::DAERHSFunc user_fcn;
59static DAEFunc::DAEJacFunc user_jac;
60
61static F77_INT nn;
62
63static F77_INT
64ddassl_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
99static F77_INT
100ddassl_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
125{
126 ColumnVector retval;
127
128 if (! m_initialized || m_restart || DAEFunc::m_reset
129 || DASSL_options::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.rwdata ();
276 double *pxdot = m_xdot.rwdata ();
277
278 F77_INT *pinfo = m_info.rwdata ();
279
280 double *prel_tol = m_rel_tol.rwdata ();
281 double *pabs_tol = m_abs_tol.rwdata ();
282
283 double *prwork = m_rwork.rwdata ();
284 F77_INT *piwork = m_iwork.rwdata ();
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
346Matrix
348{
349 Matrix dummy;
350 return integrate (tout, dummy);
351}
352
353Matrix
354DASSL::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
390Matrix
392{
393 Matrix dummy;
394 return integrate (tout, dummy, tcrit);
395}
396
397Matrix
398DASSL::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 {
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
501std::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:563
void resize(const dim_vector &dv, const T &rfv)
Size of the specified dimension.
bool isempty() const
Size of the specified dimension.
Definition Array.h:652
T * rwdata()
Size of the specified dimension.
octave_idx_type numel() const
Number of elements in the array.
Definition Array.h:418
DAEJacFunc jacobian_function() const
Definition DAEFunc.h:83
Matrix(* DAEJacFunc)(const ColumnVector &x, const ColumnVector &xdot, double t, double cj)
Definition DAEFunc.h:45
bool m_reset
Definition DAEFunc.h:102
DAERHSFunc function() const
Definition DAEFunc.h:74
ColumnVector(* DAERHSFunc)(const ColumnVector &x, const ColumnVector &xdot, double t, octave_idx_type &ires)
Definition DAEFunc.h:37
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
void resize(octave_idx_type nr, octave_idx_type nc, double rfv=0)
Definition dMatrix.h:156
ColumnVector m_xdot
Definition base-dae.h:79
double m_stop_time
Definition base-de.h:111
bool m_restart
Definition base-de.h:115
double m_t
Definition base-de.h:109
octave_idx_type m_istate
Definition base-de.h:119
virtual void force_restart()
Definition base-de.h:97
void clear_stop_time()
Definition base-de.h:91
bool m_stop_time_set
Definition base-de.h:113
octave_idx_type size() const
Definition base-de.h:78
bool m_integration_error
Definition base-de.h:117
ColumnVector m_x
Definition base-de.h:107
void set_stop_time(double tt)
Definition base-de.h:84
Vector representing the dimensions (size) of an Array.
Definition dim-vector.h:90
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)