26 #if defined (HAVE_CONFIG_H)
44 #if defined (HAVE_SUNDIALS)
46 # if defined (HAVE_NVECTOR_NVECTOR_SERIAL_H)
47 # include <nvector/nvector_serial.h>
50 # if defined (HAVE_IDA_IDA_H)
52 # elif defined (HAVE_IDA_H)
55 # if defined (HAVE_IDA_IDA_DIRECT_H)
56 # include <ida/ida_direct.h>
57 # elif defined (HAVE_IDA_DIRECT_H)
58 # include <ida_direct.h>
61 # if defined (HAVE_SUNLINSOL_SUNLINSOL_DENSE_H)
62 # include <sunlinsol/sunlinsol_dense.h>
65 # if defined (HAVE_SUNLINSOL_SUNLINSOL_KLU_H)
66 # if defined (HAVE_KLU_H)
69 # if defined (HAVE_KLU_KLU_H)
72 # if defined (HAVE_SUITESPARSE_KLU_H)
73 # include <suitesparse/klu.h>
75 # if defined (HAVE_UFPARSE_KLU_H)
76 # include <ufsparse/klu.h>
78 # include <sunlinsol/sunlinsol_klu.h>
83 # if ! defined (HAVE_IDASETJACFN) && defined (HAVE_IDADLSSETJACFN)
85 IDASetJacFn (
void *ida_mem, IDADlsJacFn jac)
87 return IDADlsSetJacFn (ida_mem, jac);
91 # if ! defined (HAVE_IDASETLINEARSOLVER) && defined (HAVE_IDADLSSETLINEARSOLVER)
93 IDASetLinearSolver (
void *ida_mem, SUNLinearSolver LS, SUNMatrix
A)
95 return IDADlsSetLinearSolver (ida_mem, LS,
A);
99 # if ! defined (HAVE_SUNLINSOL_DENSE) && defined (HAVE_SUNDENSELINEARSOLVER)
100 static inline SUNLinearSolver
101 SUNLinSol_Dense (N_Vector y, SUNMatrix
A)
103 return SUNDenseLinearSolver (y,
A);
107 # if defined (HAVE_SUNDIALS_SUNLINSOL_KLU)
108 # if ! defined (HAVE_SUNLINSOL_KLU) && defined (HAVE_SUNKLU)
109 static inline SUNLinearSolver
110 SUNLinSol_KLU (N_Vector y, SUNMatrix
A)
112 return SUNKLU (y,
A);
117 static inline realtype *
118 nv_data_s (N_Vector& v)
120 #if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
124 # pragma GCC diagnostic push
125 # pragma GCC diagnostic ignored "-Wold-style-cast"
128 return NV_DATA_S (v);
130 #if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
132 # pragma GCC diagnostic pop
153 realtype t, realtype cj,
166 : m_t0 (0.0), m_y0 (), m_yp0 (), m_havejac (false), m_havejacfun (false),
167 m_havejacsparse (false), m_mem (nullptr), m_num (), m_ida_fun (),
168 m_ida_jac (), m_dfdy (nullptr), m_dfdyp (nullptr), m_spdfdy (nullptr),
169 m_spdfdyp (nullptr), m_fun (nullptr), m_jacfun (nullptr), m_jacspfun (nullptr),
170 m_jacdcell (nullptr), m_jacspcell (nullptr),
171 m_sunJacMatrix (nullptr), m_sunLinearSolver (nullptr)
177 : m_t0 (t), m_y0 (y), m_yp0 (yp), m_havejac (false), m_havejacfun (false),
178 m_havejacsparse (false), m_mem (nullptr), m_num (), m_ida_fun (ida_fcn),
179 m_ida_jac (), m_dfdy (nullptr), m_dfdyp (nullptr), m_spdfdy (nullptr),
180 m_spdfdyp (nullptr), m_fun (daefun), m_jacfun (nullptr), m_jacspfun (nullptr),
181 m_jacdcell (nullptr), m_jacspcell (nullptr),
182 m_sunJacMatrix (nullptr), m_sunLinearSolver (nullptr)
189 SUNLinSolFree (m_sunLinearSolver);
190 SUNMatDestroy (m_sunJacMatrix);
194 set_jacobian (
const octave_value& jac, DAEJacFuncDense j)
200 m_havejacsparse =
false;
206 set_jacobian (
const octave_value& jac, DAEJacFuncSparse j)
212 m_havejacsparse =
true;
218 set_jacobian (
Matrix *dy,
Matrix *dyp, DAEJacCellDense j)
224 m_havejacfun =
false;
225 m_havejacsparse =
false;
238 m_havejacfun =
false;
239 m_havejacsparse =
true;
244 void set_userdata (
void);
250 static N_Vector ColToNVec (
const ColumnVector& data,
long int n);
259 set_tolerance (realtype abstol, realtype reltol);
262 resfun (realtype t, N_Vector yy, N_Vector yyp,
263 N_Vector rr,
void *user_data);
266 resfun_impl (realtype t, N_Vector& yy,
267 N_Vector& yyp, N_Vector& rr);
269 jacdense (realtype t, realtype cj, N_Vector yy,
270 N_Vector yyp, N_Vector, SUNMatrix JJ,
void *user_data,
271 N_Vector, N_Vector, N_Vector)
273 IDA *
self =
static_cast <IDA *
> (user_data);
274 self->jacdense_impl (t, cj, yy, yyp, JJ);
279 jacdense_impl (realtype t, realtype cj,
280 N_Vector& yy, N_Vector& yyp, SUNMatrix& JJ);
282 # if defined (HAVE_SUNDIALS_SUNLINSOL_KLU)
284 jacsparse (realtype t, realtype cj, N_Vector yy, N_Vector yyp,
285 N_Vector, SUNMatrix Jac,
void *user_data, N_Vector,
288 IDA *
self =
static_cast <IDA *
> (user_data);
289 self->jacsparse_impl (t, cj, yy, yyp, Jac);
294 jacsparse_impl (realtype t, realtype cj, N_Vector& yy,
295 N_Vector& yyp, SUNMatrix& Jac);
298 void set_maxstep (realtype maxstep);
300 void set_initialstep (realtype initialstep);
304 int refine, realtype tend,
bool haveoutputfcn,
313 outputfun (
const octave_value& output_fcn,
bool haveoutputsel,
314 const ColumnVector& output, realtype tout, realtype tend,
321 realtype tsol,
const ColumnVector& y,
const std::string& flag,
324 int cont,
int& temp, realtype told,
ColumnVector& yold);
326 void set_maxorder (
int maxorder);
331 const int refine,
bool haverefine,
bool haveoutputfcn,
336 void print_stat (
void);
345 bool m_havejacsparse;
355 DAEJacFuncDense m_jacfun;
356 DAEJacFuncSparse m_jacspfun;
357 DAEJacCellDense m_jacdcell;
358 DAEJacCellSparse m_jacspcell;
359 SUNMatrix m_sunJacMatrix;
360 SUNLinearSolver m_sunLinearSolver;
364 IDA::resfun (realtype t, N_Vector yy, N_Vector yyp, N_Vector rr,
367 IDA *
self =
static_cast <IDA *
> (user_data);
368 self->resfun_impl (t, yy, yyp, rr);
373 IDA::resfun_impl (realtype t, N_Vector& yy,
374 N_Vector& yyp, N_Vector& rr)
382 realtype *puntrr = nv_data_s (rr);
391 N_Vector yy = ColToNVec(y, m_num);
395 # if defined (HAVE_SUNDIALS_SUNLINSOL_KLU)
399 m_sunJacMatrix = SUNSparseMatrix (m_num, m_num, m_num*m_num, CSC_MAT);
400 if (! m_sunJacMatrix)
401 error (
"Unable to create sparse Jacobian for Sundials");
403 m_sunLinearSolver = SUNLinSol_KLU (yy, m_sunJacMatrix);
404 if (! m_sunLinearSolver)
405 error (
"Unable to create KLU sparse solver");
407 if (IDASetLinearSolver (m_mem, m_sunLinearSolver, m_sunJacMatrix))
408 error (
"Unable to set sparse linear solver");
410 IDASetJacFn (m_mem, IDA::jacsparse);
413 error (
"SUNDIALS SUNLINSOL KLU is not available in this version of Octave");
420 m_sunJacMatrix = SUNDenseMatrix (m_num, m_num);
421 if (! m_sunJacMatrix)
422 error (
"Unable to create dense Jacobian for Sundials");
424 m_sunLinearSolver = SUNLinSol_Dense (yy, m_sunJacMatrix);
425 if (! m_sunLinearSolver)
426 error (
"Unable to create dense linear solver");
428 if (IDASetLinearSolver (m_mem, m_sunLinearSolver, m_sunJacMatrix))
429 error (
"Unable to set dense linear solver");
431 if (m_havejac && IDASetJacFn (m_mem, IDA::jacdense) != 0)
432 error (
"Unable to set dense Jacobian function");
438 IDA::jacdense_impl (realtype t, realtype cj,
439 N_Vector& yy, N_Vector& yyp, SUNMatrix& JJ)
442 long int Neq = NV_LENGTH_S(yy);
451 jac = (*m_jacfun) (y, yp, t, cj, m_ida_jac);
453 jac = (*m_jacdcell) (m_dfdy, m_dfdyp, cj);
455 std::copy (jac.fortran_vec (),
456 jac.fortran_vec () + jac.numel (),
457 SUNDenseMatrix_Data (JJ));
460 # if defined (HAVE_SUNDIALS_SUNLINSOL_KLU)
462 IDA::jacsparse_impl (realtype t, realtype cj, N_Vector& yy, N_Vector& yyp,
473 jac = (*m_jacspfun) (y, yp, t, cj, m_ida_jac);
475 jac = (*m_jacspcell) (m_spdfdy, m_spdfdyp, cj);
477 SUNMatZero_Sparse (Jac);
478 sunindextype *colptrs = SUNSparseMatrix_IndexPointers (Jac);
479 sunindextype *rowvals = SUNSparseMatrix_IndexValues (Jac);
481 for (
int i = 0; i < m_num + 1; i++)
482 colptrs[i] = jac.cidx(i);
484 double *
d = SUNSparseMatrix_Data (Jac);
485 for (
int i = 0; i < jac.nnz (); i++)
487 rowvals[i] = jac.ridx(i);
494 IDA::NVecToCol (N_Vector& v,
long int n)
497 realtype *punt = nv_data_s (v);
508 N_Vector v = N_VNew_Serial (
n);
510 realtype *punt = nv_data_s (v);
519 IDA::set_userdata (
void)
521 void *userdata =
this;
523 if (IDASetUserData (m_mem, userdata) != 0)
524 error (
"User data not set");
530 m_num = m_y0.numel ();
531 m_mem = IDACreate ();
533 N_Vector yy = ColToNVec (m_y0, m_num);
535 N_Vector yyp = ColToNVec (m_yp0, m_num);
537 IDA::set_userdata ();
539 if (IDAInit (m_mem, IDA::resfun, m_t0, yy, yyp) != 0)
540 error (
"IDA not initialized");
544 IDA::set_tolerance (
ColumnVector& abstol, realtype reltol)
546 N_Vector abs_tol = ColToNVec (abstol, m_num);
548 if (IDASVtolerances (m_mem, reltol, abs_tol) != 0)
549 error (
"IDA: Tolerance not set");
551 N_VDestroy_Serial (abs_tol);
555 IDA::set_tolerance (realtype abstol, realtype reltol)
557 if (IDASStolerances (m_mem, reltol, abstol) != 0)
558 error (
"IDA: Tolerance not set");
562 IDA::integrate (
const int numt,
const ColumnVector& tspan,
564 const int refine,
bool haverefine,
bool haveoutputfcn,
573 int cont = 0, temp = 0;
575 std::string
string =
"";
578 realtype tsol = tspan(0);
579 realtype tend = tspan(numt-1);
581 N_Vector yyp = ColToNVec (yp, m_num);
583 N_Vector yy = ColToNVec (y, m_num);
587 status = IDA::outputfun (output_fcn, haveoutputsel, y,
588 tsol, tend, outputsel,
"init");
591 if (haveeventfunction)
592 status = IDA::event (event_fcn, te, ye, ie, tsol, y,
593 "init", yp, oldval, oldisterminal,
594 olddir, cont, temp, tsol, yold);
601 output.
resize (numt, m_num);
611 if (IDASolve (m_mem, tspan (j), &tsol, yy, yyp, IDA_NORMAL) != 0)
612 error (
"IDASolve failed");
614 yout = NVecToCol (yy, m_num);
615 ypout = NVecToCol (yyp, m_num);
619 output.
elem (j, i) = yout.elem (i);
622 status = IDA::outputfun (output_fcn, haveoutputsel, yout, tsol,
623 tend, outputsel,
string);
625 if (haveeventfunction)
626 status = IDA::event (event_fcn, te, ye, ie, tout(j), yout,
627 string, ypout, oldval, oldisterminal,
628 olddir, j, temp, tout(j-1), yold);
633 output.
resize (j + 1, m_num);
649 bool posdirection = (tend > tsol);
652 while (((posdirection == 1 && tsol < tend)
653 || (posdirection == 0 && tsol > tend))
656 if (IDASolve (m_mem, tend, &tsol, yy, yyp, IDA_ONE_STEP) != 0)
657 error (
"IDASolve failed");
660 status = IDA::interpolate (cont, output, tout, refine, tend,
661 haveoutputfcn, haveoutputsel,
662 output_fcn, outputsel,
663 haveeventfunction, event_fcn, te,
664 ye, ie, oldval, oldisterminal,
667 ypout = NVecToCol (yyp, m_num);
669 output.
resize (cont + 1, m_num);
672 yout = NVecToCol (yy, m_num);
675 output.
elem (cont, i) = yout.elem (i);
677 if (haveoutputfcn && ! haverefine && tout(cont) < tend)
678 status = IDA::outputfun (output_fcn, haveoutputsel, yout, tsol,
679 tend, outputsel,
string);
681 if (haveeventfunction && ! haverefine && tout(cont) < tend)
682 status = IDA::event (event_fcn, te, ye, ie, tout(cont), yout,
683 string, ypout, oldval, oldisterminal,
684 olddir, cont, temp, tout(cont-1), yold);
690 N_Vector dky = N_VNew_Serial (m_num);
692 if (IDAGetDky (m_mem, tend, 0, dky) != 0)
693 error (
"IDA failed to interpolate y");
696 yout = NVecToCol (dky, m_num);
699 output.
elem (cont, i) = yout.elem (i);
704 status = IDA::outputfun (output_fcn, haveoutputsel, yout,
705 tend, tend, outputsel,
string);
708 if (haveeventfunction)
709 status = IDA::event (event_fcn, te, ye, ie, tend, yout,
710 string, ypout, oldval, oldisterminal,
711 olddir, cont, temp, tout(cont-1),
715 N_VDestroy_Serial (dky);
719 status = IDA::outputfun (output_fcn, haveoutputsel, yout, tend, tend,
724 return ovl (tout, output, te, ye, ie);
730 realtype tsol,
const ColumnVector& y,
const std::string& flag,
745 oldval = output(0).vector_value ();
746 oldisterminal = output(1).vector_value ();
747 olddir = output(2).vector_value ();
760 if ((val(i) > 0 && oldval(i) < 0 && dir(i) != -1)
761 || (val(i) < 0 && oldval(i) > 0 && dir(i) != 1))
763 index.
resize (index.numel () + 1);
764 index (index.numel () - 1) = i;
768 if (cont == 1 && index.numel () > 0)
777 te(0) = tsol - val (index(0)) * (tsol - told)
778 / (val (index(0)) - oldval (index(0)));
781 = y - ((tsol - te(0)) * (y - yold) / (tsol - told));
784 ye.
elem (0, i) = ytemp.elem (i);
787 else if (index.numel () > 0)
790 te.
resize (temp + index.numel ());
791 ye.
resize (temp + index.numel (), m_num);
792 ie.
resize (temp + index.numel ());
797 if (isterminal (index(i)) == 1)
801 ie(temp+i) = index(i);
802 te(temp+i) = tsol - val(index(i)) * (tsol - told)
803 / (val(index(i)) - oldval(index(i)));
806 = y - (tsol - te (temp + i)) * (y - yold) / (tsol - told);
809 ye.
elem (temp + i, j) = ytemp.elem (j);
813 temp += index.numel ();
821 oldisterminal = isterminal;
829 int refine, realtype tend,
bool haveoutputfcn,
837 realtype h = 0, tcur = 0;
840 N_Vector dky = N_VNew_Serial (m_num);
842 N_Vector dkyp = N_VNew_Serial (m_num);
846 std::string
string =
"";
848 if (IDAGetLastStep (m_mem, &h) != 0)
849 error (
"IDA failed to return last step");
851 if (IDAGetCurrentTime (m_mem, &tcur) != 0)
852 error (
"IDA failed to return the current time");
854 realtype tin = tcur - h;
856 realtype step = h / refine;
859 i < refine && tin + step * i < tend && status == 0;
862 if (IDAGetDky (m_mem, tin + step*i, 0, dky) != 0)
863 error (
"IDA failed to interpolate y");
865 if (IDAGetDky (m_mem, tin + step*i, 1, dkyp) != 0)
866 error (
"IDA failed to interpolate yp");
869 output.
resize (cont + 1, m_num);
872 tout(cont) = tin + step * i;
873 yout = NVecToCol (dky, m_num);
874 ypout = NVecToCol (dkyp, m_num);
877 output.
elem (cont, j) = yout.elem (j);
880 status = IDA::outputfun (output_fcn, haveoutputsel, yout,
881 tout(cont), tend, outputsel,
"");
883 if (haveeventfunction)
884 status = IDA::event (event_fcn, te, ye, ie, tout(cont),
885 yout,
string, ypout, oldval,
886 oldisterminal, olddir, cont, temp,
890 N_VDestroy_Serial (dky);
896 IDA::outputfun (
const octave_value& output_fcn,
bool haveoutputsel,
899 const std::string& flag)
910 ysel(i) = yout(outputsel(i));
924 feval (output_fcn, output, 0);
930 status = val(0).bool_value ();
936 feval (output_fcn, output, 0);
943 IDA::set_maxstep (realtype maxstep)
945 if (IDASetMaxStep (m_mem, maxstep) != 0)
946 error (
"IDA: Max Step not set");
950 IDA::set_initialstep (realtype initialstep)
952 if (IDASetInitStep (m_mem, initialstep) != 0)
953 error (
"IDA: Initial Step not set");
957 IDA::set_maxorder (
int maxorder)
959 if (IDASetMaxOrd (m_mem, maxorder) != 0)
960 error (
"IDA: Max Order not set");
964 IDA::print_stat (
void)
966 long int nsteps = 0, netfails = 0, nrevals = 0;
968 if (IDAGetNumSteps (m_mem, &nsteps) != 0)
969 error (
"IDA failed to return the number of internal steps");
971 if (IDAGetNumErrTestFails (m_mem, &netfails) != 0)
972 error (
"IDA failed to return the number of internal errors");
974 if (IDAGetNumResEvals (m_mem, &nrevals) != 0)
975 error (
"IDA failed to return the number of residual evaluations");
993 tmp =
feval (ida_fc,
ovl (t,
x, xdot), 1);
1000 return tmp(0).vector_value ();
1011 tmp =
feval (ida_jc,
ovl (t,
x, xdot), 2);
1018 return tmp(0).matrix_value () + cj * tmp(1).matrix_value ();
1029 tmp =
feval (ida_jc,
ovl (t,
x, xdot), 2);
1036 return tmp(0).sparse_matrix_value () + cj * tmp(1).sparse_matrix_value ();
1040 ida_dense_cell_jac (
Matrix *dfdy,
Matrix *dfdyp,
double cj)
1042 return (*dfdy) + cj * (*dfdyp);
1049 return (*spdfdy) + cj * (*spdfdyp);
1064 IDA dae (t0, y0, yp0, ida_fcn, ida_user_function);
1073 Matrix ida_dfdy, ida_dfdyp;
1083 dae.set_jacobian (ida_jac, ida_sparse_jac);
1085 dae.set_jacobian (ida_jac, ida_dense_jac);
1093 ida_spdfdy = jaccell(0).sparse_matrix_value ();
1094 ida_spdfdyp = jaccell(1).sparse_matrix_value ();
1096 dae.set_jacobian (&ida_spdfdy, &ida_spdfdyp,
1097 ida_sparse_cell_jac);
1101 ida_dfdy = jaccell(0).matrix_value ();
1102 ida_dfdyp = jaccell(1).matrix_value ();
1104 dae.set_jacobian (&ida_dfdy, &ida_dfdyp, ida_dense_cell_jac);
1121 dae.set_tolerance (abs_tol, rel_tol);
1127 dae.set_tolerance (abs_tol, rel_tol);
1133 dae.set_maxstep (maxstep);
1140 dae.set_initialstep (initialstep);
1146 dae.set_maxorder (maxorder);
1151 bool haverefine = (refine > 1);
1157 bool haveoutputfunction
1160 if (haveoutputfunction)
1161 output_fcn = options.
getfield(
"OutputFcn");
1172 bool haveeventfunction
1175 if (haveeventfunction)
1176 event_fcn = options.
getfield(
"Events");
1182 retval = dae.integrate (numt, tspan, y0, yp0, refine,
1183 haverefine, haveoutputfunction,
1184 output_fcn, haveoutputsel, outputsel,
1185 haveeventfunction, event_fcn);
1206 #if defined (HAVE_SUNDIALS)
1209 int nargin = args.
length ();
1218 error (
"__ode15__: odefun must be a function handle");
1222 = args(1).xvector_value (
"__ode15__: TRANGE must be a vector of numbers");
1224 int numt = tspan.
numel ();
1226 realtype t0 = tspan (0);
1229 error (
"__ode15__: TRANGE must contain at least 2 elements");
1231 error (
"__ode15__: TRANGE must be strictly monotonic");
1235 = args(2).xvector_value (
"__ode15__: initial state y0 must be a vector");
1238 = args(3).xvector_value (
"__ode15__: initial state yp0 must be a vector");
1242 error (
"__ode15__: initial state y0 and yp0 must have the same length");
1243 else if (y0.
numel () < 1)
1244 error (
"__ode15__: initial state yp0 must be a vector or a scalar");
1247 if (! args(4).isstruct ())
1248 error (
"__ode15__: OPTS argument must be a structure");
1251 = args(4).xscalar_map_value (
"__ode15__: OPTS argument must be a scalar structure");
1254 return octave::do_ode15 (ida_fcn, tspan, numt, t0, y0, yp0, options);
1259 octave_unused_parameter (args);
sortmode issorted(sortmode mode=UNSORTED) const
Ordering is auto-detected or can be specified.
octave_idx_type numel(void) const
Number of elements in the array.
T & elem(octave_idx_type n)
Size of the specified dimension.
void resize(octave_idx_type n, const double &rfv=0)
void resize(octave_idx_type nr, octave_idx_type nc, double rfv=0)
octave_value getfield(const std::string &key) const
void resize(octave_idx_type n, const octave_value &rfv=octave_value())
octave_idx_type length(void) const
bool bool_value(bool warn=false) const
int int_value(bool req_int=false, bool frc_str_conv=false) const
Cell cell_value(void) const
bool is_function_handle(void) const
Array< double > vector_value(bool frc_str_conv=false, bool frc_vec_conv=false) const
double double_value(bool frc_str_conv=false) const
#define DEFUN_DLD(name, args_name, nargout_name, doc)
Macro to define an at run time dynamically loadable builtin function.
OCTINTERP_API void print_usage(void)
void error(const char *fmt,...)
void err_disabled_feature(const std::string &fcn, const std::string &feature, const std::string &pkg)
void err_user_supplied_eval(const char *name)
F77_RET_T const F77_INT F77_CMPLX * A
F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE * d
F77_RET_T const F77_DBLE * x
static void initialize(void)
octave_value_list feval(const char *name, const octave_value_list &args, int nargout)
Evaluate an Octave function (built-in or interpreted) and return the list of result values.
octave_value::octave_value(const Array< char > &chm, char type) return retval
octave_value_list ovl(const OV_Args &... args)
Construct an octave_value_list with less typing.