GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
LSODE.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1993-2018 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
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License 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 <https://www.gnu.org/licenses/>.
20 
21 */
22 
23 #if defined (HAVE_CONFIG_H)
24 # include "config.h"
25 #endif
26 
27 #include <sstream>
28 
29 #include "LSODE.h"
30 #include "f77-fcn.h"
31 #include "lo-error.h"
32 #include "quit.h"
33 
34 typedef F77_INT (*lsode_fcn_ptr) (const F77_INT&, const double&, double*,
35  double*, F77_INT&);
36 
37 typedef F77_INT (*lsode_jac_ptr) (const F77_INT&, const double&, double*,
38  const F77_INT&, const F77_INT&, double*,
39  const F77_INT&);
40 
41 extern "C"
42 {
43  F77_RET_T
45  F77_DBLE&, F77_INT&, F77_DBLE&, const F77_DBLE*,
48  F77_INT&);
49 }
50 
54 
55 static F77_INT
56 lsode_f (const F77_INT& neq, const double& time, double *, double *deriv,
57  F77_INT& ierr)
58 {
59  BEGIN_INTERRUPT_WITH_EXCEPTIONS;
60 
61  ColumnVector tmp_deriv;
62 
63  // NOTE: this won't work if LSODE passes copies of the state vector.
64  // In that case we have to create a temporary vector object
65  // and copy.
66 
67  tmp_deriv = (*user_fun) (*tmp_x, time);
68 
69  if (tmp_deriv.isempty ())
70  ierr = -1;
71  else
72  {
73  for (F77_INT i = 0; i < neq; i++)
74  deriv[i] = tmp_deriv.elem (i);
75  }
76 
77  END_INTERRUPT_WITH_EXCEPTIONS;
78 
79  return 0;
80 }
81 
82 static F77_INT
83 lsode_j (const F77_INT& neq, const double& time, double *, const F77_INT&,
84  const F77_INT&, double *pd, const F77_INT& nrowpd)
85 {
86  BEGIN_INTERRUPT_WITH_EXCEPTIONS;
87 
88  Matrix tmp_jac (neq, neq);
89 
90  // NOTE: this won't work if LSODE passes copies of the state vector.
91  // In that case we have to create a temporary vector object
92  // and copy.
93 
94  tmp_jac = (*user_jac) (*tmp_x, time);
95 
96  for (F77_INT j = 0; j < neq; j++)
97  for (F77_INT i = 0; i < neq; i++)
98  pd[nrowpd * j + i] = tmp_jac (i, j);
99 
100  END_INTERRUPT_WITH_EXCEPTIONS;
101 
102  return 0;
103 }
104 
106 LSODE::do_integrate (double tout)
107 {
109 
110  static F77_INT nn = 0;
111 
112  if (! initialized || restart || ODEFunc::reset || LSODE_options::reset)
113  {
114  integration_error = false;
115 
116  initialized = true;
117 
118  istate = 1;
119 
120  F77_INT n = octave::to_f77_int (size ());
121 
122  nn = n;
123 
124  octave_idx_type max_maxord = 0;
125 
126  if (integration_method () == "stiff")
127  {
128  max_maxord = 5;
129 
130  if (jac)
131  method_flag = 21;
132  else
133  method_flag = 22;
134 
135  liw = 20 + n;
136  lrw = 22 + n * (9 + n);
137  }
138  else
139  {
140  max_maxord = 12;
141 
142  method_flag = 10;
143 
144  liw = 20;
145  lrw = 22 + 16 * n;
146  }
147 
148  iwork.resize (dim_vector (liw, 1));
149 
150  for (F77_INT i = 4; i < 9; i++)
151  iwork(i) = 0;
152 
153  rwork.resize (dim_vector (lrw, 1));
154 
155  for (F77_INT i = 4; i < 9; i++)
156  rwork(i) = 0;
157 
158  octave_idx_type maxord = maximum_order ();
159 
160  if (maxord >= 0)
161  {
162  if (maxord > 0 && maxord <= max_maxord)
163  {
164  iwork(4) = octave::to_f77_int (maxord);
165  iopt = 1;
166  }
167  else
168  {
169  // FIXME: Should this be a warning?
170  (*current_liboctave_error_handler)
171  ("lsode: invalid value for maximum order");
172  integration_error = true;
173  return retval;
174  }
175  }
176 
177  if (stop_time_set)
178  {
179  itask = 4;
180  rwork(0) = stop_time;
181  iopt = 1;
182  }
183  else
184  {
185  itask = 1;
186  }
187 
188  restart = false;
189 
190  // ODEFunc
191 
192  // NOTE: this won't work if LSODE passes copies of the state vector.
193  // In that case we have to create a temporary vector object
194  // and copy.
195 
196  tmp_x = &x;
197 
198  user_fun = function ();
200 
201  ColumnVector xdot = (*user_fun) (x, t);
202 
203  if (x.numel () != xdot.numel ())
204  {
205  // FIXME: Should this be a warning?
206  (*current_liboctave_error_handler)
207  ("lsode: inconsistent sizes for state and derivative vectors");
208 
209  integration_error = true;
210  return retval;
211  }
212 
213  ODEFunc::reset = false;
214 
215  // LSODE_options
216 
217  rel_tol = relative_tolerance ();
218  abs_tol = absolute_tolerance ();
219 
220  F77_INT abs_tol_len = octave::to_f77_int (abs_tol.numel ());
221 
222  if (abs_tol_len == 1)
223  itol = 1;
224  else if (abs_tol_len == n)
225  itol = 2;
226  else
227  {
228  // FIXME: Should this be a warning?
229  (*current_liboctave_error_handler)
230  ("lsode: inconsistent sizes for state and absolute tolerance vectors");
231 
232  integration_error = true;
233  return retval;
234  }
235 
236  double iss = initial_step_size ();
237  if (iss >= 0.0)
238  {
239  rwork(4) = iss;
240  iopt = 1;
241  }
242 
243  double maxss = maximum_step_size ();
244  if (maxss >= 0.0)
245  {
246  rwork(5) = maxss;
247  iopt = 1;
248  }
249 
250  double minss = minimum_step_size ();
251  if (minss >= 0.0)
252  {
253  rwork(6) = minss;
254  iopt = 1;
255  }
256 
257  F77_INT sl = octave::to_f77_int (step_limit ());
258  if (sl > 0)
259  {
260  iwork(5) = sl;
261  iopt = 1;
262  }
263 
264  LSODE_options::reset = false;
265  }
266 
267  double *px = x.fortran_vec ();
268 
269  double *pabs_tol = abs_tol.fortran_vec ();
270 
271  F77_INT *piwork = iwork.fortran_vec ();
272  double *prwork = rwork.fortran_vec ();
273 
274  F77_INT tmp_istate = octave::to_f77_int (istate);
275 
276  F77_XFCN (dlsode, DLSODE, (lsode_f, nn, px, t, tout, itol, rel_tol,
277  pabs_tol, itask, tmp_istate, iopt, prwork, lrw,
278  piwork, liw, lsode_j, method_flag));
279 
280  istate = tmp_istate;
281 
282  switch (istate)
283  {
284  case 1: // prior to initial integration step.
285  case 2: // lsode was successful.
286  retval = x;
287  t = tout;
288  break;
289 
290  case -1: // excess work done on this call (perhaps wrong mf).
291  case -2: // excess accuracy requested (tolerances too small).
292  case -3: // invalid input detected (see printed message).
293  case -4: // repeated error test failures (check all inputs).
294  case -5: // repeated convergence failures (perhaps bad Jacobian
295  // supplied or wrong choice of mf or tolerances).
296  case -6: // error weight became zero during problem. (solution
297  // component i vanished, and atol or atol(i) = 0.)
298  case -13: // return requested in user-supplied function.
299  integration_error = true;
300  break;
301 
302  default:
303  integration_error = true;
304  (*current_liboctave_error_handler)
305  ("unrecognized value of istate (= %d) returned from lsode", istate);
306  break;
307  }
308 
309  return retval;
310 }
311 
314 {
316 
317  std::ostringstream buf;
318  buf << t;
319  std::string t_curr = buf.str ();
320 
321  switch (istate)
322  {
323  case 1:
324  retval = "prior to initial integration step";
325  break;
326 
327  case 2:
328  retval = "successful exit";
329  break;
330 
331  case 3:
332  retval = "prior to continuation call with modified parameters";
333  break;
334 
335  case -1:
336  retval = "excess work on this call (t = " + t_curr +
337  "; perhaps wrong integration method)";
338  break;
339 
340  case -2:
341  retval = "excess accuracy requested (tolerances too small)";
342  break;
343 
344  case -3:
345  retval = "invalid input detected (see printed message)";
346  break;
347 
348  case -4:
349  retval = "repeated error test failures (t = " + t_curr +
350  "; check all inputs)";
351  break;
352 
353  case -5:
354  retval = "repeated convergence failures (t = " + t_curr +
355  "; perhaps bad Jacobian supplied or wrong choice of integration method or tolerances)";
356  break;
357 
358  case -6:
359  retval = "error weight became zero during problem. (t = " + t_curr +
360  "; solution component i vanished, and atol or atol(i) == 0)";
361  break;
362 
363  case -13:
364  retval = "return requested in user-supplied function (t = "
365  + t_curr + ')';
366  break;
367 
368  default:
369  retval = "unknown error state";
370  break;
371  }
372 
373  return retval;
374 }
375 
376 Matrix
378 {
379  Matrix retval;
380 
381  octave_idx_type n_out = tout.numel ();
382  F77_INT n = octave::to_f77_int (size ());
383 
384  if (n_out > 0 && n > 0)
385  {
386  retval.resize (n_out, n);
387 
388  for (F77_INT i = 0; i < n; i++)
389  retval.elem (0, i) = x.elem (i);
390 
391  for (octave_idx_type j = 1; j < n_out; j++)
392  {
393  ColumnVector x_next = do_integrate (tout.elem (j));
394 
395  if (integration_error)
396  return retval;
397 
398  for (F77_INT i = 0; i < n; i++)
399  retval.elem (j, i) = x_next.elem (i);
400  }
401  }
402 
403  return retval;
404 }
405 
406 Matrix
407 LSODE::do_integrate (const ColumnVector& tout, const ColumnVector& tcrit)
408 {
409  Matrix retval;
410 
411  octave_idx_type n_out = tout.numel ();
412  F77_INT n = octave::to_f77_int (size ());
413 
414  if (n_out > 0 && n > 0)
415  {
416  retval.resize (n_out, n);
417 
418  for (F77_INT i = 0; i < n; i++)
419  retval.elem (0, i) = x.elem (i);
420 
421  octave_idx_type n_crit = tcrit.numel ();
422 
423  if (n_crit > 0)
424  {
425  octave_idx_type i_crit = 0;
426  octave_idx_type i_out = 1;
427  double next_crit = tcrit.elem (0);
428  double next_out;
429  while (i_out < n_out)
430  {
431  bool do_restart = false;
432 
433  next_out = tout.elem (i_out);
434  if (i_crit < n_crit)
435  next_crit = tcrit.elem (i_crit);
436 
437  bool save_output = false;
438  double t_out;
439 
440  if (next_crit == next_out)
441  {
442  set_stop_time (next_crit);
443  t_out = next_out;
444  save_output = true;
445  i_out++;
446  i_crit++;
447  do_restart = true;
448  }
449  else if (next_crit < next_out)
450  {
451  if (i_crit < n_crit)
452  {
453  set_stop_time (next_crit);
454  t_out = next_crit;
455  save_output = false;
456  i_crit++;
457  do_restart = true;
458  }
459  else
460  {
461  clear_stop_time ();
462  t_out = next_out;
463  save_output = true;
464  i_out++;
465  }
466  }
467  else
468  {
469  set_stop_time (next_crit);
470  t_out = next_out;
471  save_output = true;
472  i_out++;
473  }
474 
475  ColumnVector x_next = do_integrate (t_out);
476 
477  if (integration_error)
478  return retval;
479 
480  if (save_output)
481  {
482  for (F77_INT i = 0; i < n; i++)
483  retval.elem (i_out-1, i) = x_next.elem (i);
484  }
485 
486  if (do_restart)
487  force_restart ();
488  }
489  }
490  else
491  {
492  retval = do_integrate (tout);
493 
494  if (integration_error)
495  return retval;
496  }
497  }
498 
499  return retval;
500 }
F77_RET_T F77_INT F77_DBLE F77_DBLE F77_DBLE F77_INT F77_DBLE const F77_DBLE F77_INT F77_INT F77_INT F77_DBLE F77_INT F77_INT F77_INT F77_INT &static ODEFunc::ODERHSFunc user_fun
Definition: LSODE.cc:44
octave_f77_int_type iopt
Definition: LSODE.h:65
ColumnVector(* ODERHSFunc)(const ColumnVector &, double)
Definition: ODEFunc.h:36
Array< double > abs_tol
Definition: LSODE.h:76
Matrix(* ODEJacFunc)(const ColumnVector &, double)
Definition: ODEFunc.h:37
ODEJacFunc jacobian_function(void) const
Definition: ODEFunc.h:73
static ColumnVector * tmp_x
Definition: LSODE.cc:53
bool isempty(void) const
Definition: Array.h:565
bool initialized
Definition: LSODE.h:61
F77_RET_T F77_FUNC(dlsode, DLSODE)(lsode_fcn_ptr
static F77_INT lsode_j(const F77_INT &neq, const double &time, double *, const F77_INT &, const F77_INT &, double *pd, const F77_INT &nrowpd)
Definition: LSODE.cc:83
const T * fortran_vec(void) const
Definition: Array.h:584
bool integration_error
Definition: base-de.h:115
static F77_INT nn
Definition: DASPK.cc:62
ColumnVector do_integrate(double t)
Definition: LSODE.cc:106
octave_idx_type istate
Definition: base-de.h:117
T & elem(octave_idx_type n)
Definition: Array.h:488
std::string error_message(void) const
Definition: LSODE.cc:313
#define F77_XFCN(f, F, args)
Definition: f77-fcn.h:41
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_value resize(const dim_vector &dv, bool fill=false) const
Definition: ov.h:511
octave_f77_int_type method_flag
Definition: LSODE.h:63
octave_f77_int_type itask
Definition: LSODE.h:64
octave_idx_type size(void) const
Definition: base-de.h:76
F77_INT(* lsode_fcn_ptr)(const F77_INT &, const double &, double *, double *, F77_INT &)
Definition: LSODE.cc:34
virtual void force_restart(void)
Definition: base-de.h:95
F77_INT(* lsode_jac_ptr)(const F77_INT &, const double &, double *, const F77_INT &, const F77_INT &, double *, const F77_INT &)
Definition: LSODE.cc:37
octave_f77_int_type itol
Definition: LSODE.h:66
Array< double > rwork
Definition: LSODE.h:72
void set_stop_time(double tt)
Definition: base-de.h:82
double t
Definition: base-de.h:107
void resize(const dim_vector &dv, const T &rfv)
Resizing (with fill).
Definition: Array.cc:1010
octave_value retval
Definition: data.cc:6246
Definition: dMatrix.h:36
Array< octave_f77_int_type > iwork
Definition: LSODE.h:71
ODEJacFunc jac
Definition: ODEFunc.h:85
void clear_stop_time(void)
Definition: base-de.h:89
double rel_tol
Definition: LSODE.h:74
static ODEFunc::ODEJacFunc user_jac
Definition: LSODE.cc:52
double stop_time
Definition: base-de.h:109
ColumnVector x
Definition: base-de.h:105
octave_f77_int_type F77_INT
Definition: f77-fcn.h:305
bool reset
Definition: ODEFunc.h:92
for i
Definition: data.cc:5264
static F77_INT lsode_f(const F77_INT &neq, const double &time, double *, double *deriv, F77_INT &ierr)
Definition: LSODE.cc:56
octave_f77_int_type liw
Definition: LSODE.h:68
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:366
bool restart
Definition: base-de.h:113
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:87
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 const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE const F77_INT F77_INT & ierr
subroutine DLSODE(F, NEQ, Y, T, TOUT, ITOL, RTOL, ATOL, ITASK, ISTATE, IOPT, RWORK, LRW, IWORK, LIW, JAC, MF)
Definition: dlsode.f:3
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:888
octave_f77_int_type lrw
Definition: LSODE.h:69
bool stop_time_set
Definition: base-de.h:111