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