comparison libinterp/dldfcn/__ode15__.cc @ 31607:aac27ad79be6 stable

maint: Re-indent code after switch to using namespace macros. * build-env.h, build-env.in.cc, Cell.h, __betainc__.cc, __eigs__.cc, __ftp__.cc, __ichol__.cc, __ilu__.cc, __isprimelarge__.cc, __magick_read__.cc, __pchip_deriv__.cc, amd.cc, base-text-renderer.cc, base-text-renderer.h, besselj.cc, bitfcns.cc, bsxfun.cc, c-file-ptr-stream.h, call-stack.cc, call-stack.h, ccolamd.cc, cellfun.cc, chol.cc, colamd.cc, dasrt.cc, data.cc, debug.cc, defaults.cc, defaults.h, det.cc, display.cc, display.h, dlmread.cc, dynamic-ld.cc, dynamic-ld.h, ellipj.cc, environment.cc, environment.h, error.cc, error.h, errwarn.h, event-manager.cc, event-manager.h, event-queue.cc, event-queue.h, fcn-info.cc, fcn-info.h, fft.cc, fft2.cc, file-io.cc, filter.cc, find.cc, ft-text-renderer.cc, ft-text-renderer.h, gcd.cc, gl-render.cc, gl-render.h, gl2ps-print.cc, gl2ps-print.h, graphics-toolkit.cc, graphics-toolkit.h, graphics.cc, gsvd.cc, gtk-manager.cc, gtk-manager.h, help.cc, help.h, hook-fcn.cc, hook-fcn.h, input.cc, input.h, interpreter-private.cc, interpreter-private.h, interpreter.cc, interpreter.h, inv.cc, jsondecode.cc, jsonencode.cc, latex-text-renderer.cc, latex-text-renderer.h, load-path.cc, load-path.h, load-save.cc, load-save.h, lookup.cc, ls-hdf5.cc, ls-mat4.cc, ls-mat5.cc, lsode.cc, lu.cc, mappers.cc, matrix_type.cc, max.cc, mex.cc, mexproto.h, mxarray.h, mxtypes.in.h, oct-errno.in.cc, oct-hdf5-types.cc, oct-hist.cc, oct-hist.h, oct-map.cc, oct-map.h, oct-opengl.h, oct-prcstrm.h, oct-process.cc, oct-process.h, oct-stdstrm.h, oct-stream.cc, oct-stream.h, oct-strstrm.h, octave-default-image.h, ordqz.cc, ordschur.cc, pager.cc, pager.h, pinv.cc, pow2.cc, pr-output.cc, psi.cc, qr.cc, quadcc.cc, rand.cc, regexp.cc, settings.cc, settings.h, sighandlers.cc, sighandlers.h, sparse-xpow.cc, sqrtm.cc, stack-frame.cc, stack-frame.h, stream-euler.cc, strfns.cc, svd.cc, syminfo.cc, syminfo.h, symrcm.cc, symrec.cc, symrec.h, symscope.cc, symscope.h, symtab.cc, symtab.h, sysdep.cc, sysdep.h, text-engine.cc, text-engine.h, text-renderer.cc, text-renderer.h, time.cc, toplev.cc, typecast.cc, url-handle-manager.cc, url-handle-manager.h, urlwrite.cc, utils.cc, utils.h, variables.cc, variables.h, xdiv.cc, __delaunayn__.cc, __init_fltk__.cc, __init_gnuplot__.cc, __ode15__.cc, __voronoi__.cc, audioread.cc, convhulln.cc, gzip.cc, cdef-class.cc, cdef-class.h, cdef-fwd.h, cdef-manager.cc, cdef-manager.h, cdef-method.cc, cdef-method.h, cdef-object.cc, cdef-object.h, cdef-package.cc, cdef-package.h, cdef-property.cc, cdef-property.h, cdef-utils.cc, cdef-utils.h, ov-base-diag.cc, ov-base-int.cc, ov-base-mat.cc, ov-base-mat.h, ov-base-scalar.cc, ov-base.cc, ov-base.h, ov-bool-mat.cc, ov-bool-mat.h, ov-bool-sparse.cc, ov-bool.cc, ov-builtin.h, ov-cell.cc, ov-ch-mat.cc, ov-class.cc, ov-class.h, ov-classdef.cc, ov-classdef.h, ov-complex.cc, ov-cx-diag.cc, ov-cx-mat.cc, ov-cx-sparse.cc, ov-dld-fcn.cc, ov-dld-fcn.h, ov-fcn-handle.cc, ov-fcn-handle.h, ov-fcn.h, ov-float.cc, ov-flt-complex.cc, ov-flt-cx-diag.cc, ov-flt-cx-mat.cc, ov-flt-re-diag.cc, ov-flt-re-mat.cc, ov-flt-re-mat.h, ov-intx.h, ov-java.cc, ov-lazy-idx.cc, ov-legacy-range.cc, ov-magic-int.cc, ov-mex-fcn.cc, ov-mex-fcn.h, ov-null-mat.cc, ov-perm.cc, ov-range.cc, ov-re-diag.cc, ov-re-mat.cc, ov-re-mat.h, ov-re-sparse.cc, ov-scalar.cc, ov-str-mat.cc, ov-struct.cc, ov-typeinfo.cc, ov-typeinfo.h, ov-usr-fcn.cc, ov-usr-fcn.h, ov.cc, ov.h, ovl.h, octave.cc, octave.h, op-b-sbm.cc, op-bm-sbm.cc, op-cs-scm.cc, op-fm-fcm.cc, op-fs-fcm.cc, op-s-scm.cc, op-scm-cs.cc, op-scm-s.cc, op-sm-cs.cc, ops.h, anon-fcn-validator.cc, anon-fcn-validator.h, bp-table.cc, bp-table.h, comment-list.cc, comment-list.h, filepos.h, lex.h, oct-lvalue.cc, oct-lvalue.h, parse.h, profiler.cc, profiler.h, pt-anon-scopes.cc, pt-anon-scopes.h, pt-arg-list.cc, pt-arg-list.h, pt-args-block.cc, pt-args-block.h, pt-array-list.cc, pt-array-list.h, pt-assign.cc, pt-assign.h, pt-binop.cc, pt-binop.h, pt-bp.cc, pt-bp.h, pt-cbinop.cc, pt-cbinop.h, pt-cell.cc, pt-cell.h, pt-check.cc, pt-check.h, pt-classdef.cc, pt-classdef.h, pt-cmd.h, pt-colon.cc, pt-colon.h, pt-const.cc, pt-const.h, pt-decl.cc, pt-decl.h, pt-eval.cc, pt-eval.h, pt-except.cc, pt-except.h, pt-exp.cc, pt-exp.h, pt-fcn-handle.cc, pt-fcn-handle.h, pt-id.cc, pt-id.h, pt-idx.cc, pt-idx.h, pt-jump.h, pt-loop.cc, pt-loop.h, pt-mat.cc, pt-mat.h, pt-misc.cc, pt-misc.h, pt-pr-code.cc, pt-pr-code.h, pt-select.cc, pt-select.h, pt-spmd.cc, pt-spmd.h, pt-stmt.cc, pt-stmt.h, pt-tm-const.cc, pt-tm-const.h, pt-unop.cc, pt-unop.h, pt-walk.cc, pt-walk.h, pt.cc, pt.h, token.cc, token.h, Range.cc, Range.h, idx-vector.cc, idx-vector.h, range-fwd.h, CollocWt.cc, CollocWt.h, aepbalance.cc, aepbalance.h, chol.cc, chol.h, gepbalance.cc, gepbalance.h, gsvd.cc, gsvd.h, hess.cc, hess.h, lo-mappers.cc, lo-mappers.h, lo-specfun.cc, lo-specfun.h, lu.cc, lu.h, oct-convn.cc, oct-convn.h, oct-fftw.cc, oct-fftw.h, oct-norm.cc, oct-norm.h, oct-rand.cc, oct-rand.h, oct-spparms.cc, oct-spparms.h, qr.cc, qr.h, qrp.cc, qrp.h, randgamma.cc, randgamma.h, randmtzig.cc, randmtzig.h, randpoisson.cc, randpoisson.h, schur.cc, schur.h, sparse-chol.cc, sparse-chol.h, sparse-lu.cc, sparse-lu.h, sparse-qr.cc, sparse-qr.h, svd.cc, svd.h, child-list.cc, child-list.h, dir-ops.cc, dir-ops.h, file-ops.cc, file-ops.h, file-stat.cc, file-stat.h, lo-sysdep.cc, lo-sysdep.h, lo-sysinfo.cc, lo-sysinfo.h, mach-info.cc, mach-info.h, oct-env.cc, oct-env.h, oct-group.cc, oct-group.h, oct-password.cc, oct-password.h, oct-syscalls.cc, oct-syscalls.h, oct-time.cc, oct-time.h, oct-uname.cc, oct-uname.h, action-container.cc, action-container.h, base-list.h, cmd-edit.cc, cmd-edit.h, cmd-hist.cc, cmd-hist.h, f77-fcn.h, file-info.cc, file-info.h, lo-array-errwarn.cc, lo-array-errwarn.h, lo-hash.cc, lo-hash.h, lo-ieee.h, lo-regexp.cc, lo-regexp.h, lo-utils.cc, lo-utils.h, oct-base64.cc, oct-base64.h, oct-glob.cc, oct-glob.h, oct-inttypes.h, oct-mutex.cc, oct-mutex.h, oct-refcount.h, oct-shlib.cc, oct-shlib.h, oct-sparse.cc, oct-sparse.h, oct-string.h, octave-preserve-stream-state.h, pathsearch.cc, pathsearch.h, quit.cc, quit.h, unwind-prot.cc, unwind-prot.h, url-transfer.cc, url-transfer.h: Re-indent code after switch to using namespace macros.
author Rik <rik@octave.org>
date Thu, 01 Dec 2022 18:02:15 -0800
parents e88a07dec498
children 597f3ee61a48
comparison
equal deleted inserted replaced
31605:e88a07dec498 31607:aac27ad79be6
85 OCTAVE_BEGIN_NAMESPACE(octave) 85 OCTAVE_BEGIN_NAMESPACE(octave)
86 86
87 #if defined (HAVE_SUNDIALS) 87 #if defined (HAVE_SUNDIALS)
88 88
89 # if ! defined (HAVE_IDASETJACFN) && defined (HAVE_IDADLSSETJACFN) 89 # if ! defined (HAVE_IDASETJACFN) && defined (HAVE_IDADLSSETJACFN)
90 static inline int 90 static inline int
91 IDASetJacFn (void *ida_mem, IDADlsJacFn jac) 91 IDASetJacFn (void *ida_mem, IDADlsJacFn jac)
92 { 92 {
93 return IDADlsSetJacFn (ida_mem, jac); 93 return IDADlsSetJacFn (ida_mem, jac);
94 } 94 }
95 # endif 95 # endif
96 96
97 # if ! defined (HAVE_IDASETLINEARSOLVER) && defined (HAVE_IDADLSSETLINEARSOLVER) 97 # if ! defined (HAVE_IDASETLINEARSOLVER) && defined (HAVE_IDADLSSETLINEARSOLVER)
98 static inline int 98 static inline int
99 IDASetLinearSolver (void *ida_mem, SUNLinearSolver LS, SUNMatrix A) 99 IDASetLinearSolver (void *ida_mem, SUNLinearSolver LS, SUNMatrix A)
100 { 100 {
101 return IDADlsSetLinearSolver (ida_mem, LS, A); 101 return IDADlsSetLinearSolver (ida_mem, LS, A);
102 } 102 }
103 # endif 103 # endif
104 104
105 # if ! defined (HAVE_SUNLINSOL_DENSE) && defined (HAVE_SUNDENSELINEARSOLVER) 105 # if ! defined (HAVE_SUNLINSOL_DENSE) && defined (HAVE_SUNDENSELINEARSOLVER)
106 static inline SUNLinearSolver 106 static inline SUNLinearSolver
107 SUNLinSol_Dense (N_Vector y, SUNMatrix A) 107 SUNLinSol_Dense (N_Vector y, SUNMatrix A)
108 { 108 {
109 return SUNDenseLinearSolver (y, A); 109 return SUNDenseLinearSolver (y, A);
110 } 110 }
111 # endif 111 # endif
112 112
113 # if defined (HAVE_SUNDIALS_SUNLINSOL_KLU) 113 # if defined (HAVE_SUNDIALS_SUNLINSOL_KLU)
114 # if ! defined (HAVE_SUNLINSOL_KLU) && defined (HAVE_SUNKLU) 114 # if ! defined (HAVE_SUNLINSOL_KLU) && defined (HAVE_SUNKLU)
115 static inline SUNLinearSolver 115 static inline SUNLinearSolver
116 SUNLinSol_KLU (N_Vector y, SUNMatrix A) 116 SUNLinSol_KLU (N_Vector y, SUNMatrix A)
117 { 117 {
118 return SUNKLU (y, A); 118 return SUNKLU (y, A);
119 } 119 }
120 # endif 120 # endif
121 # endif 121 # endif
122 122
123 static inline realtype * 123 static inline realtype *
124 nv_data_s (N_Vector& v) 124 nv_data_s (N_Vector& v)
125 { 125 {
126 # if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC) 126 # if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
127 // Disable warning from GCC about old-style casts in Sundials 127 // Disable warning from GCC about old-style casts in Sundials
128 // macro expansions. Do this in a function so that this 128 // macro expansions. Do this in a function so that this
129 // diagnostic may still be enabled for the rest of the file. 129 // diagnostic may still be enabled for the rest of the file.
130 # pragma GCC diagnostic push 130 # pragma GCC diagnostic push
131 # pragma GCC diagnostic ignored "-Wold-style-cast" 131 # pragma GCC diagnostic ignored "-Wold-style-cast"
132 # endif 132 # endif
133 133
134 return NV_DATA_S (v); 134 return NV_DATA_S (v);
135 135
136 # if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC) 136 # if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
137 // Restore prevailing warning state for remainder of the file. 137 // Restore prevailing warning state for remainder of the file.
138 # pragma GCC diagnostic pop 138 # pragma GCC diagnostic pop
139 # endif 139 # endif
140 }
141
142 class IDA
143 {
144 public:
145
146 typedef
147 ColumnVector (*DAERHSFuncIDA) (const ColumnVector& x,
148 const ColumnVector& xdot,
149 realtype t, const octave_value& idaf);
150
151 typedef
152 Matrix (*DAEJacFuncDense) (const ColumnVector& x,
153 const ColumnVector& xdot, realtype t,
154 realtype cj, const octave_value& idaj);
155
156 typedef
157 SparseMatrix (*DAEJacFuncSparse) (const ColumnVector& x,
158 const ColumnVector& xdot,
159 realtype t, realtype cj,
160 const octave_value& idaj);
161
162 typedef
163 Matrix (*DAEJacCellDense) (Matrix *dfdy, Matrix *dfdyp,
164 realtype cj);
165
166 typedef
167 SparseMatrix (*DAEJacCellSparse) (SparseMatrix *dfdy,
168 SparseMatrix *dfdyp, realtype cj);
169
170 //Default
171 IDA (void)
172 : m_t0 (0.0), m_y0 (), m_yp0 (), m_havejac (false), m_havejacfcn (false),
173 m_havejacsparse (false), m_mem (nullptr), m_num (), m_ida_fcn (),
174 m_ida_jac (), m_dfdy (nullptr), m_dfdyp (nullptr), m_spdfdy (nullptr),
175 m_spdfdyp (nullptr), m_fcn (nullptr), m_jacfcn (nullptr),
176 m_jacspfcn (nullptr), m_jacdcell (nullptr), m_jacspcell (nullptr),
177 m_sunJacMatrix (nullptr), m_sunLinearSolver (nullptr)
178 { }
179
180
181 IDA (realtype t, ColumnVector y, ColumnVector yp,
182 const octave_value& ida_fcn, DAERHSFuncIDA daefun)
183 : m_t0 (t), m_y0 (y), m_yp0 (yp), m_havejac (false), m_havejacfcn (false),
184 m_havejacsparse (false), m_mem (nullptr), m_num (), m_ida_fcn (ida_fcn),
185 m_ida_jac (), m_dfdy (nullptr), m_dfdyp (nullptr), m_spdfdy (nullptr),
186 m_spdfdyp (nullptr), m_fcn (daefun), m_jacfcn (nullptr),
187 m_jacspfcn (nullptr), m_jacdcell (nullptr), m_jacspcell (nullptr),
188 m_sunJacMatrix (nullptr), m_sunLinearSolver (nullptr)
189 { }
190
191
192 ~IDA (void)
193 {
194 IDAFree (&m_mem);
195 SUNLinSolFree (m_sunLinearSolver);
196 SUNMatDestroy (m_sunJacMatrix);
197 # if defined (HAVE_SUNDIALS_SUNCONTEXT)
198 SUNContext_Free (&m_sunContext);
199 # endif
140 } 200 }
141 201
142 class IDA 202 IDA&
203 set_jacobian (const octave_value& jac, DAEJacFuncDense j)
143 { 204 {
144 public: 205 m_jacfcn = j;
145 206 m_ida_jac = jac;
146 typedef 207 m_havejac = true;
147 ColumnVector (*DAERHSFuncIDA) (const ColumnVector& x, 208 m_havejacfcn = true;
148 const ColumnVector& xdot, 209 m_havejacsparse = false;
149 realtype t, const octave_value& idaf); 210
150 211 return *this;
151 typedef 212 }
152 Matrix (*DAEJacFuncDense) (const ColumnVector& x, 213
153 const ColumnVector& xdot, realtype t, 214 IDA&
154 realtype cj, const octave_value& idaj); 215 set_jacobian (const octave_value& jac, DAEJacFuncSparse j)
155 216 {
156 typedef 217 m_jacspfcn = j;
157 SparseMatrix (*DAEJacFuncSparse) (const ColumnVector& x, 218 m_ida_jac = jac;
158 const ColumnVector& xdot, 219 m_havejac = true;
159 realtype t, realtype cj, 220 m_havejacfcn = true;
160 const octave_value& idaj); 221 m_havejacsparse = true;
161 222
162 typedef 223 return *this;
163 Matrix (*DAEJacCellDense) (Matrix *dfdy, Matrix *dfdyp, 224 }
164 realtype cj); 225
165 226 IDA&
166 typedef 227 set_jacobian (Matrix *dy, Matrix *dyp, DAEJacCellDense j)
167 SparseMatrix (*DAEJacCellSparse) (SparseMatrix *dfdy, 228 {
168 SparseMatrix *dfdyp, realtype cj); 229 m_jacdcell = j;
169 230 m_dfdy = dy;
170 //Default 231 m_dfdyp = dyp;
171 IDA (void) 232 m_havejac = true;
172 : m_t0 (0.0), m_y0 (), m_yp0 (), m_havejac (false), m_havejacfcn (false), 233 m_havejacfcn = false;
173 m_havejacsparse (false), m_mem (nullptr), m_num (), m_ida_fcn (), 234 m_havejacsparse = false;
174 m_ida_jac (), m_dfdy (nullptr), m_dfdyp (nullptr), m_spdfdy (nullptr), 235
175 m_spdfdyp (nullptr), m_fcn (nullptr), m_jacfcn (nullptr), 236 return *this;
176 m_jacspfcn (nullptr), m_jacdcell (nullptr), m_jacspcell (nullptr), 237 }
177 m_sunJacMatrix (nullptr), m_sunLinearSolver (nullptr) 238
178 { } 239 IDA&
179 240 set_jacobian (SparseMatrix *dy, SparseMatrix *dyp,
180 241 DAEJacCellSparse j)
181 IDA (realtype t, ColumnVector y, ColumnVector yp, 242 {
182 const octave_value& ida_fcn, DAERHSFuncIDA daefun) 243 m_jacspcell = j;
183 : m_t0 (t), m_y0 (y), m_yp0 (yp), m_havejac (false), m_havejacfcn (false), 244 m_spdfdy = dy;
184 m_havejacsparse (false), m_mem (nullptr), m_num (), m_ida_fcn (ida_fcn), 245 m_spdfdyp = dyp;
185 m_ida_jac (), m_dfdy (nullptr), m_dfdyp (nullptr), m_spdfdy (nullptr), 246 m_havejac = true;
186 m_spdfdyp (nullptr), m_fcn (daefun), m_jacfcn (nullptr), 247 m_havejacfcn = false;
187 m_jacspfcn (nullptr), m_jacdcell (nullptr), m_jacspcell (nullptr), 248 m_havejacsparse = true;
188 m_sunJacMatrix (nullptr), m_sunLinearSolver (nullptr) 249
189 { } 250 return *this;
190 251 }
191 252
192 ~IDA (void) 253 void set_userdata (void);
193 { 254
194 IDAFree (&m_mem); 255 void initialize (void);
195 SUNLinSolFree (m_sunLinearSolver); 256
196 SUNMatDestroy (m_sunJacMatrix); 257 static ColumnVector NVecToCol (N_Vector& v, octave_f77_int_type n);
258
197 # if defined (HAVE_SUNDIALS_SUNCONTEXT) 259 # if defined (HAVE_SUNDIALS_SUNCONTEXT)
198 SUNContext_Free (&m_sunContext); 260 N_Vector ColToNVec (const ColumnVector& data, octave_f77_int_type n);
199 # endif
200 }
201
202 IDA&
203 set_jacobian (const octave_value& jac, DAEJacFuncDense j)
204 {
205 m_jacfcn = j;
206 m_ida_jac = jac;
207 m_havejac = true;
208 m_havejacfcn = true;
209 m_havejacsparse = false;
210
211 return *this;
212 }
213
214 IDA&
215 set_jacobian (const octave_value& jac, DAEJacFuncSparse j)
216 {
217 m_jacspfcn = j;
218 m_ida_jac = jac;
219 m_havejac = true;
220 m_havejacfcn = true;
221 m_havejacsparse = true;
222
223 return *this;
224 }
225
226 IDA&
227 set_jacobian (Matrix *dy, Matrix *dyp, DAEJacCellDense j)
228 {
229 m_jacdcell = j;
230 m_dfdy = dy;
231 m_dfdyp = dyp;
232 m_havejac = true;
233 m_havejacfcn = false;
234 m_havejacsparse = false;
235
236 return *this;
237 }
238
239 IDA&
240 set_jacobian (SparseMatrix *dy, SparseMatrix *dyp,
241 DAEJacCellSparse j)
242 {
243 m_jacspcell = j;
244 m_spdfdy = dy;
245 m_spdfdyp = dyp;
246 m_havejac = true;
247 m_havejacfcn = false;
248 m_havejacsparse = true;
249
250 return *this;
251 }
252
253 void set_userdata (void);
254
255 void initialize (void);
256
257 static ColumnVector NVecToCol (N_Vector& v, octave_f77_int_type n);
258
259 # if defined (HAVE_SUNDIALS_SUNCONTEXT)
260 N_Vector ColToNVec (const ColumnVector& data, octave_f77_int_type n);
261 # else 261 # else
262 static N_Vector ColToNVec (const ColumnVector& data, octave_f77_int_type n); 262 static N_Vector ColToNVec (const ColumnVector& data, octave_f77_int_type n);
263 # endif 263 # endif
264 264
265 void 265 void
266 set_up (const ColumnVector& y); 266 set_up (const ColumnVector& y);
267 267
268 void 268 void
269 set_tolerance (ColumnVector& abstol, realtype reltol); 269 set_tolerance (ColumnVector& abstol, realtype reltol);
270 270
271 void 271 void
272 set_tolerance (realtype abstol, realtype reltol); 272 set_tolerance (realtype abstol, realtype reltol);
273 273
274 static int 274 static int
275 resfun (realtype t, N_Vector yy, N_Vector yyp, 275 resfun (realtype t, N_Vector yy, N_Vector yyp,
276 N_Vector rr, void *user_data); 276 N_Vector rr, void *user_data);
277 277
278 void 278 void
279 resfun_impl (realtype t, N_Vector& yy, 279 resfun_impl (realtype t, N_Vector& yy,
280 N_Vector& yyp, N_Vector& rr); 280 N_Vector& yyp, N_Vector& rr);
281 static int 281 static int
282 jacdense (realtype t, realtype cj, N_Vector yy, N_Vector yyp, 282 jacdense (realtype t, realtype cj, N_Vector yy, N_Vector yyp,
283 N_Vector, SUNMatrix JJ, void *user_data, N_Vector, 283 N_Vector, SUNMatrix JJ, void *user_data, N_Vector,
284 N_Vector, N_Vector) 284 N_Vector, N_Vector)
285 {
286 IDA *self = static_cast <IDA *> (user_data);
287 self->jacdense_impl (t, cj, yy, yyp, JJ);
288 return 0;
289 }
290
291 void
292 jacdense_impl (realtype t, realtype cj,
293 N_Vector& yy, N_Vector& yyp, SUNMatrix& JJ);
294
295 # if defined (HAVE_SUNDIALS_SUNLINSOL_KLU)
296 static int
297 jacsparse (realtype t, realtype cj, N_Vector yy, N_Vector yyp,
298 N_Vector, SUNMatrix Jac, void *user_data, N_Vector,
299 N_Vector, N_Vector)
300 {
301 IDA *self = static_cast <IDA *> (user_data);
302 self->jacsparse_impl (t, cj, yy, yyp, Jac);
303 return 0;
304 }
305
306 void
307 jacsparse_impl (realtype t, realtype cj,
308 N_Vector& yy, N_Vector& yyp, SUNMatrix& Jac);
309 # endif
310
311 void set_maxstep (realtype maxstep);
312
313 void set_initialstep (realtype initialstep);
314
315 bool
316 interpolate (octave_idx_type& cont, Matrix& output, ColumnVector& tout,
317 int refine, realtype tend, bool haveoutputfcn,
318 bool haveoutputsel, const octave_value& output_fcn,
319 ColumnVector& outputsel, bool haveeventfunction,
320 const octave_value& event_fcn, ColumnVector& te,
321 Matrix& ye, ColumnVector& ie, ColumnVector& oldval,
322 ColumnVector& oldisterminal, ColumnVector& olddir,
323 octave_idx_type& temp, ColumnVector& yold,
324 const octave_idx_type num_event_args);
325
326 bool
327 outputfun (const octave_value& output_fcn, bool haveoutputsel,
328 const ColumnVector& output, realtype tout, realtype tend,
329 ColumnVector& outputsel, const std::string& flag);
330
331
332 bool
333 event (const octave_value& event_fcn,
334 ColumnVector& te, Matrix& ye, ColumnVector& ie,
335 realtype tsol, const ColumnVector& y, const std::string& flag,
336 const ColumnVector& yp, ColumnVector& oldval,
337 ColumnVector& oldisterminal, ColumnVector& olddir,
338 octave_idx_type cont, octave_idx_type& temp, realtype told,
339 ColumnVector& yold,
340 const octave_idx_type num_event_args);
341
342 void set_maxorder (int maxorder);
343
344 octave_value_list
345 integrate (const octave_idx_type numt, const ColumnVector& tt,
346 const ColumnVector& y0, const ColumnVector& yp0,
347 const int refine, bool haverefine, bool haveoutputfcn,
348 const octave_value& output_fcn, bool haveoutputsel,
349 ColumnVector& outputsel, bool haveeventfunction,
350 const octave_value& event_fcn,
351 const octave_idx_type num_event_args);
352
353 void print_stat (void);
354
355 private:
356
357 realtype m_t0;
358 ColumnVector m_y0;
359 ColumnVector m_yp0;
360 bool m_havejac;
361 bool m_havejacfcn;
362 bool m_havejacsparse;
363 void *m_mem;
364 octave_f77_int_type m_num;
365 octave_value m_ida_fcn;
366 octave_value m_ida_jac;
367 Matrix *m_dfdy;
368 Matrix *m_dfdyp;
369 SparseMatrix *m_spdfdy;
370 SparseMatrix *m_spdfdyp;
371 DAERHSFuncIDA m_fcn;
372 DAEJacFuncDense m_jacfcn;
373 DAEJacFuncSparse m_jacspfcn;
374 DAEJacCellDense m_jacdcell;
375 DAEJacCellSparse m_jacspcell;
376 # if defined (HAVE_SUNDIALS_SUNCONTEXT)
377 SUNContext m_sunContext;
378 # endif
379 SUNMatrix m_sunJacMatrix;
380 SUNLinearSolver m_sunLinearSolver;
381 };
382
383 int
384 IDA::resfun (realtype t, N_Vector yy, N_Vector yyp, N_Vector rr,
385 void *user_data)
386 { 285 {
387 IDA *self = static_cast <IDA *> (user_data); 286 IDA *self = static_cast <IDA *> (user_data);
388 self->resfun_impl (t, yy, yyp, rr); 287 self->jacdense_impl (t, cj, yy, yyp, JJ);
389 return 0; 288 return 0;
390 } 289 }
391 290
392 void 291 void
393 IDA::resfun_impl (realtype t, N_Vector& yy, 292 jacdense_impl (realtype t, realtype cj,
394 N_Vector& yyp, N_Vector& rr) 293 N_Vector& yy, N_Vector& yyp, SUNMatrix& JJ);
294
295 # if defined (HAVE_SUNDIALS_SUNLINSOL_KLU)
296 static int
297 jacsparse (realtype t, realtype cj, N_Vector yy, N_Vector yyp,
298 N_Vector, SUNMatrix Jac, void *user_data, N_Vector,
299 N_Vector, N_Vector)
395 { 300 {
396 ColumnVector y = IDA::NVecToCol (yy, m_num); 301 IDA *self = static_cast <IDA *> (user_data);
397 302 self->jacsparse_impl (t, cj, yy, yyp, Jac);
398 ColumnVector yp = IDA::NVecToCol (yyp, m_num); 303 return 0;
399
400 ColumnVector res = (*m_fcn) (y, yp, t, m_ida_fcn);
401
402 realtype *puntrr = nv_data_s (rr);
403
404 for (octave_idx_type i = 0; i < m_num; i++)
405 puntrr[i] = res(i);
406 } 304 }
305
306 void
307 jacsparse_impl (realtype t, realtype cj,
308 N_Vector& yy, N_Vector& yyp, SUNMatrix& Jac);
309 # endif
310
311 void set_maxstep (realtype maxstep);
312
313 void set_initialstep (realtype initialstep);
314
315 bool
316 interpolate (octave_idx_type& cont, Matrix& output, ColumnVector& tout,
317 int refine, realtype tend, bool haveoutputfcn,
318 bool haveoutputsel, const octave_value& output_fcn,
319 ColumnVector& outputsel, bool haveeventfunction,
320 const octave_value& event_fcn, ColumnVector& te,
321 Matrix& ye, ColumnVector& ie, ColumnVector& oldval,
322 ColumnVector& oldisterminal, ColumnVector& olddir,
323 octave_idx_type& temp, ColumnVector& yold,
324 const octave_idx_type num_event_args);
325
326 bool
327 outputfun (const octave_value& output_fcn, bool haveoutputsel,
328 const ColumnVector& output, realtype tout, realtype tend,
329 ColumnVector& outputsel, const std::string& flag);
330
331
332 bool
333 event (const octave_value& event_fcn,
334 ColumnVector& te, Matrix& ye, ColumnVector& ie,
335 realtype tsol, const ColumnVector& y, const std::string& flag,
336 const ColumnVector& yp, ColumnVector& oldval,
337 ColumnVector& oldisterminal, ColumnVector& olddir,
338 octave_idx_type cont, octave_idx_type& temp, realtype told,
339 ColumnVector& yold,
340 const octave_idx_type num_event_args);
341
342 void set_maxorder (int maxorder);
343
344 octave_value_list
345 integrate (const octave_idx_type numt, const ColumnVector& tt,
346 const ColumnVector& y0, const ColumnVector& yp0,
347 const int refine, bool haverefine, bool haveoutputfcn,
348 const octave_value& output_fcn, bool haveoutputsel,
349 ColumnVector& outputsel, bool haveeventfunction,
350 const octave_value& event_fcn,
351 const octave_idx_type num_event_args);
352
353 void print_stat (void);
354
355 private:
356
357 realtype m_t0;
358 ColumnVector m_y0;
359 ColumnVector m_yp0;
360 bool m_havejac;
361 bool m_havejacfcn;
362 bool m_havejacsparse;
363 void *m_mem;
364 octave_f77_int_type m_num;
365 octave_value m_ida_fcn;
366 octave_value m_ida_jac;
367 Matrix *m_dfdy;
368 Matrix *m_dfdyp;
369 SparseMatrix *m_spdfdy;
370 SparseMatrix *m_spdfdyp;
371 DAERHSFuncIDA m_fcn;
372 DAEJacFuncDense m_jacfcn;
373 DAEJacFuncSparse m_jacspfcn;
374 DAEJacCellDense m_jacdcell;
375 DAEJacCellSparse m_jacspcell;
376 # if defined (HAVE_SUNDIALS_SUNCONTEXT)
377 SUNContext m_sunContext;
378 # endif
379 SUNMatrix m_sunJacMatrix;
380 SUNLinearSolver m_sunLinearSolver;
381 };
382
383 int
384 IDA::resfun (realtype t, N_Vector yy, N_Vector yyp, N_Vector rr,
385 void *user_data)
386 {
387 IDA *self = static_cast <IDA *> (user_data);
388 self->resfun_impl (t, yy, yyp, rr);
389 return 0;
390 }
391
392 void
393 IDA::resfun_impl (realtype t, N_Vector& yy,
394 N_Vector& yyp, N_Vector& rr)
395 {
396 ColumnVector y = IDA::NVecToCol (yy, m_num);
397
398 ColumnVector yp = IDA::NVecToCol (yyp, m_num);
399
400 ColumnVector res = (*m_fcn) (y, yp, t, m_ida_fcn);
401
402 realtype *puntrr = nv_data_s (rr);
403
404 for (octave_idx_type i = 0; i < m_num; i++)
405 puntrr[i] = res(i);
406 }
407 407
408 # if defined (HAVE_SUNDIALS_SUNCONTEXT) 408 # if defined (HAVE_SUNDIALS_SUNCONTEXT)
409 # define OCTAVE_SUNCONTEXT , m_sunContext 409 # define OCTAVE_SUNCONTEXT , m_sunContext
410 # else 410 # else
411 # define OCTAVE_SUNCONTEXT 411 # define OCTAVE_SUNCONTEXT
412 # endif 412 # endif
413 413
414 void 414 void
415 IDA::set_up (const ColumnVector& y) 415 IDA::set_up (const ColumnVector& y)
416 { 416 {
417 N_Vector yy = ColToNVec (y, m_num); 417 N_Vector yy = ColToNVec (y, m_num);
418 418
419 if (m_havejacsparse) 419 if (m_havejacsparse)
420 { 420 {
421 # if defined (HAVE_SUNDIALS_SUNLINSOL_KLU) 421 # if defined (HAVE_SUNDIALS_SUNLINSOL_KLU)
422 # if defined (HAVE_SUNSPARSEMATRIX_REALLOCATE) 422 # if defined (HAVE_SUNSPARSEMATRIX_REALLOCATE)
423 // Initially allocate memory for 0 entries. We will reallocate when we 423 // Initially allocate memory for 0 entries. We will reallocate when we
424 // get the Jacobian matrix from the user and know the actual number of 424 // get the Jacobian matrix from the user and know the actual number of
425 // entries. 425 // entries.
426 m_sunJacMatrix = SUNSparseMatrix (m_num, m_num, 0, CSC_MAT 426 m_sunJacMatrix = SUNSparseMatrix (m_num, m_num, 0, CSC_MAT
427 OCTAVE_SUNCONTEXT); 427 OCTAVE_SUNCONTEXT);
428 # else 428 # else
429 octave_f77_int_type max_elems; 429 octave_f77_int_type max_elems;
430 if (math::int_multiply_overflow (m_num, m_num, &max_elems)) 430 if (math::int_multiply_overflow (m_num, m_num, &max_elems))
431 error ("Unable to allocate memory for sparse Jacobian"); 431 error ("Unable to allocate memory for sparse Jacobian");
432 432
433 m_sunJacMatrix = SUNSparseMatrix (m_num, m_num, max_elems, CSC_MAT 433 m_sunJacMatrix = SUNSparseMatrix (m_num, m_num, max_elems, CSC_MAT
434 OCTAVE_SUNCONTEXT); 434 OCTAVE_SUNCONTEXT);
435 # endif 435 # endif
436 if (! m_sunJacMatrix) 436 if (! m_sunJacMatrix)
437 error ("Unable to create sparse Jacobian for Sundials"); 437 error ("Unable to create sparse Jacobian for Sundials");
438 438
439 m_sunLinearSolver = SUNLinSol_KLU (yy, m_sunJacMatrix 439 m_sunLinearSolver = SUNLinSol_KLU (yy, m_sunJacMatrix
440 OCTAVE_SUNCONTEXT);
441 if (! m_sunLinearSolver)
442 error ("Unable to create KLU sparse solver");
443
444 if (IDASetLinearSolver (m_mem, m_sunLinearSolver, m_sunJacMatrix))
445 error ("Unable to set sparse linear solver");
446
447 IDASetJacFn (m_mem, IDA::jacsparse);
448
449 # else
450 error ("SUNDIALS SUNLINSOL KLU was unavailable or disabled when "
451 "Octave was built");
452
453 # endif
454
455 }
456 else
457 {
458
459 m_sunJacMatrix = SUNDenseMatrix (m_num, m_num OCTAVE_SUNCONTEXT);
460 if (! m_sunJacMatrix)
461 error ("Unable to create dense Jacobian for Sundials");
462
463 m_sunLinearSolver = SUNLinSol_Dense (yy, m_sunJacMatrix
440 OCTAVE_SUNCONTEXT); 464 OCTAVE_SUNCONTEXT);
441 if (! m_sunLinearSolver) 465 if (! m_sunLinearSolver)
442 error ("Unable to create KLU sparse solver"); 466 error ("Unable to create dense linear solver");
443 467
444 if (IDASetLinearSolver (m_mem, m_sunLinearSolver, m_sunJacMatrix)) 468 if (IDASetLinearSolver (m_mem, m_sunLinearSolver, m_sunJacMatrix))
445 error ("Unable to set sparse linear solver"); 469 error ("Unable to set dense linear solver");
446 470
447 IDASetJacFn (m_mem, IDA::jacsparse); 471 if (m_havejac && IDASetJacFn (m_mem, IDA::jacdense) != 0)
448 472 error ("Unable to set dense Jacobian function");
473
474 }
475 }
476
477 void
478 IDA::jacdense_impl (realtype t, realtype cj,
479 N_Vector& yy, N_Vector& yyp, SUNMatrix& JJ)
480
481 {
482 octave_f77_int_type Neq = NV_LENGTH_S (yy);
483
484 ColumnVector y = NVecToCol (yy, Neq);
485
486 ColumnVector yp = NVecToCol (yyp, Neq);
487
488 Matrix jac;
489
490 if (m_havejacfcn)
491 jac = (*m_jacfcn) (y, yp, t, cj, m_ida_jac);
492 else
493 jac = (*m_jacdcell) (m_dfdy, m_dfdyp, cj);
494
495 octave_f77_int_type num_jac = to_f77_int (jac.numel ());
496 std::copy (jac.fortran_vec (),
497 jac.fortran_vec () + num_jac,
498 SUNDenseMatrix_Data (JJ));
499 }
500
501 # if defined (HAVE_SUNDIALS_SUNLINSOL_KLU)
502 void
503 IDA::jacsparse_impl (realtype t, realtype cj, N_Vector& yy, N_Vector& yyp,
504 SUNMatrix& Jac)
505
506 {
507 ColumnVector y = NVecToCol (yy, m_num);
508
509 ColumnVector yp = NVecToCol (yyp, m_num);
510
511 SparseMatrix jac;
512
513 if (m_havejacfcn)
514 jac = (*m_jacspfcn) (y, yp, t, cj, m_ida_jac);
515 else
516 jac = (*m_jacspcell) (m_spdfdy, m_spdfdyp, cj);
517
518 # if defined (HAVE_SUNSPARSEMATRIX_REALLOCATE)
519 octave_f77_int_type nnz = to_f77_int (jac.nnz ());
520 if (nnz > SUNSparseMatrix_NNZ (Jac))
521 {
522 // Allocate memory for sparse Jacobian defined in user function.
523 // This will always be required at least once since we set the number
524 // of non-zero elements to zero initially.
525 if (SUNSparseMatrix_Reallocate (Jac, nnz))
526 error ("Unable to allocate sufficient memory for IDA sparse matrix");
527 }
528 # endif
529
530 SUNMatZero_Sparse (Jac);
531 // We have to use "sunindextype *" here but still need to check that
532 // conversion of each element to "octave_f77_int_type" is save.
533 sunindextype *colptrs = SUNSparseMatrix_IndexPointers (Jac);
534 sunindextype *rowvals = SUNSparseMatrix_IndexValues (Jac);
535
536 for (octave_f77_int_type i = 0; i < m_num + 1; i++)
537 colptrs[i] = to_f77_int (jac.cidx (i));
538
539 double *d = SUNSparseMatrix_Data (Jac);
540 for (octave_f77_int_type i = 0; i < to_f77_int (jac.nnz ()); i++)
541 {
542 rowvals[i] = to_f77_int (jac.ridx (i));
543 d[i] = jac.data (i);
544 }
545 }
546 # endif
547
548 ColumnVector
549 IDA::NVecToCol (N_Vector& v, octave_f77_int_type n)
550 {
551 ColumnVector data (n);
552 realtype *punt = nv_data_s (v);
553
554 for (octave_f77_int_type i = 0; i < n; i++)
555 data(i) = punt[i];
556
557 return data;
558 }
559
560 N_Vector
561 IDA::ColToNVec (const ColumnVector& data, octave_f77_int_type n)
562 {
563 N_Vector v = N_VNew_Serial (n OCTAVE_SUNCONTEXT);
564
565 realtype *punt = nv_data_s (v);
566
567 for (octave_f77_int_type i = 0; i < n; i++)
568 punt[i] = data(i);
569
570 return v;
571 }
572
573 void
574 IDA::set_userdata (void)
575 {
576 void *userdata = this;
577
578 if (IDASetUserData (m_mem, userdata) != 0)
579 error ("User data not set");
580 }
581
582 void
583 IDA::initialize (void)
584 {
585 m_num = to_f77_int (m_y0.numel ());
586 # if defined (HAVE_SUNDIALS_SUNCONTEXT)
587 if (SUNContext_Create (nullptr, &m_sunContext) < 0)
588 error ("__ode15__: unable to create context for SUNDIALS");
589 m_mem = IDACreate (m_sunContext);
449 # else 590 # else
450 error ("SUNDIALS SUNLINSOL KLU was unavailable or disabled when " 591 m_mem = IDACreate ();
451 "Octave was built"); 592 # endif
452 593
453 # endif 594 N_Vector yy = ColToNVec (m_y0, m_num);
454 595
455 } 596 N_Vector yyp = ColToNVec (m_yp0, m_num);
456 else 597
457 { 598 IDA::set_userdata ();
458 599
459 m_sunJacMatrix = SUNDenseMatrix (m_num, m_num OCTAVE_SUNCONTEXT); 600 if (IDAInit (m_mem, IDA::resfun, m_t0, yy, yyp) != 0)
460 if (! m_sunJacMatrix) 601 error ("IDA not initialized");
461 error ("Unable to create dense Jacobian for Sundials"); 602 }
462 603
463 m_sunLinearSolver = SUNLinSol_Dense (yy, m_sunJacMatrix 604 void
464 OCTAVE_SUNCONTEXT); 605 IDA::set_tolerance (ColumnVector& abstol, realtype reltol)
465 if (! m_sunLinearSolver) 606 {
466 error ("Unable to create dense linear solver"); 607 N_Vector abs_tol = ColToNVec (abstol, m_num);
467 608
468 if (IDASetLinearSolver (m_mem, m_sunLinearSolver, m_sunJacMatrix)) 609 if (IDASVtolerances (m_mem, reltol, abs_tol) != 0)
469 error ("Unable to set dense linear solver"); 610 error ("IDA: Tolerance not set");
470 611
471 if (m_havejac && IDASetJacFn (m_mem, IDA::jacdense) != 0) 612 N_VDestroy_Serial (abs_tol);
472 error ("Unable to set dense Jacobian function"); 613 }
473 614
474 } 615 void
475 } 616 IDA::set_tolerance (realtype abstol, realtype reltol)
476 617 {
477 void 618 if (IDASStolerances (m_mem, reltol, abstol) != 0)
478 IDA::jacdense_impl (realtype t, realtype cj, 619 error ("IDA: Tolerance not set");
479 N_Vector& yy, N_Vector& yyp, SUNMatrix& JJ) 620 }
480 621
481 { 622 octave_value_list
482 octave_f77_int_type Neq = NV_LENGTH_S (yy); 623 IDA::integrate (const octave_idx_type numt, const ColumnVector& tspan,
483 624 const ColumnVector& y, const ColumnVector& yp,
484 ColumnVector y = NVecToCol (yy, Neq); 625 const int refine, bool haverefine, bool haveoutputfcn,
485 626 const octave_value& output_fcn, bool haveoutputsel,
486 ColumnVector yp = NVecToCol (yyp, Neq); 627 ColumnVector& outputsel, bool haveeventfunction,
487 628 const octave_value& event_fcn,
488 Matrix jac; 629 const octave_idx_type num_event_args)
489 630 {
490 if (m_havejacfcn) 631 // Set up output
491 jac = (*m_jacfcn) (y, yp, t, cj, m_ida_jac); 632 ColumnVector tout, yout (m_num), ypout (m_num), ysel (outputsel.numel ());
492 else 633 ColumnVector ie, te, oldval, oldisterminal, olddir;
493 jac = (*m_jacdcell) (m_dfdy, m_dfdyp, cj); 634 Matrix output, ye;
494 635 octave_idx_type cont = 0, temp = 0;
495 octave_f77_int_type num_jac = to_f77_int (jac.numel ()); 636 bool status = false;
496 std::copy (jac.fortran_vec (), 637 std::string string = "";
497 jac.fortran_vec () + num_jac, 638 ColumnVector yold = y;
498 SUNDenseMatrix_Data (JJ)); 639
499 } 640 realtype tsol = tspan(0);
500 641 realtype tend = tspan(numt-1);
501 # if defined (HAVE_SUNDIALS_SUNLINSOL_KLU) 642
502 void 643 N_Vector yyp = ColToNVec (yp, m_num);
503 IDA::jacsparse_impl (realtype t, realtype cj, N_Vector& yy, N_Vector& yyp, 644
504 SUNMatrix& Jac) 645 N_Vector yy = ColToNVec (y, m_num);
505 646
506 { 647 // Initialize OutputFcn
507 ColumnVector y = NVecToCol (yy, m_num); 648 if (haveoutputfcn)
508 649 status = IDA::outputfun (output_fcn, haveoutputsel, y,
509 ColumnVector yp = NVecToCol (yyp, m_num); 650 tsol, tend, outputsel, "init");
510 651
511 SparseMatrix jac; 652 // Initialize Events
512 653 if (haveeventfunction)
513 if (m_havejacfcn) 654 status = IDA::event (event_fcn, te, ye, ie, tsol, y,
514 jac = (*m_jacspfcn) (y, yp, t, cj, m_ida_jac); 655 "init", yp, oldval, oldisterminal,
515 else 656 olddir, cont, temp, tsol, yold, num_event_args);
516 jac = (*m_jacspcell) (m_spdfdy, m_spdfdyp, cj); 657
517 658 if (numt > 2)
518 # if defined (HAVE_SUNSPARSEMATRIX_REALLOCATE) 659 {
519 octave_f77_int_type nnz = to_f77_int (jac.nnz ()); 660 // First output value
520 if (nnz > SUNSparseMatrix_NNZ (Jac)) 661 tout.resize (numt);
521 { 662 tout(0) = tsol;
522 // Allocate memory for sparse Jacobian defined in user function. 663 output.resize (numt, m_num);
523 // This will always be required at least once since we set the number 664
524 // of non-zero elements to zero initially. 665 for (octave_idx_type i = 0; i < m_num; i++)
525 if (SUNSparseMatrix_Reallocate (Jac, nnz)) 666 output.elem (0, i) = y.elem (i);
526 error ("Unable to allocate sufficient memory for IDA sparse matrix"); 667
527 } 668 //Main loop
528 # endif 669 for (octave_idx_type j = 1; j < numt && status == 0; j++)
529 670 {
530 SUNMatZero_Sparse (Jac); 671 // IDANORMAL already interpolates tspan(j)
531 // We have to use "sunindextype *" here but still need to check that 672
532 // conversion of each element to "octave_f77_int_type" is save. 673 if (IDASolve (m_mem, tspan (j), &tsol, yy, yyp, IDA_NORMAL) != 0)
533 sunindextype *colptrs = SUNSparseMatrix_IndexPointers (Jac); 674 error ("IDASolve failed");
534 sunindextype *rowvals = SUNSparseMatrix_IndexValues (Jac); 675
535 676 yout = NVecToCol (yy, m_num);
536 for (octave_f77_int_type i = 0; i < m_num + 1; i++) 677 ypout = NVecToCol (yyp, m_num);
537 colptrs[i] = to_f77_int (jac.cidx (i)); 678 tout(j) = tsol;
538 679
539 double *d = SUNSparseMatrix_Data (Jac); 680 for (octave_idx_type i = 0; i < m_num; i++)
540 for (octave_f77_int_type i = 0; i < to_f77_int (jac.nnz ()); i++) 681 output.elem (j, i) = yout.elem (i);
541 { 682
542 rowvals[i] = to_f77_int (jac.ridx (i)); 683 if (haveoutputfcn)
543 d[i] = jac.data (i); 684 status = IDA::outputfun (output_fcn, haveoutputsel, yout, tsol,
544 } 685 tend, outputsel, string);
545 } 686
546 # endif 687 if (haveeventfunction)
547 688 status = IDA::event (event_fcn, te, ye, ie, tout(j), yout,
548 ColumnVector 689 string, ypout, oldval, oldisterminal,
549 IDA::NVecToCol (N_Vector& v, octave_f77_int_type n) 690 olddir, j, temp, tout(j-1), yold,
550 { 691 num_event_args);
551 ColumnVector data (n); 692
552 realtype *punt = nv_data_s (v); 693 // If integration is stopped, return only the reached steps
553 694 if (status == 1)
554 for (octave_f77_int_type i = 0; i < n; i++) 695 {
555 data(i) = punt[i]; 696 output.resize (j + 1, m_num);
556 697 tout.resize (j + 1);
557 return data; 698 }
558 } 699
559 700 }
560 N_Vector 701 }
561 IDA::ColToNVec (const ColumnVector& data, octave_f77_int_type n) 702 else // numel (tspan) == 2
562 { 703 {
563 N_Vector v = N_VNew_Serial (n OCTAVE_SUNCONTEXT); 704 // First output value
564 705 tout.resize (1);
565 realtype *punt = nv_data_s (v); 706 tout(0) = tsol;
566 707 output.resize (1, m_num);
567 for (octave_f77_int_type i = 0; i < n; i++) 708
568 punt[i] = data(i); 709 for (octave_idx_type i = 0; i < m_num; i++)
569 710 output.elem (0, i) = y.elem (i);
570 return v; 711
571 } 712 bool posdirection = (tend > tsol);
572 713
573 void 714 //main loop
574 IDA::set_userdata (void) 715 while (((posdirection == 1 && tsol < tend)
575 { 716 || (posdirection == 0 && tsol > tend))
576 void *userdata = this; 717 && status == 0)
577 718 {
578 if (IDASetUserData (m_mem, userdata) != 0) 719 if (IDASolve (m_mem, tend, &tsol, yy, yyp, IDA_ONE_STEP) != 0)
579 error ("User data not set"); 720 error ("IDASolve failed");
580 } 721
581 722 if (haverefine)
582 void 723 status = IDA::interpolate (cont, output, tout, refine, tend,
583 IDA::initialize (void) 724 haveoutputfcn, haveoutputsel,
584 { 725 output_fcn, outputsel,
585 m_num = to_f77_int (m_y0.numel ()); 726 haveeventfunction, event_fcn, te,
586 # if defined (HAVE_SUNDIALS_SUNCONTEXT) 727 ye, ie, oldval, oldisterminal,
587 if (SUNContext_Create (nullptr, &m_sunContext) < 0) 728 olddir, temp, yold,
588 error ("__ode15__: unable to create context for SUNDIALS"); 729 num_event_args);
589 m_mem = IDACreate (m_sunContext); 730
590 # else 731 ypout = NVecToCol (yyp, m_num);
591 m_mem = IDACreate (); 732 cont += 1;
592 # endif 733 output.resize (cont + 1, m_num); // This may be not efficient
593 734 tout.resize (cont + 1);
594 N_Vector yy = ColToNVec (m_y0, m_num); 735 tout(cont) = tsol;
595 736 yout = NVecToCol (yy, m_num);
596 N_Vector yyp = ColToNVec (m_yp0, m_num); 737
597 738 for (octave_idx_type i = 0; i < m_num; i++)
598 IDA::set_userdata (); 739 output.elem (cont, i) = yout.elem (i);
599 740
600 if (IDAInit (m_mem, IDA::resfun, m_t0, yy, yyp) != 0) 741 if (haveoutputfcn && ! haverefine && tout(cont) < tend)
601 error ("IDA not initialized"); 742 status = IDA::outputfun (output_fcn, haveoutputsel, yout, tsol,
602 } 743 tend, outputsel, string);
603 744
604 void 745 if (haveeventfunction && ! haverefine && tout(cont) < tend)
605 IDA::set_tolerance (ColumnVector& abstol, realtype reltol) 746 status = IDA::event (event_fcn, te, ye, ie, tout(cont), yout,
606 { 747 string, ypout, oldval, oldisterminal,
607 N_Vector abs_tol = ColToNVec (abstol, m_num); 748 olddir, cont, temp, tout(cont-1), yold,
608 749 num_event_args);
609 if (IDASVtolerances (m_mem, reltol, abs_tol) != 0) 750 }
610 error ("IDA: Tolerance not set"); 751
611 752 if (status == 0)
612 N_VDestroy_Serial (abs_tol); 753 {
613 } 754 // Interpolate in tend
614 755 N_Vector dky = N_VNew_Serial (m_num OCTAVE_SUNCONTEXT);
615 void 756
616 IDA::set_tolerance (realtype abstol, realtype reltol) 757 if (IDAGetDky (m_mem, tend, 0, dky) != 0)
617 { 758 error ("IDA failed to interpolate y");
618 if (IDASStolerances (m_mem, reltol, abstol) != 0) 759
619 error ("IDA: Tolerance not set"); 760 tout(cont) = tend;
620 } 761 yout = NVecToCol (dky, m_num);
621 762
622 octave_value_list 763 for (octave_idx_type i = 0; i < m_num; i++)
623 IDA::integrate (const octave_idx_type numt, const ColumnVector& tspan, 764 output.elem (cont, i) = yout.elem (i);
624 const ColumnVector& y, const ColumnVector& yp, 765
625 const int refine, bool haverefine, bool haveoutputfcn, 766 // Plot final value
626 const octave_value& output_fcn, bool haveoutputsel, 767 if (haveoutputfcn)
768 {
769 status = IDA::outputfun (output_fcn, haveoutputsel, yout,
770 tend, tend, outputsel, string);
771
772 // Events during last step
773 if (haveeventfunction)
774 status = IDA::event (event_fcn, te, ye, ie, tend, yout,
775 string, ypout, oldval, oldisterminal,
776 olddir, cont, temp, tout(cont-1),
777 yold, num_event_args);
778 }
779
780 N_VDestroy_Serial (dky);
781 }
782
783 // Cleanup plotter
784 status = IDA::outputfun (output_fcn, haveoutputsel, yout, tend, tend,
785 outputsel, "done");
786
787 }
788
789 // Index of Events (ie) variable must use 1-based indexing
790 return ovl (tout, output, te, ye, ie + 1.0);
791 }
792
793 bool
794 IDA::event (const octave_value& event_fcn,
795 ColumnVector& te, Matrix& ye, ColumnVector& ie, realtype tsol,
796 const ColumnVector& y, const std::string& flag,
797 const ColumnVector& yp, ColumnVector& oldval,
798 ColumnVector& oldisterminal, ColumnVector& olddir,
799 octave_idx_type cont, octave_idx_type& temp, realtype told,
800 ColumnVector& yold,
801 const octave_idx_type num_event_args)
802 {
803 bool status = false;
804
805 octave_value_list args;
806 if (num_event_args == 2)
807 args = ovl (tsol, y);
808 else
809 args = ovl (tsol, y, yp);
810
811 // cont is the number of steps reached by the solver
812 // temp is the number of events registered
813
814 if (flag == "init")
815 {
816 octave_value_list output = feval (event_fcn, args, 3);
817 oldval = output(0).vector_value ();
818 oldisterminal = output(1).vector_value ();
819 olddir = output(2).vector_value ();
820 }
821 else if (flag == "")
822 {
823 ColumnVector index (0);
824 octave_value_list output = feval (event_fcn, args, 3);
825 ColumnVector val = output(0).vector_value ();
826 ColumnVector isterminal = output(1).vector_value ();
827 ColumnVector dir = output(2).vector_value ();
828
829 // Get the index of the changed values
830 for (octave_idx_type i = 0; i < val.numel (); i++)
831 {
832 // Check for sign change and whether a rising / falling edge
833 // either passes through zero or detaches from zero (bug #59063)
834 if ((dir(i) != -1
835 && ((val(i) >= 0 && oldval(i) < 0)
836 || (val(i) > 0 && oldval(i) <= 0))) // increasing
837 || (dir(i) != 1
838 && ((val(i) <= 0 && oldval(i) > 0)
839 || (val(i) < 0 && oldval(i) >= 0)))) // decreasing
840 {
841 index.resize (index.numel () + 1);
842 index (index.numel () - 1) = i;
843 }
844 }
845
846 if (cont == 1 && index.numel () > 0) // Events in first step
847 {
848 temp = 1; // register only the first event
849 te.resize (1);
850 ye.resize (1, m_num);
851 ie.resize (1);
852
853 // Linear interpolation
854 ie(0) = index(0);
855 te(0) = tsol - val (index(0)) * (tsol - told)
856 / (val (index(0)) - oldval (index(0)));
857
858 ColumnVector ytemp
859 = y - ((tsol - te(0)) * (y - yold) / (tsol - told));
860
861 for (octave_idx_type i = 0; i < m_num; i++)
862 ye.elem (0, i) = ytemp.elem (i);
863
864 }
865 else if (index.numel () > 0)
866 // Not first step: register all events and test
867 // if stop integration or not
868 {
869 te.resize (temp + index.numel ());
870 ye.resize (temp + index.numel (), m_num);
871 ie.resize (temp + index.numel ());
872
873 for (octave_idx_type i = 0; i < index.numel (); i++)
874 {
875
876 if (isterminal (index(i)) == 1)
877 status = 1; // Stop integration
878
879 // Linear interpolation
880 ie(temp+i) = index(i);
881 te(temp+i) = tsol - val(index(i)) * (tsol - told)
882 / (val(index(i)) - oldval(index(i)));
883
884 ColumnVector ytemp
885 = y - (tsol - te (temp + i)) * (y - yold) / (tsol - told);
886
887 for (octave_idx_type j = 0; j < m_num; j++)
888 ye.elem (temp + i, j) = ytemp.elem (j);
889
890 }
891
892 temp += index.numel ();
893 }
894
895 // Update variables
896 yold = y;
897 told = tsol;
898 olddir = dir;
899 oldval = val;
900 oldisterminal = isterminal;
901 }
902
903 return status;
904 }
905
906 bool
907 IDA::interpolate (octave_idx_type& cont, Matrix& output, ColumnVector& tout,
908 int refine, realtype tend, bool haveoutputfcn,
909 bool haveoutputsel, const octave_value& output_fcn,
627 ColumnVector& outputsel, bool haveeventfunction, 910 ColumnVector& outputsel, bool haveeventfunction,
628 const octave_value& event_fcn, 911 const octave_value& event_fcn, ColumnVector& te,
912 Matrix& ye, ColumnVector& ie, ColumnVector& oldval,
913 ColumnVector& oldisterminal, ColumnVector& olddir,
914 octave_idx_type& temp, ColumnVector& yold,
629 const octave_idx_type num_event_args) 915 const octave_idx_type num_event_args)
630 { 916 {
631 // Set up output 917 realtype h = 0, tcur = 0;
632 ColumnVector tout, yout (m_num), ypout (m_num), ysel (outputsel.numel ()); 918 bool status = false;
633 ColumnVector ie, te, oldval, oldisterminal, olddir; 919
634 Matrix output, ye; 920 N_Vector dky = N_VNew_Serial (m_num OCTAVE_SUNCONTEXT);
635 octave_idx_type cont = 0, temp = 0; 921
636 bool status = false; 922 N_Vector dkyp = N_VNew_Serial (m_num OCTAVE_SUNCONTEXT);
637 std::string string = ""; 923
638 ColumnVector yold = y; 924 ColumnVector yout (m_num);
639 925 ColumnVector ypout (m_num);
640 realtype tsol = tspan(0); 926 std::string string = "";
641 realtype tend = tspan(numt-1); 927
642 928 if (IDAGetLastStep (m_mem, &h) != 0)
643 N_Vector yyp = ColToNVec (yp, m_num); 929 error ("IDA failed to return last step");
644 930
645 N_Vector yy = ColToNVec (y, m_num); 931 if (IDAGetCurrentTime (m_mem, &tcur) != 0)
646 932 error ("IDA failed to return the current time");
647 // Initialize OutputFcn 933
648 if (haveoutputfcn) 934 realtype tin = tcur - h;
649 status = IDA::outputfun (output_fcn, haveoutputsel, y, 935
650 tsol, tend, outputsel, "init"); 936 realtype step = h / refine;
651 937
652 // Initialize Events 938 for (octave_idx_type i = 1;
653 if (haveeventfunction) 939 i < refine && tin + step * i < tend && status == 0;
654 status = IDA::event (event_fcn, te, ye, ie, tsol, y, 940 i++)
655 "init", yp, oldval, oldisterminal, 941 {
656 olddir, cont, temp, tsol, yold, num_event_args); 942 if (IDAGetDky (m_mem, tin + step*i, 0, dky) != 0)
657 943 error ("IDA failed to interpolate y");
658 if (numt > 2) 944
659 { 945 if (IDAGetDky (m_mem, tin + step*i, 1, dkyp) != 0)
660 // First output value 946 error ("IDA failed to interpolate yp");
661 tout.resize (numt); 947
662 tout(0) = tsol; 948 cont += 1;
663 output.resize (numt, m_num); 949 output.resize (cont + 1, m_num);
664 950 tout.resize (cont + 1);
665 for (octave_idx_type i = 0; i < m_num; i++) 951
666 output.elem (0, i) = y.elem (i); 952 tout(cont) = tin + step * i;
667 953 yout = NVecToCol (dky, m_num);
668 //Main loop 954 ypout = NVecToCol (dkyp, m_num);
669 for (octave_idx_type j = 1; j < numt && status == 0; j++) 955
670 { 956 for (octave_idx_type j = 0; j < m_num; j++)
671 // IDANORMAL already interpolates tspan(j) 957 output.elem (cont, j) = yout.elem (j);
672 958
673 if (IDASolve (m_mem, tspan (j), &tsol, yy, yyp, IDA_NORMAL) != 0) 959 if (haveoutputfcn)
674 error ("IDASolve failed"); 960 status = IDA::outputfun (output_fcn, haveoutputsel, yout,
675 961 tout(cont), tend, outputsel, "");
676 yout = NVecToCol (yy, m_num); 962
677 ypout = NVecToCol (yyp, m_num); 963 if (haveeventfunction)
678 tout(j) = tsol; 964 status = IDA::event (event_fcn, te, ye, ie, tout(cont),
679 965 yout, string, ypout, oldval,
680 for (octave_idx_type i = 0; i < m_num; i++) 966 oldisterminal, olddir, cont, temp,
681 output.elem (j, i) = yout.elem (i); 967 tout(cont-1), yold, num_event_args);
682 968 }
683 if (haveoutputfcn) 969
684 status = IDA::outputfun (output_fcn, haveoutputsel, yout, tsol, 970 N_VDestroy_Serial (dky);
685 tend, outputsel, string); 971
686 972 return status;
687 if (haveeventfunction) 973 }
688 status = IDA::event (event_fcn, te, ye, ie, tout(j), yout, 974
689 string, ypout, oldval, oldisterminal, 975 bool
690 olddir, j, temp, tout(j-1), yold, 976 IDA::outputfun (const octave_value& output_fcn, bool haveoutputsel,
691 num_event_args); 977 const ColumnVector& yout, realtype tsol,
692 978 realtype tend, ColumnVector& outputsel,
693 // If integration is stopped, return only the reached steps 979 const std::string& flag)
694 if (status == 1) 980 {
695 { 981 bool status = false;
696 output.resize (j + 1, m_num); 982
697 tout.resize (j + 1); 983 octave_value_list output;
698 } 984 output(2) = flag;
699 985
700 } 986 ColumnVector ysel (outputsel.numel ());
701 } 987 if (haveoutputsel)
702 else // numel (tspan) == 2 988 {
703 { 989 for (octave_idx_type i = 0; i < outputsel.numel (); i++)
704 // First output value 990 ysel(i) = yout(outputsel(i));
705 tout.resize (1); 991
706 tout(0) = tsol; 992 output(1) = ysel;
707 output.resize (1, m_num); 993 }
708 994 else
709 for (octave_idx_type i = 0; i < m_num; i++) 995 output(1) = yout;
710 output.elem (0, i) = y.elem (i); 996
711 997 if (flag == "init")
712 bool posdirection = (tend > tsol); 998 {
713 999 ColumnVector toutput (2);
714 //main loop 1000 toutput(0) = tsol;
715 while (((posdirection == 1 && tsol < tend) 1001 toutput(1) = tend;
716 || (posdirection == 0 && tsol > tend)) 1002 output(0) = toutput;
717 && status == 0) 1003
718 { 1004 feval (output_fcn, output, 0);
719 if (IDASolve (m_mem, tend, &tsol, yy, yyp, IDA_ONE_STEP) != 0) 1005 }
720 error ("IDASolve failed"); 1006 else if (flag == "")
721 1007 {
722 if (haverefine) 1008 output(0) = tsol;
723 status = IDA::interpolate (cont, output, tout, refine, tend, 1009 octave_value_list val = feval (output_fcn, output, 1);
724 haveoutputfcn, haveoutputsel, 1010 status = val(0).bool_value ();
725 output_fcn, outputsel, 1011 }
726 haveeventfunction, event_fcn, te, 1012 else
727 ye, ie, oldval, oldisterminal, 1013 {
728 olddir, temp, yold, 1014 // Cleanup plotter
729 num_event_args); 1015 output(0) = tend;
730 1016 feval (output_fcn, output, 0);
731 ypout = NVecToCol (yyp, m_num); 1017 }
732 cont += 1; 1018
733 output.resize (cont + 1, m_num); // This may be not efficient 1019 return status;
734 tout.resize (cont + 1); 1020 }
735 tout(cont) = tsol; 1021
736 yout = NVecToCol (yy, m_num); 1022 void
737 1023 IDA::set_maxstep (realtype maxstep)
738 for (octave_idx_type i = 0; i < m_num; i++) 1024 {
739 output.elem (cont, i) = yout.elem (i); 1025 if (IDASetMaxStep (m_mem, maxstep) != 0)
740 1026 error ("IDA: Max Step not set");
741 if (haveoutputfcn && ! haverefine && tout(cont) < tend) 1027 }
742 status = IDA::outputfun (output_fcn, haveoutputsel, yout, tsol, 1028
743 tend, outputsel, string); 1029 void
744 1030 IDA::set_initialstep (realtype initialstep)
745 if (haveeventfunction && ! haverefine && tout(cont) < tend) 1031 {
746 status = IDA::event (event_fcn, te, ye, ie, tout(cont), yout, 1032 if (IDASetInitStep (m_mem, initialstep) != 0)
747 string, ypout, oldval, oldisterminal, 1033 error ("IDA: Initial Step not set");
748 olddir, cont, temp, tout(cont-1), yold, 1034 }
749 num_event_args); 1035
750 } 1036 void
751 1037 IDA::set_maxorder (int maxorder)
752 if (status == 0) 1038 {
753 { 1039 if (IDASetMaxOrd (m_mem, maxorder) != 0)
754 // Interpolate in tend 1040 error ("IDA: Max Order not set");
755 N_Vector dky = N_VNew_Serial (m_num OCTAVE_SUNCONTEXT); 1041 }
756 1042
757 if (IDAGetDky (m_mem, tend, 0, dky) != 0) 1043 void
758 error ("IDA failed to interpolate y"); 1044 IDA::print_stat (void)
759 1045 {
760 tout(cont) = tend; 1046 long int nsteps = 0, netfails = 0, nrevals = 0;
761 yout = NVecToCol (dky, m_num); 1047
762 1048 if (IDAGetNumSteps (m_mem, &nsteps) != 0)
763 for (octave_idx_type i = 0; i < m_num; i++) 1049 error ("IDA failed to return the number of internal steps");
764 output.elem (cont, i) = yout.elem (i); 1050
765 1051 if (IDAGetNumErrTestFails (m_mem, &netfails) != 0)
766 // Plot final value 1052 error ("IDA failed to return the number of internal errors");
767 if (haveoutputfcn) 1053
768 { 1054 if (IDAGetNumResEvals (m_mem, &nrevals) != 0)
769 status = IDA::outputfun (output_fcn, haveoutputsel, yout, 1055 error ("IDA failed to return the number of residual evaluations");
770 tend, tend, outputsel, string); 1056
771 1057 octave_stdout << nsteps << " successful steps\n";
772 // Events during last step 1058 octave_stdout << netfails << " failed attempts\n";
773 if (haveeventfunction) 1059 octave_stdout << nrevals << " function evaluations\n";
774 status = IDA::event (event_fcn, te, ye, ie, tend, yout, 1060 // octave_stdout << " partial derivatives\n";
775 string, ypout, oldval, oldisterminal, 1061 // octave_stdout << " LU decompositions\n";
776 olddir, cont, temp, tout(cont-1), 1062 // octave_stdout << " solutions of linear systems\n";
777 yold, num_event_args); 1063 }
778 } 1064
779 1065 static ColumnVector
780 N_VDestroy_Serial (dky); 1066 ida_user_function (const ColumnVector& x, const ColumnVector& xdot,
781 } 1067 double t, const octave_value& ida_fc)
782 1068 {
783 // Cleanup plotter 1069 octave_value_list tmp;
784 status = IDA::outputfun (output_fcn, haveoutputsel, yout, tend, tend, 1070
785 outputsel, "done"); 1071 try
786 1072 {
787 } 1073 tmp = feval (ida_fc, ovl (t, x, xdot), 1);
788 1074 }
789 // Index of Events (ie) variable must use 1-based indexing 1075 catch (execution_exception& ee)
790 return ovl (tout, output, te, ye, ie + 1.0); 1076 {
791 } 1077 err_user_supplied_eval (ee, "__ode15__");
792 1078 }
793 bool 1079
794 IDA::event (const octave_value& event_fcn, 1080 return tmp(0).vector_value ();
795 ColumnVector& te, Matrix& ye, ColumnVector& ie, realtype tsol, 1081 }
796 const ColumnVector& y, const std::string& flag, 1082
797 const ColumnVector& yp, ColumnVector& oldval, 1083 static Matrix
798 ColumnVector& oldisterminal, ColumnVector& olddir, 1084 ida_dense_jac (const ColumnVector& x, const ColumnVector& xdot,
799 octave_idx_type cont, octave_idx_type& temp, realtype told, 1085 double t, double cj, const octave_value& ida_jc)
800 ColumnVector& yold, 1086 {
801 const octave_idx_type num_event_args) 1087 octave_value_list tmp;
802 { 1088
803 bool status = false; 1089 try
804 1090 {
805 octave_value_list args; 1091 tmp = feval (ida_jc, ovl (t, x, xdot), 2);
806 if (num_event_args == 2) 1092 }
807 args = ovl (tsol, y); 1093 catch (execution_exception& ee)
808 else 1094 {
809 args = ovl (tsol, y, yp); 1095 err_user_supplied_eval (ee, "__ode15__");
810 1096 }
811 // cont is the number of steps reached by the solver 1097
812 // temp is the number of events registered 1098 return tmp(0).matrix_value () + cj * tmp(1).matrix_value ();
813 1099 }
814 if (flag == "init") 1100
815 { 1101 static SparseMatrix
816 octave_value_list output = feval (event_fcn, args, 3); 1102 ida_sparse_jac (const ColumnVector& x, const ColumnVector& xdot,
817 oldval = output(0).vector_value (); 1103 double t, double cj, const octave_value& ida_jc)
818 oldisterminal = output(1).vector_value (); 1104 {
819 olddir = output(2).vector_value (); 1105 octave_value_list tmp;
820 } 1106
821 else if (flag == "") 1107 try
822 { 1108 {
823 ColumnVector index (0); 1109 tmp = feval (ida_jc, ovl (t, x, xdot), 2);
824 octave_value_list output = feval (event_fcn, args, 3); 1110 }
825 ColumnVector val = output(0).vector_value (); 1111 catch (execution_exception& ee)
826 ColumnVector isterminal = output(1).vector_value (); 1112 {
827 ColumnVector dir = output(2).vector_value (); 1113 err_user_supplied_eval (ee, "__ode15__");
828 1114 }
829 // Get the index of the changed values 1115
830 for (octave_idx_type i = 0; i < val.numel (); i++) 1116 return tmp(0).sparse_matrix_value () + cj * tmp(1).sparse_matrix_value ();
831 { 1117 }
832 // Check for sign change and whether a rising / falling edge 1118
833 // either passes through zero or detaches from zero (bug #59063) 1119 static Matrix
834 if ((dir(i) != -1 1120 ida_dense_cell_jac (Matrix *dfdy, Matrix *dfdyp, double cj)
835 && ((val(i) >= 0 && oldval(i) < 0) 1121 {
836 || (val(i) > 0 && oldval(i) <= 0))) // increasing 1122 return (*dfdy) + cj * (*dfdyp);
837 || (dir(i) != 1 1123 }
838 && ((val(i) <= 0 && oldval(i) > 0) 1124
839 || (val(i) < 0 && oldval(i) >= 0)))) // decreasing 1125 static SparseMatrix
840 { 1126 ida_sparse_cell_jac (SparseMatrix *spdfdy, SparseMatrix *spdfdyp,
841 index.resize (index.numel () + 1); 1127 double cj)
842 index (index.numel () - 1) = i; 1128 {
843 } 1129 return (*spdfdy) + cj * (*spdfdyp);
844 } 1130 }
845 1131
846 if (cont == 1 && index.numel () > 0) // Events in first step 1132 static octave_value_list
847 { 1133 do_ode15 (const octave_value& ida_fcn,
848 temp = 1; // register only the first event 1134 const ColumnVector& tspan,
849 te.resize (1); 1135 const octave_idx_type numt,
850 ye.resize (1, m_num); 1136 const realtype t0,
851 ie.resize (1); 1137 const ColumnVector& y0,
852 1138 const ColumnVector& yp0,
853 // Linear interpolation 1139 const octave_scalar_map& options,
854 ie(0) = index(0); 1140 const octave_idx_type num_event_args)
855 te(0) = tsol - val (index(0)) * (tsol - told) 1141 {
856 / (val (index(0)) - oldval (index(0))); 1142 octave_value_list retval;
857 1143
858 ColumnVector ytemp 1144 // Create object
859 = y - ((tsol - te(0)) * (y - yold) / (tsol - told)); 1145 IDA dae (t0, y0, yp0, ida_fcn, ida_user_function);
860 1146
861 for (octave_idx_type i = 0; i < m_num; i++) 1147 // Set Jacobian
862 ye.elem (0, i) = ytemp.elem (i); 1148 bool havejac = options.getfield ("havejac").bool_value ();
863 1149
864 } 1150 bool havejacsparse = options.getfield ("havejacsparse").bool_value ();
865 else if (index.numel () > 0) 1151
866 // Not first step: register all events and test 1152 bool havejacfcn = options.getfield ("havejacfcn").bool_value ();
867 // if stop integration or not 1153
868 { 1154 Matrix ida_dfdy, ida_dfdyp;
869 te.resize (temp + index.numel ()); 1155 SparseMatrix ida_spdfdy, ida_spdfdyp;
870 ye.resize (temp + index.numel (), m_num); 1156
871 ie.resize (temp + index.numel ()); 1157 if (havejac)
872 1158 {
873 for (octave_idx_type i = 0; i < index.numel (); i++) 1159 if (havejacfcn)
874 { 1160 {
875 1161 octave_value ida_jac = options.getfield ("Jacobian");
876 if (isterminal (index(i)) == 1) 1162
877 status = 1; // Stop integration 1163 if (havejacsparse)
878 1164 dae.set_jacobian (ida_jac, ida_sparse_jac);
879 // Linear interpolation 1165 else
880 ie(temp+i) = index(i); 1166 dae.set_jacobian (ida_jac, ida_dense_jac);
881 te(temp+i) = tsol - val(index(i)) * (tsol - told) 1167 }
882 / (val(index(i)) - oldval(index(i))); 1168 else
883 1169 {
884 ColumnVector ytemp 1170 Cell jaccell = options.getfield ("Jacobian").cell_value ();
885 = y - (tsol - te (temp + i)) * (y - yold) / (tsol - told); 1171
886 1172 if (havejacsparse)
887 for (octave_idx_type j = 0; j < m_num; j++) 1173 {
888 ye.elem (temp + i, j) = ytemp.elem (j); 1174 ida_spdfdy = jaccell(0).sparse_matrix_value ();
889 1175 ida_spdfdyp = jaccell(1).sparse_matrix_value ();
890 } 1176
891 1177 dae.set_jacobian (&ida_spdfdy, &ida_spdfdyp,
892 temp += index.numel (); 1178 ida_sparse_cell_jac);
893 } 1179 }
894 1180 else
895 // Update variables 1181 {
896 yold = y; 1182 ida_dfdy = jaccell(0).matrix_value ();
897 told = tsol; 1183 ida_dfdyp = jaccell(1).matrix_value ();
898 olddir = dir; 1184
899 oldval = val; 1185 dae.set_jacobian (&ida_dfdy, &ida_dfdyp, ida_dense_cell_jac);
900 oldisterminal = isterminal; 1186 }
901 } 1187 }
902 1188 }
903 return status; 1189
904 } 1190 // Initialize IDA
905 1191 dae.initialize ();
906 bool 1192
907 IDA::interpolate (octave_idx_type& cont, Matrix& output, ColumnVector& tout, 1193 // Set tolerances
908 int refine, realtype tend, bool haveoutputfcn, 1194 realtype rel_tol = options.getfield ("RelTol").double_value ();
909 bool haveoutputsel, const octave_value& output_fcn, 1195
910 ColumnVector& outputsel, bool haveeventfunction, 1196 bool haveabstolvec = options.getfield ("haveabstolvec").bool_value ();
911 const octave_value& event_fcn, ColumnVector& te, 1197
912 Matrix& ye, ColumnVector& ie, ColumnVector& oldval, 1198 if (haveabstolvec)
913 ColumnVector& oldisterminal, ColumnVector& olddir, 1199 {
914 octave_idx_type& temp, ColumnVector& yold, 1200 ColumnVector abs_tol = options.getfield ("AbsTol").vector_value ();
915 const octave_idx_type num_event_args) 1201
916 { 1202 dae.set_tolerance (abs_tol, rel_tol);
917 realtype h = 0, tcur = 0; 1203 }
918 bool status = false; 1204 else
919 1205 {
920 N_Vector dky = N_VNew_Serial (m_num OCTAVE_SUNCONTEXT); 1206 realtype abs_tol = options.getfield ("AbsTol").double_value ();
921 1207
922 N_Vector dkyp = N_VNew_Serial (m_num OCTAVE_SUNCONTEXT); 1208 dae.set_tolerance (abs_tol, rel_tol);
923 1209 }
924 ColumnVector yout (m_num); 1210
925 ColumnVector ypout (m_num); 1211 //Set max step
926 std::string string = ""; 1212 realtype maxstep = options.getfield ("MaxStep").double_value ();
927 1213
928 if (IDAGetLastStep (m_mem, &h) != 0) 1214 dae.set_maxstep (maxstep);
929 error ("IDA failed to return last step"); 1215
930 1216 //Set initial step
931 if (IDAGetCurrentTime (m_mem, &tcur) != 0) 1217 if (! options.getfield ("InitialStep").isempty ())
932 error ("IDA failed to return the current time"); 1218 {
933 1219 realtype initialstep = options.getfield ("InitialStep").double_value ();
934 realtype tin = tcur - h; 1220
935 1221 dae.set_initialstep (initialstep);
936 realtype step = h / refine; 1222 }
937 1223
938 for (octave_idx_type i = 1; 1224 //Set max order FIXME: it doesn't work
939 i < refine && tin + step * i < tend && status == 0; 1225 int maxorder = options.getfield ("MaxOrder").int_value ();
940 i++) 1226
941 { 1227 dae.set_maxorder (maxorder);
942 if (IDAGetDky (m_mem, tin + step*i, 0, dky) != 0) 1228
943 error ("IDA failed to interpolate y"); 1229 //Set Refine
944 1230 const int refine = options.getfield ("Refine").int_value ();
945 if (IDAGetDky (m_mem, tin + step*i, 1, dkyp) != 0) 1231
946 error ("IDA failed to interpolate yp"); 1232 bool haverefine = (refine > 1);
947 1233
948 cont += 1; 1234 octave_value output_fcn;
949 output.resize (cont + 1, m_num); 1235 ColumnVector outputsel;
950 tout.resize (cont + 1); 1236
951 1237 // OutputFcn
952 tout(cont) = tin + step * i; 1238 bool haveoutputfunction
953 yout = NVecToCol (dky, m_num); 1239 = options.getfield ("haveoutputfunction").bool_value ();
954 ypout = NVecToCol (dkyp, m_num); 1240
955 1241 if (haveoutputfunction)
956 for (octave_idx_type j = 0; j < m_num; j++) 1242 output_fcn = options.getfield ("OutputFcn");
957 output.elem (cont, j) = yout.elem (j); 1243
958 1244 // OutputSel
959 if (haveoutputfcn) 1245 bool haveoutputsel = options.getfield ("haveoutputselection").bool_value ();
960 status = IDA::outputfun (output_fcn, haveoutputsel, yout, 1246
961 tout(cont), tend, outputsel, ""); 1247 if (haveoutputsel)
962 1248 outputsel = options.getfield ("OutputSel").vector_value ();
963 if (haveeventfunction) 1249
964 status = IDA::event (event_fcn, te, ye, ie, tout(cont), 1250 octave_value event_fcn;
965 yout, string, ypout, oldval, 1251
966 oldisterminal, olddir, cont, temp, 1252 // Events
967 tout(cont-1), yold, num_event_args); 1253 bool haveeventfunction
968 } 1254 = options.getfield ("haveeventfunction").bool_value ();
969 1255
970 N_VDestroy_Serial (dky); 1256 if (haveeventfunction)
971 1257 event_fcn = options.getfield ("Events");
972 return status; 1258
973 } 1259 // Set up linear solver
974 1260 dae.set_up (y0);
975 bool 1261
976 IDA::outputfun (const octave_value& output_fcn, bool haveoutputsel, 1262 // Integrate
977 const ColumnVector& yout, realtype tsol, 1263 retval = dae.integrate (numt, tspan, y0, yp0, refine,
978 realtype tend, ColumnVector& outputsel, 1264 haverefine, haveoutputfunction,
979 const std::string& flag) 1265 output_fcn, haveoutputsel, outputsel,
980 { 1266 haveeventfunction, event_fcn, num_event_args);
981 bool status = false; 1267
982 1268 // Statistics
983 octave_value_list output; 1269 bool havestats = options.getfield ("havestats").bool_value ();
984 output(2) = flag; 1270
985 1271 if (havestats)
986 ColumnVector ysel (outputsel.numel ()); 1272 dae.print_stat ();
987 if (haveoutputsel) 1273
988 { 1274 return retval;
989 for (octave_idx_type i = 0; i < outputsel.numel (); i++) 1275 }
990 ysel(i) = yout(outputsel(i));
991
992 output(1) = ysel;
993 }
994 else
995 output(1) = yout;
996
997 if (flag == "init")
998 {
999 ColumnVector toutput (2);
1000 toutput(0) = tsol;
1001 toutput(1) = tend;
1002 output(0) = toutput;
1003
1004 feval (output_fcn, output, 0);
1005 }
1006 else if (flag == "")
1007 {
1008 output(0) = tsol;
1009 octave_value_list val = feval (output_fcn, output, 1);
1010 status = val(0).bool_value ();
1011 }
1012 else
1013 {
1014 // Cleanup plotter
1015 output(0) = tend;
1016 feval (output_fcn, output, 0);
1017 }
1018
1019 return status;
1020 }
1021
1022 void
1023 IDA::set_maxstep (realtype maxstep)
1024 {
1025 if (IDASetMaxStep (m_mem, maxstep) != 0)
1026 error ("IDA: Max Step not set");
1027 }
1028
1029 void
1030 IDA::set_initialstep (realtype initialstep)
1031 {
1032 if (IDASetInitStep (m_mem, initialstep) != 0)
1033 error ("IDA: Initial Step not set");
1034 }
1035
1036 void
1037 IDA::set_maxorder (int maxorder)
1038 {
1039 if (IDASetMaxOrd (m_mem, maxorder) != 0)
1040 error ("IDA: Max Order not set");
1041 }
1042
1043 void
1044 IDA::print_stat (void)
1045 {
1046 long int nsteps = 0, netfails = 0, nrevals = 0;
1047
1048 if (IDAGetNumSteps (m_mem, &nsteps) != 0)
1049 error ("IDA failed to return the number of internal steps");
1050
1051 if (IDAGetNumErrTestFails (m_mem, &netfails) != 0)
1052 error ("IDA failed to return the number of internal errors");
1053
1054 if (IDAGetNumResEvals (m_mem, &nrevals) != 0)
1055 error ("IDA failed to return the number of residual evaluations");
1056
1057 octave_stdout << nsteps << " successful steps\n";
1058 octave_stdout << netfails << " failed attempts\n";
1059 octave_stdout << nrevals << " function evaluations\n";
1060 // octave_stdout << " partial derivatives\n";
1061 // octave_stdout << " LU decompositions\n";
1062 // octave_stdout << " solutions of linear systems\n";
1063 }
1064
1065 static ColumnVector
1066 ida_user_function (const ColumnVector& x, const ColumnVector& xdot,
1067 double t, const octave_value& ida_fc)
1068 {
1069 octave_value_list tmp;
1070
1071 try
1072 {
1073 tmp = feval (ida_fc, ovl (t, x, xdot), 1);
1074 }
1075 catch (execution_exception& ee)
1076 {
1077 err_user_supplied_eval (ee, "__ode15__");
1078 }
1079
1080 return tmp(0).vector_value ();
1081 }
1082
1083 static Matrix
1084 ida_dense_jac (const ColumnVector& x, const ColumnVector& xdot,
1085 double t, double cj, const octave_value& ida_jc)
1086 {
1087 octave_value_list tmp;
1088
1089 try
1090 {
1091 tmp = feval (ida_jc, ovl (t, x, xdot), 2);
1092 }
1093 catch (execution_exception& ee)
1094 {
1095 err_user_supplied_eval (ee, "__ode15__");
1096 }
1097
1098 return tmp(0).matrix_value () + cj * tmp(1).matrix_value ();
1099 }
1100
1101 static SparseMatrix
1102 ida_sparse_jac (const ColumnVector& x, const ColumnVector& xdot,
1103 double t, double cj, const octave_value& ida_jc)
1104 {
1105 octave_value_list tmp;
1106
1107 try
1108 {
1109 tmp = feval (ida_jc, ovl (t, x, xdot), 2);
1110 }
1111 catch (execution_exception& ee)
1112 {
1113 err_user_supplied_eval (ee, "__ode15__");
1114 }
1115
1116 return tmp(0).sparse_matrix_value () + cj * tmp(1).sparse_matrix_value ();
1117 }
1118
1119 static Matrix
1120 ida_dense_cell_jac (Matrix *dfdy, Matrix *dfdyp, double cj)
1121 {
1122 return (*dfdy) + cj * (*dfdyp);
1123 }
1124
1125 static SparseMatrix
1126 ida_sparse_cell_jac (SparseMatrix *spdfdy, SparseMatrix *spdfdyp,
1127 double cj)
1128 {
1129 return (*spdfdy) + cj * (*spdfdyp);
1130 }
1131
1132 static octave_value_list
1133 do_ode15 (const octave_value& ida_fcn,
1134 const ColumnVector& tspan,
1135 const octave_idx_type numt,
1136 const realtype t0,
1137 const ColumnVector& y0,
1138 const ColumnVector& yp0,
1139 const octave_scalar_map& options,
1140 const octave_idx_type num_event_args)
1141 {
1142 octave_value_list retval;
1143
1144 // Create object
1145 IDA dae (t0, y0, yp0, ida_fcn, ida_user_function);
1146
1147 // Set Jacobian
1148 bool havejac = options.getfield ("havejac").bool_value ();
1149
1150 bool havejacsparse = options.getfield ("havejacsparse").bool_value ();
1151
1152 bool havejacfcn = options.getfield ("havejacfcn").bool_value ();
1153
1154 Matrix ida_dfdy, ida_dfdyp;
1155 SparseMatrix ida_spdfdy, ida_spdfdyp;
1156
1157 if (havejac)
1158 {
1159 if (havejacfcn)
1160 {
1161 octave_value ida_jac = options.getfield ("Jacobian");
1162
1163 if (havejacsparse)
1164 dae.set_jacobian (ida_jac, ida_sparse_jac);
1165 else
1166 dae.set_jacobian (ida_jac, ida_dense_jac);
1167 }
1168 else
1169 {
1170 Cell jaccell = options.getfield ("Jacobian").cell_value ();
1171
1172 if (havejacsparse)
1173 {
1174 ida_spdfdy = jaccell(0).sparse_matrix_value ();
1175 ida_spdfdyp = jaccell(1).sparse_matrix_value ();
1176
1177 dae.set_jacobian (&ida_spdfdy, &ida_spdfdyp,
1178 ida_sparse_cell_jac);
1179 }
1180 else
1181 {
1182 ida_dfdy = jaccell(0).matrix_value ();
1183 ida_dfdyp = jaccell(1).matrix_value ();
1184
1185 dae.set_jacobian (&ida_dfdy, &ida_dfdyp, ida_dense_cell_jac);
1186 }
1187 }
1188 }
1189
1190 // Initialize IDA
1191 dae.initialize ();
1192
1193 // Set tolerances
1194 realtype rel_tol = options.getfield ("RelTol").double_value ();
1195
1196 bool haveabstolvec = options.getfield ("haveabstolvec").bool_value ();
1197
1198 if (haveabstolvec)
1199 {
1200 ColumnVector abs_tol = options.getfield ("AbsTol").vector_value ();
1201
1202 dae.set_tolerance (abs_tol, rel_tol);
1203 }
1204 else
1205 {
1206 realtype abs_tol = options.getfield ("AbsTol").double_value ();
1207
1208 dae.set_tolerance (abs_tol, rel_tol);
1209 }
1210
1211 //Set max step
1212 realtype maxstep = options.getfield ("MaxStep").double_value ();
1213
1214 dae.set_maxstep (maxstep);
1215
1216 //Set initial step
1217 if (! options.getfield ("InitialStep").isempty ())
1218 {
1219 realtype initialstep = options.getfield ("InitialStep").double_value ();
1220
1221 dae.set_initialstep (initialstep);
1222 }
1223
1224 //Set max order FIXME: it doesn't work
1225 int maxorder = options.getfield ("MaxOrder").int_value ();
1226
1227 dae.set_maxorder (maxorder);
1228
1229 //Set Refine
1230 const int refine = options.getfield ("Refine").int_value ();
1231
1232 bool haverefine = (refine > 1);
1233
1234 octave_value output_fcn;
1235 ColumnVector outputsel;
1236
1237 // OutputFcn
1238 bool haveoutputfunction
1239 = options.getfield ("haveoutputfunction").bool_value ();
1240
1241 if (haveoutputfunction)
1242 output_fcn = options.getfield ("OutputFcn");
1243
1244 // OutputSel
1245 bool haveoutputsel = options.getfield ("haveoutputselection").bool_value ();
1246
1247 if (haveoutputsel)
1248 outputsel = options.getfield ("OutputSel").vector_value ();
1249
1250 octave_value event_fcn;
1251
1252 // Events
1253 bool haveeventfunction
1254 = options.getfield ("haveeventfunction").bool_value ();
1255
1256 if (haveeventfunction)
1257 event_fcn = options.getfield ("Events");
1258
1259 // Set up linear solver
1260 dae.set_up (y0);
1261
1262 // Integrate
1263 retval = dae.integrate (numt, tspan, y0, yp0, refine,
1264 haverefine, haveoutputfunction,
1265 output_fcn, haveoutputsel, outputsel,
1266 haveeventfunction, event_fcn, num_event_args);
1267
1268 // Statistics
1269 bool havestats = options.getfield ("havestats").bool_value ();
1270
1271 if (havestats)
1272 dae.print_stat ();
1273
1274 return retval;
1275 }
1276 1276
1277 #endif 1277 #endif
1278 1278
1279 DEFUN_DLD (__ode15__, args, , 1279 DEFUN_DLD (__ode15__, args, ,
1280 doc: /* -*- texinfo -*- 1280 doc: /* -*- texinfo -*-