GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
__ode15__.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2016-2018 Francesco Faccio <francesco.faccio@mail.polimi.it>
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 "dColVector.h"
28 #include "dMatrix.h"
29 #include "dSparse.h"
30 
31 #include "Cell.h"
32 #include "defun-dld.h"
33 #include "error.h"
34 #include "errwarn.h"
35 #include "oct-map.h"
36 #include "ov.h"
37 #include "ovl.h"
38 #include "parse.h"
39 
40 #if defined (HAVE_SUNDIALS)
41 
42 # if defined (HAVE_IDA_IDA_H)
43 # include <ida/ida.h>
44 # endif
45 
46 # if defined (HAVE_IDA_IDA_DENSE_H)
47 # include <ida/ida_dense.h>
48 # endif
49 
50 # if defined (HAVE_IDA_IDA_KLU_H)
51 # include <ida/ida_klu.h>
52 # include <sundials/sundials_sparse.h>
53 # endif
54 
55 # if defined (HAVE_NVECTOR_NVECTOR_SERIAL_H)
56 # include <nvector/nvector_serial.h>
57 # endif
58 
59 static inline realtype *
60 nv_data_s (N_Vector& v)
61 {
62 #if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
63  // Disable warning from GCC about old-style casts in Sundials
64  // macro expansions. Do this in a function so that this
65  // diagnostic may still be enabled for the rest of the file.
66 # pragma GCC diagnostic push
67 # pragma GCC diagnostic ignored "-Wold-style-cast"
68 #endif
69 
70  return NV_DATA_S (v);
71 
72 #if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
73  // Restore prevailing warning state for remainder of the file.
74 # pragma GCC diagnostic pop
75 #endif
76 }
77 
78 namespace octave
79 {
80  class IDA
81  {
82  public:
83 
84  typedef
85  ColumnVector (*DAERHSFuncIDA) (const ColumnVector& x,
86  const ColumnVector& xdot,
87  realtype t, octave_function *idaf);
88 
89  typedef
90  Matrix (*DAEJacFuncDense) (const ColumnVector& x,
91  const ColumnVector& xdot, realtype t,
92  realtype cj, octave_function *idaj);
93 
94  typedef
95  SparseMatrix (*DAEJacFuncSparse) (const ColumnVector& x,
96  const ColumnVector& xdot,
97  realtype t, realtype cj,
98  octave_function *idaj);
99 
100  typedef
101  Matrix (*DAEJacCellDense) (Matrix *dfdy, Matrix *dfdyp,
102  realtype cj);
103 
104  typedef
105  SparseMatrix (*DAEJacCellSparse) (SparseMatrix *dfdy,
106  SparseMatrix *dfdyp, realtype cj);
107 
108  //Default
109  IDA (void)
110  : t0 (0.0), y0 (), yp0 (), havejac (false), havejacfun (false),
111  havejacsparse (false), mem (nullptr), num (), ida_fun (nullptr),
112  ida_jac (nullptr), dfdy (nullptr), dfdyp (nullptr), spdfdy (nullptr),
113  spdfdyp (nullptr), fun (nullptr), jacfun (nullptr), jacspfun (nullptr),
114  jacdcell (nullptr), jacspcell (nullptr)
115  { }
116 
117 
118  IDA (realtype t, ColumnVector y, ColumnVector yp,
119  octave_function *ida_fcn, DAERHSFuncIDA daefun)
120  : t0 (t), y0 (y), yp0 (yp), havejac (false), havejacfun (false),
121  havejacsparse (false), mem (nullptr), num (), ida_fun (ida_fcn),
122  ida_jac (nullptr), dfdy (nullptr), dfdyp (nullptr), spdfdy (nullptr),
123  spdfdyp (nullptr), fun (daefun), jacfun (nullptr), jacspfun (nullptr),
124  jacdcell (nullptr), jacspcell (nullptr)
125  { }
126 
127 
128  ~IDA (void) { IDAFree (&mem); }
129 
130  IDA&
131  set_jacobian (octave_function *jac, DAEJacFuncDense j)
132  {
133  jacfun = j;
134  ida_jac = jac;
135  havejac = true;
136  havejacfun = true;
137  havejacsparse = false;
138  return *this;
139  }
140 
141  IDA&
142  set_jacobian (octave_function *jac, DAEJacFuncSparse j)
143  {
144  jacspfun = j;
145  ida_jac = jac;
146  havejac = true;
147  havejacfun = true;
148  havejacsparse = true;
149  return *this;
150  }
151 
152  IDA&
153  set_jacobian (Matrix *dy, Matrix *dyp, DAEJacCellDense j)
154  {
155  jacdcell = j;
156  dfdy = dy;
157  dfdyp = dyp;
158  havejac = true;
159  havejacfun = false;
160  havejacsparse = false;
161  return *this;
162  }
163 
164  IDA&
165  set_jacobian (SparseMatrix *dy, SparseMatrix *dyp,
166  DAEJacCellSparse j)
167  {
168  jacspcell = j;
169  spdfdy = dy;
170  spdfdyp = dyp;
171  havejac = true;
172  havejacfun = false;
173  havejacsparse = true;
174  return *this;
175  }
176 
177  void set_userdata (void);
178 
179  void initialize (void);
180 
181  static ColumnVector NVecToCol (N_Vector& v, long int n);
182 
183  static N_Vector ColToNVec (const ColumnVector& data, long int n);
184 
185  void
186  set_up (void);
187 
188  void
189  set_tolerance (ColumnVector& abstol, realtype reltol);
190 
191  void
192  set_tolerance (realtype abstol, realtype reltol);
193 
194  static int
195  resfun (realtype t, N_Vector yy, N_Vector yyp,
196  N_Vector rr, void *user_data);
197 
198  void
199  resfun_impl (realtype t, N_Vector& yy,
200  N_Vector& yyp, N_Vector& rr);
201 
202  static int
203  jacdense (long int Neq, realtype t, realtype cj, N_Vector yy,
204  N_Vector yyp, N_Vector, DlsMat JJ, void *user_data,
205  N_Vector, N_Vector, N_Vector)
206  {
207  IDA *self = static_cast <IDA *> (user_data);
208  self->jacdense_impl (Neq, t, cj, yy, yyp, JJ);
209  return 0;
210  }
211 
212  void
213  jacdense_impl (long int Neq, realtype t, realtype cj,
214  N_Vector& yy, N_Vector& yyp, DlsMat& JJ);
215 
216 # if defined (HAVE_SUNDIALS_IDAKLU)
217  static int
218  jacsparse (realtype t, realtype cj, N_Vector yy, N_Vector yyp,
219  N_Vector, SlsMat Jac, void *user_data, N_Vector,
220  N_Vector, N_Vector)
221  {
222  IDA *self = static_cast <IDA *> (user_data);
223  self->jacsparse_impl (t, cj, yy, yyp, Jac);
224  return 0;
225  }
226 
227  void
228  jacsparse_impl (realtype t, realtype cj, N_Vector& yy,
229  N_Vector& yyp, SlsMat& Jac);
230 #endif
231 
232  void set_maxstep (realtype maxstep);
233 
234  void set_initialstep (realtype initialstep);
235 
236  bool
237  interpolate (int& cont, Matrix& output, ColumnVector& tout,
238  int refine, realtype tend, bool haveoutputfcn,
239  bool haveoutputsel, octave_function *output_fcn,
240  ColumnVector& outputsel, bool haveeventfunction,
241  octave_function *event_fcn, ColumnVector& te,
242  Matrix& ye, ColumnVector& ie, ColumnVector& oldval,
243  ColumnVector& oldisterminal, ColumnVector& olddir,
244  int& temp, ColumnVector& yold);
245 
246  bool
247  outputfun (octave_function *output_fcn, bool haveoutputsel,
248  const ColumnVector& output, realtype tout, realtype tend,
249  ColumnVector& outputsel, const std::string& flag);
250 
251 
252  bool
253  event (octave_function *event_fcn,
254  ColumnVector& te, Matrix& ye, ColumnVector& ie,
255  realtype tsol, const ColumnVector& y, const std::string& flag,
256  const ColumnVector& yp, ColumnVector& oldval,
257  ColumnVector& oldisterminal, ColumnVector& olddir,
258  int cont, int& temp, realtype told, ColumnVector& yold);
259 
260  void set_maxorder (int maxorder);
261 
263  integrate (const int numt, const ColumnVector& tt,
264  const ColumnVector& y0, const ColumnVector& yp0,
265  const int refine, bool haverefine, bool haveoutputfcn,
266  octave_function *output_fcn, bool haveoutputsel,
267  ColumnVector& outputsel, bool haveeventfunction,
268  octave_function *event_fcn);
269 
270  void print_stat (void);
271 
272  private:
273 
274  realtype t0;
275  ColumnVector y0;
276  ColumnVector yp0;
277  bool havejac;
278  bool havejacfun;
279  bool havejacsparse;
280  void *mem;
281  int num;
282  octave_function *ida_fun;
283  octave_function *ida_jac;
284  Matrix *dfdy;
285  Matrix *dfdyp;
286  SparseMatrix *spdfdy;
287  SparseMatrix *spdfdyp;
288  DAERHSFuncIDA fun;
289  DAEJacFuncDense jacfun;
290  DAEJacFuncSparse jacspfun;
291  DAEJacCellDense jacdcell;
292  DAEJacCellSparse jacspcell;
293  };
294 
295  int
296  IDA::resfun (realtype t, N_Vector yy, N_Vector yyp, N_Vector rr,
297  void *user_data)
298  {
299  IDA *self = static_cast <IDA *> (user_data);
300  self->resfun_impl (t, yy, yyp, rr);
301  return 0;
302  }
303 
304  void
305  IDA::resfun_impl (realtype t, N_Vector& yy,
306  N_Vector& yyp, N_Vector& rr)
307  {
308  BEGIN_INTERRUPT_WITH_EXCEPTIONS;
309 
310  ColumnVector y = IDA::NVecToCol (yy, num);
311 
312  ColumnVector yp = IDA::NVecToCol (yyp, num);
313 
314  ColumnVector res = (*fun) (y, yp, t, ida_fun);
315 
316  realtype *puntrr = nv_data_s (rr);
317 
318  for (octave_idx_type i = 0; i < num; i++)
319  puntrr[i] = res(i);
320 
321  END_INTERRUPT_WITH_EXCEPTIONS;
322  }
323 
324  void
325  IDA::set_up (void)
326  {
327  if (havejacsparse)
328  {
329 # if defined (HAVE_SUNDIALS_IDAKLU)
330  if (IDAKLU (mem, num, num*num, CSC_MAT) != 0)
331  error ("IDAKLU solver not initialized");
332 
333  IDASlsSetSparseJacFn (mem, IDA::jacsparse);
334 # else
335  error ("IDAKLU is not available in this version of Octave");
336 # endif
337  }
338  else
339  {
340  if (IDADense (mem, num) != 0)
341  error ("IDADense solver not initialized");
342 
343  if (havejac && IDADlsSetDenseJacFn (mem, IDA::jacdense) != 0)
344  error ("Dense Jacobian not set");
345  }
346  }
347 
348  void
349  IDA::jacdense_impl (long int Neq, realtype t, realtype cj,
350  N_Vector& yy, N_Vector& yyp, DlsMat& JJ)
351 
352  {
353  BEGIN_INTERRUPT_WITH_EXCEPTIONS;
354 
355  ColumnVector y = NVecToCol (yy, Neq);
356 
357  ColumnVector yp = NVecToCol (yyp, Neq);
358 
359  Matrix jac;
360 
361  if (havejacfun)
362  jac = (*jacfun) (y, yp, t, cj, ida_jac);
363  else
364  jac = (*jacdcell) (dfdy, dfdyp, cj);
365 
366  std::copy (jac.fortran_vec (),
367  jac.fortran_vec () + jac.numel (),
368  JJ->data);
369 
370  END_INTERRUPT_WITH_EXCEPTIONS;
371  }
372 
373 # if defined (HAVE_SUNDIALS_IDAKLU)
374  void
375  IDA::jacsparse_impl (realtype t, realtype cj, N_Vector& yy, N_Vector& yyp,
376  SlsMat& Jac)
377 
378  {
379  BEGIN_INTERRUPT_WITH_EXCEPTIONS;
380 
381  ColumnVector y = NVecToCol (yy, num);
382 
383  ColumnVector yp = NVecToCol (yyp, num);
384 
385  SparseMatrix jac;
386 
387  if (havejacfun)
388  jac = (*jacspfun) (y, yp, t, cj, ida_jac);
389  else
390  jac = (*jacspcell) (spdfdy, spdfdyp, cj);
391 
392  SparseSetMatToZero (Jac);
393  int *colptrs = *(Jac->colptrs);
394  int *rowvals = *(Jac->rowvals);
395 
396  for (int i = 0; i < num + 1; i++)
397  colptrs[i] = jac.cidx(i);
398 
399  for (int i = 0; i < jac.nnz (); i++)
400  {
401  rowvals[i] = jac.ridx(i);
402  Jac->data[i] = jac.data(i);
403  }
404 
405  END_INTERRUPT_WITH_EXCEPTIONS;
406  }
407 #endif
408 
410  IDA::NVecToCol (N_Vector& v, long int n)
411  {
412  ColumnVector data (n);
413  realtype *punt = nv_data_s (v);
414 
415  for (octave_idx_type i = 0; i < n; i++)
416  data(i) = punt[i];
417 
418  return data;
419  }
420 
421  N_Vector
422  IDA::ColToNVec (const ColumnVector& data, long int n)
423  {
424  N_Vector v = N_VNew_Serial (n);
425 
426  realtype *punt = nv_data_s (v);
427 
428  for (octave_idx_type i = 0; i < n; i++)
429  punt[i] = data(i);
430 
431  return v;
432  }
433 
434  void
435  IDA::set_userdata (void)
436  {
437  void *userdata = this;
438 
439  if (IDASetUserData (mem, userdata) != 0)
440  error ("User data not set");
441  }
442 
443  void
444  IDA::initialize (void)
445  {
446  num = y0.numel ();
447  mem = IDACreate ();
448 
449  N_Vector yy = ColToNVec (y0, num);
450 
451  N_Vector yyp = ColToNVec (yp0, num);
452 
453  IDA::set_userdata ();
454 
455  if (IDAInit (mem, IDA::resfun, t0, yy, yyp) != 0)
456  error ("IDA not initialized");
457  }
458 
459  void
460  IDA::set_tolerance (ColumnVector& abstol, realtype reltol)
461  {
462  N_Vector abs_tol = ColToNVec (abstol, num);
463 
464  if (IDASVtolerances (mem, reltol, abs_tol) != 0)
465  error ("IDA: Tolerance not set");
466 
467  N_VDestroy_Serial (abs_tol);
468  }
469 
470  void
471  IDA::set_tolerance (realtype abstol, realtype reltol)
472  {
473  if (IDASStolerances (mem, reltol, abstol) != 0)
474  error ("IDA: Tolerance not set");
475  }
476 
478  IDA::integrate (const int numt, const ColumnVector& tspan,
479  const ColumnVector& y, const ColumnVector& yp,
480  const int refine, bool haverefine, bool haveoutputfcn,
481  octave_function *output_fcn, bool haveoutputsel,
482  ColumnVector& outputsel, bool haveeventfunction,
483  octave_function *event_fcn)
484  {
485  // Set up output
486  ColumnVector tout, yout (num), ypout (num), ysel (outputsel.numel ());
487  ColumnVector ie, te, oldval, oldisterminal, olddir;
488  Matrix output, ye;
489  int cont = 0, temp = 0;
490  bool status = 0;
491  std::string string = "";
492  ColumnVector yold = y;
493 
494  realtype tsol = tspan(0);
495  realtype tend = tspan(numt-1);
496 
497  N_Vector yyp = ColToNVec (yp, num);
498 
499  N_Vector yy = ColToNVec (y, num);
500 
501  // Initialize OutputFcn
502  if (haveoutputfcn)
503  status = IDA::outputfun (output_fcn, haveoutputsel, y,
504  tsol, tend, outputsel, "init");
505 
506  // Initialize Events
507  if (haveeventfunction)
508  status = IDA::event (event_fcn, te, ye, ie, tsol, y,
509  "init", yp, oldval, oldisterminal,
510  olddir, cont, temp, tsol, yold);
511 
512  if (numt > 2)
513  {
514  // First output value
515  tout.resize (numt);
516  tout(0) = tsol;
517  output.resize (numt, num);
518 
519  for (octave_idx_type i = 0; i < num; i++)
520  output.elem (0, i) = y.elem (i);
521 
522  //Main loop
523  for (octave_idx_type j = 1; j < numt && status == 0; j++)
524  {
525  // IDANORMAL already interpolates tspan(j)
526 
527  if (IDASolve (mem, tspan (j), &tsol, yy, yyp, IDA_NORMAL) != 0)
528  error ("IDASolve failed");
529 
530  yout = NVecToCol (yy, num);
531  ypout = NVecToCol (yyp, num);
532  tout(j) = tsol;
533 
534  for (octave_idx_type i = 0; i < num; i++)
535  output.elem (j, i) = yout.elem (i);
536 
537  if (haveoutputfcn)
538  status = IDA::outputfun (output_fcn, haveoutputsel, yout, tsol,
539  tend, outputsel, string);
540 
541  if (haveeventfunction)
542  status = IDA::event (event_fcn, te, ye, ie, tout(j), yout,
543  string, ypout, oldval, oldisterminal,
544  olddir, j, temp, tout(j-1), yold);
545 
546  // If integration is stopped, return only the reached steps
547  if (status == 1)
548  {
549  output.resize (j + 1, num);
550  tout.resize (j + 1);
551  }
552 
553  }
554  }
555  else // numel (tspan) == 2
556  {
557  // First output value
558  tout.resize (1);
559  tout(0) = tsol;
560  output.resize (1, num);
561 
562  for (octave_idx_type i = 0; i < num; i++)
563  output.elem (0, i) = y.elem (i);
564 
565  bool posdirection = (tend > tsol);
566 
567  //main loop
568  while (((posdirection == 1 && tsol < tend)
569  || (posdirection == 0 && tsol > tend))
570  && status == 0)
571  {
572  if (IDASolve (mem, tend, &tsol, yy, yyp, IDA_ONE_STEP) != 0)
573  error ("IDASolve failed");
574 
575  if (haverefine)
576  status = IDA::interpolate (cont, output, tout, refine, tend,
577  haveoutputfcn, haveoutputsel,
578  output_fcn, outputsel,
579  haveeventfunction, event_fcn, te,
580  ye, ie, oldval, oldisterminal,
581  olddir, temp, yold);
582 
583  ypout = NVecToCol (yyp, num);
584  cont += 1;
585  output.resize (cont + 1, num); // This may be not efficient
586  tout.resize (cont + 1);
587  tout(cont) = tsol;
588  yout = NVecToCol (yy, num);
589 
590  for (octave_idx_type i = 0; i < num; i++)
591  output.elem (cont, i) = yout.elem (i);
592 
593  if (haveoutputfcn && ! haverefine && tout(cont) < tend)
594  status = IDA::outputfun (output_fcn, haveoutputsel, yout, tsol,
595  tend, outputsel, string);
596 
597  if (haveeventfunction && ! haverefine && tout(cont) < tend)
598  status = IDA::event (event_fcn, te, ye, ie, tout(cont), yout,
599  string, ypout, oldval, oldisterminal,
600  olddir, cont, temp, tout(cont-1), yold);
601  }
602 
603  if (status == 0)
604  {
605  // Interpolate in tend
606  N_Vector dky = N_VNew_Serial (num);
607 
608  if (IDAGetDky (mem, tend, 0, dky) != 0)
609  error ("IDA failed to interpolate y");
610 
611  tout(cont) = tend;
612  yout = NVecToCol (dky, num);
613 
614  for (octave_idx_type i = 0; i < num; i++)
615  output.elem (cont, i) = yout.elem (i);
616 
617  // Plot final value
618  if (haveoutputfcn)
619  {
620  status = IDA::outputfun (output_fcn, haveoutputsel, yout,
621  tend, tend, outputsel, string);
622 
623  // Events during last step
624  if (haveeventfunction)
625  status = IDA::event (event_fcn, te, ye, ie, tend, yout,
626  string, ypout, oldval, oldisterminal,
627  olddir, cont, temp, tout(cont-1),
628  yold);
629  }
630 
631  N_VDestroy_Serial (dky);
632  }
633 
634  // Cleanup plotter
635  status = IDA::outputfun (output_fcn, haveoutputsel, yout, tend, tend,
636  outputsel, "done");
637 
638  }
639 
640  return ovl (tout, output, te, ye, ie);
641  }
642 
643  bool
644  IDA::event (octave_function *event_fcn,
645  ColumnVector& te, Matrix& ye, ColumnVector& ie,
646  realtype tsol, const ColumnVector& y, const std::string& flag,
647  const ColumnVector& yp, ColumnVector& oldval,
648  ColumnVector& oldisterminal, ColumnVector& olddir, int cont,
649  int& temp, realtype told, ColumnVector& yold)
650  {
651  bool status = 0;
652 
653  octave_value_list args = ovl (tsol, y, yp);
654 
655  // cont is the number of steps reached by the solver
656  // temp is the number of events registered
657 
658  if (flag == "init")
659  {
660  octave_value_list output = feval (event_fcn, args, 3);
661  oldval = output(0).vector_value ();
662  oldisterminal = output(1).vector_value ();
663  olddir = output(2).vector_value ();
664  }
665  else if (flag == "")
666  {
667  ColumnVector index (0);
668  octave_value_list output = feval (event_fcn, args, 3);
669  ColumnVector val = output(0).vector_value ();
670  ColumnVector isterminal = output(1).vector_value ();
671  ColumnVector dir = output(2).vector_value ();
672 
673  // Get the index of the changed values
674  for (octave_idx_type i = 0; i < val.numel (); i++)
675  {
676  if ((val(i) > 0 && oldval(i) < 0 && dir(i) != -1) // increasing
677  || (val(i) < 0 && oldval(i) > 0 && dir(i) != 1)) // decreasing
678  {
679  index.resize (index.numel () + 1);
680  index (index.numel () - 1) = i;
681  }
682  }
683 
684  if (cont == 1 && index.numel () > 0) // Events in first step
685  {
686  temp = 1; // register only the first event
687  te.resize (1);
688  ye.resize (1, num);
689  ie.resize (1);
690 
691  // Linear interpolation
692  ie(0) = index(0);
693  te(0) = tsol - val (index(0)) * (tsol - told)
694  / (val (index(0)) - oldval (index(0)));
695 
696  ColumnVector ytemp
697  = y - ((tsol - te(0)) * (y - yold) / (tsol - told));
698 
699  for (octave_idx_type i = 0; i < num; i++)
700  ye.elem (0, i) = ytemp.elem (i);
701 
702  }
703  else if (index.numel () > 0)
704  // Not first step: register all events and test if stop integration or not
705  {
706  te.resize (temp + index.numel ());
707  ye.resize (temp + index.numel (), num);
708  ie.resize (temp + index.numel ());
709 
710  for (octave_idx_type i = 0; i < index.numel (); i++)
711  {
712 
713  if (isterminal (index(i)) == 1)
714  status = 1; // Stop integration
715 
716  // Linear interpolation
717  ie(temp+i) = index(i);
718  te(temp+i) = tsol - val(index(i)) * (tsol - told)
719  / (val(index(i)) - oldval(index(i)));
720 
721  ColumnVector ytemp
722  = y - (tsol - te (temp + i)) * (y - yold) / (tsol - told);
723 
724  for (octave_idx_type j = 0; j < num; j++)
725  ye.elem (temp + i, j) = ytemp.elem (j);
726 
727  }
728 
729  temp += index.numel ();
730  }
731 
732  // Update variables
733  yold = y;
734  told = tsol;
735  olddir = dir;
736  oldval = val;
737  oldisterminal = isterminal;
738  }
739 
740  return status;
741  }
742 
743  bool
744  IDA::interpolate (int& cont, Matrix& output, ColumnVector& tout,
745  int refine, realtype tend, bool haveoutputfcn,
746  bool haveoutputsel, octave_function *output_fcn,
747  ColumnVector& outputsel, bool haveeventfunction,
748  octave_function *event_fcn, ColumnVector& te,
749  Matrix& ye, ColumnVector& ie, ColumnVector& oldval,
750  ColumnVector& oldisterminal, ColumnVector& olddir,
751  int& temp, ColumnVector& yold)
752  {
753  realtype h = 0, tcur = 0;
754  bool status = 0;
755 
756  N_Vector dky = N_VNew_Serial (num);
757 
758  N_Vector dkyp = N_VNew_Serial (num);
759 
760  ColumnVector yout (num);
761  ColumnVector ypout (num);
762  std::string string = "";
763 
764  if (IDAGetLastStep (mem, &h) != 0)
765  error ("IDA failed to return last step");
766 
767  if (IDAGetCurrentTime (mem, &tcur) != 0)
768  error ("IDA failed to return the current time");
769 
770  realtype tin = tcur - h;
771 
772  realtype step = h / refine;
773 
774  for (octave_idx_type i = 1;
775  i < refine && tin + step * i < tend && status == 0;
776  i++)
777  {
778  if (IDAGetDky (mem, tin + step*i, 0, dky) != 0)
779  error ("IDA failed to interpolate y");
780 
781  if (IDAGetDky (mem, tin + step*i, 1, dkyp) != 0)
782  error ("IDA failed to interpolate yp");
783 
784  cont += 1;
785  output.resize (cont + 1, num);
786  tout.resize (cont + 1);
787 
788  tout(cont) = tin + step * i;
789  yout = NVecToCol (dky, num);
790  ypout = NVecToCol (dkyp, num);
791 
792  for (octave_idx_type j = 0; j < num; j++)
793  output.elem (cont, j) = yout.elem (j);
794 
795  if (haveoutputfcn)
796  status = IDA::outputfun (output_fcn, haveoutputsel, yout,
797  tout(cont), tend, outputsel, "");
798 
799  if (haveeventfunction)
800  status = IDA::event (event_fcn, te, ye, ie, tout(cont),
801  yout, string, ypout, oldval,
802  oldisterminal, olddir, cont, temp,
803  tout(cont-1), yold);
804  }
805 
806  N_VDestroy_Serial (dky);
807 
808  return status;
809  }
810 
811  bool
812  IDA::outputfun (octave_function *output_fcn, bool haveoutputsel,
813  const ColumnVector& yout, realtype tsol,
814  realtype tend, ColumnVector& outputsel,
815  const std::string& flag)
816  {
817  bool status = 0;
818 
819  octave_value_list output;
820  output(2) = flag;
821 
822  ColumnVector ysel (outputsel.numel ());
823  if (haveoutputsel)
824  {
825  for (octave_idx_type i = 0; i < outputsel.numel (); i++)
826  ysel(i) = yout(outputsel(i));
827 
828  output(1) = ysel;
829  }
830  else
831  output(1) = yout;
832 
833  if (flag == "init")
834  {
835  ColumnVector toutput(2);
836  toutput(0) = tsol;
837  toutput(1) = tend;
838  output(0) = toutput;
839 
840  feval (output_fcn, output, 0);
841  }
842  else if (flag == "")
843  {
844  output(0) = tsol;
845  octave_value_list val = feval (output_fcn, output, 1);
846  status = val(0).bool_value ();
847  }
848  else
849  {
850  // Cleanup plotter
851  output(0) = tend;
852  feval (output_fcn, output, 0);
853  }
854 
855  return status;
856  }
857 
858  void
859  IDA::set_maxstep (realtype maxstep)
860  {
861  if (IDASetMaxStep (mem, maxstep) != 0)
862  error ("IDA: Max Step not set");
863  }
864 
865  void
866  IDA::set_initialstep (realtype initialstep)
867  {
868  if (IDASetInitStep (mem, initialstep) != 0)
869  error ("IDA: Initial Step not set");
870  }
871 
872  void
873  IDA::set_maxorder (int maxorder)
874  {
875  if (IDASetMaxOrd (mem, maxorder) != 0)
876  error ("IDA: Max Order not set");
877  }
878 
879  void
880  IDA::print_stat (void)
881  {
882  long int nsteps = 0, netfails = 0, nrevals = 0;
883 
884  if (IDAGetNumSteps (mem, &nsteps) != 0)
885  error ("IDA failed to return the number of internal steps");
886 
887  if (IDAGetNumErrTestFails (mem, &netfails) != 0)
888  error ("IDA failed to return the number of internal errors");
889 
890  if (IDAGetNumResEvals (mem, &nrevals) != 0)
891  error ("IDA failed to return the number of residual evaluations");
892 
893  std::cout << nsteps << " successful steps\n";
894  std::cout << netfails << " failed attempts\n";
895  std::cout << nrevals << " function evaluations\n";
896  // std::cout << " partial derivatives\n";
897  // std::cout << " LU decompositions\n";
898  // std::cout << " solutions of linear systems\n";
899  }
900 
902  ida_user_function (const ColumnVector& x, const ColumnVector& xdot,
903  double t, octave_function *ida_fc)
904  {
906 
907  try
908  {
909  tmp = feval (ida_fc, ovl (t, x, xdot), 1);
910  }
911  catch (execution_exception& e)
912  {
913  err_user_supplied_eval (e, "__ode15__");
914  }
915 
916  return tmp(0).vector_value ();
917  }
918 
919  Matrix
920  ida_dense_jac (const ColumnVector& x, const ColumnVector& xdot,
921  double t, double cj, octave_function *ida_jc)
922  {
924 
925  try
926  {
927  tmp = feval (ida_jc, ovl (t, x, xdot), 2);
928  }
929  catch (execution_exception& e)
930  {
931  err_user_supplied_eval (e, "__ode15__");
932  }
933 
934  return tmp(0).matrix_value () + cj * tmp(1).matrix_value ();
935  }
936 
938  ida_sparse_jac (const ColumnVector& x, const ColumnVector& xdot,
939  double t, double cj, octave_function *ida_jc)
940  {
942 
943  try
944  {
945  tmp = feval (ida_jc, ovl (t, x, xdot), 2);
946  }
947  catch (execution_exception& e)
948  {
949  err_user_supplied_eval (e, "__ode15__");
950  }
951 
952  return tmp(0).sparse_matrix_value () + cj * tmp(1).sparse_matrix_value ();
953  }
954 
955  Matrix
956  ida_dense_cell_jac (Matrix *dfdy, Matrix *dfdyp, double cj)
957  {
958  return (*dfdy) + cj * (*dfdyp);
959  }
960 
962  ida_sparse_cell_jac (SparseMatrix *spdfdy, SparseMatrix *spdfdyp,
963  double cj)
964  {
965  return (*spdfdy) + cj * (*spdfdyp);
966  }
967 
969  do_ode15 (octave_function *ida_fcn,
970  const ColumnVector& tspan,
971  const int numt,
972  const realtype t0,
973  const ColumnVector& y0,
974  const ColumnVector& yp0,
975  const octave_scalar_map& options)
976  {
978 
979  // Create object
980  IDA dae (t0, y0, yp0, ida_fcn, ida_user_function);
981 
982  // Set Jacobian
983  bool havejac = options.getfield ("havejac").bool_value ();
984 
985  bool havejacsparse = options.getfield ("havejacsparse").bool_value ();
986 
987  bool havejacfun = options.getfield ("havejacfun").bool_value ();
988 
989  Matrix ida_dfdy, ida_dfdyp, *dfdy, *dfdyp;
990  SparseMatrix ida_spdfdy, ida_spdfdyp, *spdfdy, *spdfdyp;
991  octave_function *ida_jac;
992  Cell jaccell;
993 
994  if (havejac)
995  {
996  if (havejacfun)
997  {
998  ida_jac = options.getfield ("Jacobian").function_value ();
999 
1000  if (havejacsparse)
1001  dae.set_jacobian (ida_jac, ida_sparse_jac);
1002  else
1003  dae.set_jacobian (ida_jac, ida_dense_jac);
1004  }
1005  else
1006  {
1007  jaccell = options.getfield ("Jacobian").cell_value ();
1008 
1009  if (havejacsparse)
1010  {
1011  ida_spdfdy = jaccell(0).sparse_matrix_value ();
1012  ida_spdfdyp = jaccell(1).sparse_matrix_value ();
1013  spdfdy = &ida_spdfdy;
1014  spdfdyp = &ida_spdfdyp;
1015  dae.set_jacobian (spdfdy, spdfdyp, ida_sparse_cell_jac);
1016  }
1017  else
1018  {
1019  ida_dfdy = jaccell(0).matrix_value ();
1020  ida_dfdyp = jaccell(1).matrix_value ();
1021  dfdy = &ida_dfdy;
1022  dfdyp = &ida_dfdyp;
1023  dae.set_jacobian (dfdy, dfdyp, ida_dense_cell_jac);
1024  }
1025  }
1026  }
1027 
1028  // Initialize IDA
1029  dae.initialize ();
1030 
1031  // Set tolerances
1032  realtype rel_tol = options.getfield("RelTol").double_value ();
1033 
1034  bool haveabstolvec = options.getfield ("haveabstolvec").bool_value ();
1035 
1036  if (haveabstolvec)
1037  {
1038  ColumnVector abs_tol = options.getfield("AbsTol").vector_value ();
1039 
1040  dae.set_tolerance (abs_tol, rel_tol);
1041  }
1042  else
1043  {
1044  realtype abs_tol = options.getfield("AbsTol").double_value ();
1045 
1046  dae.set_tolerance (abs_tol, rel_tol);
1047  }
1048 
1049  //Set max step
1050  realtype maxstep = options.getfield("MaxStep").double_value ();
1051 
1052  dae.set_maxstep (maxstep);
1053 
1054  //Set initial step
1055  if (! options.getfield("InitialStep").isempty ())
1056  {
1057  realtype initialstep = options.getfield("InitialStep").double_value ();
1058 
1059  dae.set_initialstep (initialstep);
1060  }
1061 
1062  //Set max order FIXME: it doesn't work
1063  int maxorder = options.getfield("MaxOrder").int_value ();
1064 
1065  dae.set_maxorder (maxorder);
1066 
1067  //Set Refine
1068  const int refine = options.getfield("Refine").int_value ();
1069 
1070  bool haverefine = (refine > 1);
1071 
1072  octave_function *output_fcn = nullptr;
1073  ColumnVector outputsel;
1074 
1075  // OutputFcn
1076  bool haveoutputfunction
1077  = options.getfield("haveoutputfunction").bool_value ();
1078 
1079  if (haveoutputfunction)
1080  output_fcn = options.getfield("OutputFcn").function_value ();
1081 
1082  // OutputSel
1083  bool haveoutputsel = options.getfield("haveoutputselection").bool_value ();
1084 
1085  if (haveoutputsel)
1086  outputsel = options.getfield("OutputSel").vector_value ();
1087 
1088  octave_function *event_fcn = nullptr;
1089 
1090  // Events
1091  bool haveeventfunction
1092  = options.getfield("haveeventfunction").bool_value ();
1093 
1094  if (haveeventfunction)
1095  event_fcn = options.getfield("Events").function_value ();
1096 
1097  // Set up linear solver
1098  dae.set_up ();
1099 
1100  // Integrate
1101  retval = dae.integrate (numt, tspan, y0, yp0, refine,
1102  haverefine, haveoutputfunction,
1103  output_fcn, haveoutputsel, outputsel,
1104  haveeventfunction, event_fcn);
1105 
1106  // Statistics
1107  bool havestats = options.getfield("havestats").bool_value ();
1108 
1109  if (havestats)
1110  dae.print_stat ();
1111 
1112  return retval;
1113  }
1114 }
1115 #endif
1116 
1117 
1118 DEFUN_DLD (__ode15__, args, ,
1119  doc: /* -*- texinfo -*-
1120 @deftypefn {} {@var{t}, @var{y} =} __ode15__ (@var{fun}, @var{tspan}, @var{y0}, @var{yp0}, @var{options})
1121 Undocumented internal function.
1122 @end deftypefn */)
1123 {
1124 
1125 #if defined (HAVE_SUNDIALS)
1126 
1127  // Check number of parameters
1128  int nargin = args.length ();
1129 
1130  if (nargin != 5)
1131  print_usage ();
1132 
1133  // Check odefun
1134  octave_function *ida_fcn = nullptr;
1135 
1136  octave_value f_arg = args(0);
1137 
1138  if (! f_arg.is_function_handle ())
1139  error ("__ode15__: odefun must be a function handle");
1140 
1141  ida_fcn = f_arg.function_value ();
1142 
1143  // Check input tspan
1144  ColumnVector tspan
1145  = args(1).xvector_value ("__ode15__: TRANGE must be a vector of numbers");
1146 
1147  int numt = tspan.numel ();
1148 
1149  realtype t0 = tspan (0);
1150 
1151  if (numt < 2)
1152  error ("__ode15__: TRANGE must contain at least 2 elements");
1153  else if (! tspan.issorted () || tspan(0) == tspan(numt - 1))
1154  error ("__ode15__: TRANGE must be strictly monotonic");
1155 
1156  // input y0 and yp0
1157  ColumnVector y0
1158  = args(2).xvector_value ("__ode15__: initial state y0 must be a vector");
1159 
1160  ColumnVector yp0
1161  = args(3).xvector_value ("__ode15__: initial state yp0 must be a vector");
1162 
1163 
1164  if (y0.numel () != yp0.numel ())
1165  error ("__ode15__: initial state y0 and yp0 must have the same length");
1166  else if (y0.numel () < 1)
1167  error ("__ode15__: initial state yp0 must be a vector or a scalar");
1168 
1169 
1170  if (! args(4).isstruct ())
1171  error ("__ode15__: OPTS argument must be a structure");
1172 
1174  = args(4).xscalar_map_value ("__ode15__: OPTS argument must be a scalar structure");
1175 
1176 
1177  return octave::do_ode15 (ida_fcn, tspan, numt, t0, y0, yp0, options);
1178 
1179 
1180 #else
1181 
1182  octave_unused_parameter (args);
1183 
1184  err_disabled_feature ("__ode15__", "sundials_ida, sundials_nvecserial");
1185 
1186 #endif
1187 }
OCTINTERP_API octave_value_list feval(const std::string &name, const octave_value_list &args=octave_value_list(), int nargout=0)
Definition: Cell.h:37
void resize(octave_idx_type nr, octave_idx_type nc, double rfv=0)
Definition: dMatrix.h:148
OCTINTERP_API void print_usage(void)
Definition: defun.cc:54
identity matrix If supplied two scalar respectively For allows like xample val
Definition: data.cc:4986
void error(const char *fmt,...)
Definition: error.cc:578
T & elem(octave_idx_type n)
Definition: Array.h:488
OCTAVE_EXPORT octave_value_list return the number of command line arguments passed to Octave If called with the optional argument the function t
Definition: ov-usr-fcn.cc:997
i e
Definition: data.cc:2591
static void initialize(void)
double h
Definition: graphics.cc:11808
sortmode issorted(sortmode mode=UNSORTED) const
Ordering is auto-detected or can be specified.
Definition: Array.cc:2033
bool is_function_handle(void) const
Definition: ov.h:749
double tmp
Definition: data.cc:6252
is false
Definition: cellfun.cc:400
octave_value retval
Definition: data.cc:6246
octave_function * function_value(bool silent=false) const
Definition: dMatrix.h:36
void err_user_supplied_eval(const char *name)
Definition: errwarn.cc:148
OCTAVE_EXPORT octave_value_list isa nd deftypefn *return ovl(args(0).isinteger())
OCTAVE_EXPORT octave_value_list only variables visible in the local scope are displayed The following are valid options
Definition: variables.cc:1862
Cell cell_value(void) const
Definition: ovl.h:88
octave_idx_type length(void) const
Definition: ovl.h:96
the element is set to zero In other the statement xample y
Definition: data.cc:5264
void resize(octave_idx_type n, const octave_value &rfv=octave_value())
Definition: ovl.h:100
args.length() nargin
Definition: file-io.cc:589
for i
Definition: data.cc:5264
#define DEFUN_DLD(name, args_name, nargout_name, doc)
Macro to define an at run time dynamically loadable builtin function.
Definition: defun-dld.h:58
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:366
void err_disabled_feature(const std::string &fcn, const std::string &feature, const std::string &pkg)
Definition: errwarn.cc:50
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
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 * x
void resize(octave_idx_type n, const double &rfv=0)
Definition: dColVector.h:107