00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026
00027 #include <cfloat>
00028
00029 #include <sstream>
00030
00031 #include "LSODE.h"
00032 #include "f77-fcn.h"
00033 #include "lo-error.h"
00034 #include "lo-math.h"
00035 #include "quit.h"
00036
00037 typedef octave_idx_type (*lsode_fcn_ptr) (const octave_idx_type&,
00038 const double&, double*,
00039 double*, octave_idx_type&);
00040
00041 typedef octave_idx_type (*lsode_jac_ptr) (const octave_idx_type&,
00042 const double&, double*,
00043 const octave_idx_type&,
00044 const octave_idx_type&,
00045 double*, const octave_idx_type&);
00046
00047 extern "C"
00048 {
00049 F77_RET_T
00050 F77_FUNC (dlsode, DLSODE) (lsode_fcn_ptr, octave_idx_type&, double*,
00051 double&, double&, octave_idx_type&, double&,
00052 const double*, octave_idx_type&,
00053 octave_idx_type&, octave_idx_type&,
00054 double*, octave_idx_type&, octave_idx_type*,
00055 octave_idx_type&, lsode_jac_ptr,
00056 octave_idx_type&);
00057 }
00058
00059 static ODEFunc::ODERHSFunc user_fun;
00060 static ODEFunc::ODEJacFunc user_jac;
00061 static ColumnVector *tmp_x;
00062
00063 static octave_idx_type
00064 lsode_f (const octave_idx_type& neq, const double& time, double *,
00065 double *deriv, octave_idx_type& ierr)
00066 {
00067 BEGIN_INTERRUPT_WITH_EXCEPTIONS;
00068
00069 ColumnVector tmp_deriv;
00070
00071
00072
00073
00074
00075 tmp_deriv = (*user_fun) (*tmp_x, time);
00076
00077 if (tmp_deriv.length () == 0)
00078 ierr = -1;
00079 else
00080 {
00081 for (octave_idx_type i = 0; i < neq; i++)
00082 deriv [i] = tmp_deriv.elem (i);
00083 }
00084
00085 END_INTERRUPT_WITH_EXCEPTIONS;
00086
00087 return 0;
00088 }
00089
00090 static octave_idx_type
00091 lsode_j (const octave_idx_type& neq, const double& time, double *,
00092 const octave_idx_type&, const octave_idx_type&, double *pd, const octave_idx_type& nrowpd)
00093 {
00094 BEGIN_INTERRUPT_WITH_EXCEPTIONS;
00095
00096 Matrix tmp_jac (neq, neq);
00097
00098
00099
00100
00101
00102 tmp_jac = (*user_jac) (*tmp_x, time);
00103
00104 for (octave_idx_type j = 0; j < neq; j++)
00105 for (octave_idx_type i = 0; i < neq; i++)
00106 pd [nrowpd * j + i] = tmp_jac (i, j);
00107
00108 END_INTERRUPT_WITH_EXCEPTIONS;
00109
00110 return 0;
00111 }
00112
00113 ColumnVector
00114 LSODE::do_integrate (double tout)
00115 {
00116 ColumnVector retval;
00117
00118 static octave_idx_type nn = 0;
00119
00120 if (! initialized || restart || ODEFunc::reset || LSODE_options::reset)
00121 {
00122 integration_error = false;
00123
00124 initialized = true;
00125
00126 istate = 1;
00127
00128 octave_idx_type n = size ();
00129
00130 nn = n;
00131
00132 octave_idx_type max_maxord = 0;
00133
00134 if (integration_method () == "stiff")
00135 {
00136 max_maxord = 5;
00137
00138 if (jac)
00139 method_flag = 21;
00140 else
00141 method_flag = 22;
00142
00143 liw = 20 + n;
00144 lrw = 22 + n * (9 + n);
00145 }
00146 else
00147 {
00148 max_maxord = 12;
00149
00150 method_flag = 10;
00151
00152 liw = 20;
00153 lrw = 22 + 16 * n;
00154 }
00155
00156 maxord = maximum_order ();
00157
00158 iwork.resize (dim_vector (liw, 1));
00159
00160 for (octave_idx_type i = 4; i < 9; i++)
00161 iwork(i) = 0;
00162
00163 rwork.resize (dim_vector (lrw, 1));
00164
00165 for (octave_idx_type i = 4; i < 9; i++)
00166 rwork(i) = 0;
00167
00168 if (maxord >= 0)
00169 {
00170 if (maxord > 0 && maxord <= max_maxord)
00171 {
00172 iwork(4) = maxord;
00173 iopt = 1;
00174 }
00175 else
00176 {
00177 (*current_liboctave_error_handler)
00178 ("lsode: invalid value for maximum order");
00179 integration_error = true;
00180 return retval;
00181 }
00182 }
00183
00184 if (stop_time_set)
00185 {
00186 itask = 4;
00187 rwork(0) = stop_time;
00188 iopt = 1;
00189 }
00190 else
00191 {
00192 itask = 1;
00193 }
00194
00195 restart = false;
00196
00197
00198
00199
00200
00201
00202
00203 tmp_x = &x;
00204
00205 user_fun = function ();
00206 user_jac = jacobian_function ();
00207
00208 ColumnVector xdot = (*user_fun) (x, t);
00209
00210 if (x.length () != xdot.length ())
00211 {
00212 (*current_liboctave_error_handler)
00213 ("lsode: inconsistent sizes for state and derivative vectors");
00214
00215 integration_error = true;
00216 return retval;
00217 }
00218
00219 ODEFunc::reset = false;
00220
00221
00222
00223 rel_tol = relative_tolerance ();
00224 abs_tol = absolute_tolerance ();
00225
00226 octave_idx_type abs_tol_len = abs_tol.length ();
00227
00228 if (abs_tol_len == 1)
00229 itol = 1;
00230 else if (abs_tol_len == n)
00231 itol = 2;
00232 else
00233 {
00234 (*current_liboctave_error_handler)
00235 ("lsode: inconsistent sizes for state and absolute tolerance vectors");
00236
00237 integration_error = true;
00238 return retval;
00239 }
00240
00241 double iss = initial_step_size ();
00242 if (iss >= 0.0)
00243 {
00244 rwork(4) = iss;
00245 iopt = 1;
00246 }
00247
00248 double maxss = maximum_step_size ();
00249 if (maxss >= 0.0)
00250 {
00251 rwork(5) = maxss;
00252 iopt = 1;
00253 }
00254
00255 double minss = minimum_step_size ();
00256 if (minss >= 0.0)
00257 {
00258 rwork(6) = minss;
00259 iopt = 1;
00260 }
00261
00262 octave_idx_type sl = step_limit ();
00263 if (sl > 0)
00264 {
00265 iwork(5) = sl;
00266 iopt = 1;
00267 }
00268
00269 LSODE_options::reset = false;
00270 }
00271
00272 double *px = x.fortran_vec ();
00273
00274 double *pabs_tol = abs_tol.fortran_vec ();
00275
00276 octave_idx_type *piwork = iwork.fortran_vec ();
00277 double *prwork = rwork.fortran_vec ();
00278
00279 F77_XFCN (dlsode, DLSODE, (lsode_f, nn, px, t, tout, itol, rel_tol,
00280 pabs_tol, itask, istate, iopt, prwork, lrw,
00281 piwork, liw, lsode_j, method_flag));
00282
00283 switch (istate)
00284 {
00285 case 1:
00286 case 2:
00287 retval = x;
00288 t = tout;
00289 break;
00290
00291 case -1:
00292 case -2:
00293 case -3:
00294 case -4:
00295 case -5:
00296
00297 case -6:
00298
00299 case -13:
00300 integration_error = true;
00301 break;
00302
00303 default:
00304 integration_error = true;
00305 (*current_liboctave_error_handler)
00306 ("unrecognized value of istate (= %d) returned from lsode",
00307 istate);
00308 break;
00309 }
00310
00311 return retval;
00312 }
00313
00314 std::string
00315 LSODE::error_message (void) const
00316 {
00317 std::string retval;
00318
00319 std::ostringstream buf;
00320 buf << t;
00321 std::string t_curr = buf.str ();
00322
00323 switch (istate)
00324 {
00325 case 1:
00326 retval = "prior to initial integration step";
00327 break;
00328
00329 case 2:
00330 retval = "successful exit";
00331 break;
00332
00333 case 3:
00334 retval = "prior to continuation call with modified parameters";
00335 break;
00336
00337 case -1:
00338 retval = std::string ("excess work on this call (t = ")
00339 + t_curr + "; perhaps wrong integration method)";
00340 break;
00341
00342 case -2:
00343 retval = "excess accuracy requested (tolerances too small)";
00344 break;
00345
00346 case -3:
00347 retval = "invalid input detected (see printed message)";
00348 break;
00349
00350 case -4:
00351 retval = std::string ("repeated error test failures (t = ")
00352 + t_curr + "; check all inputs)";
00353 break;
00354
00355 case -5:
00356 retval = std::string ("repeated convergence failures (t = ")
00357 + t_curr
00358 + "; perhaps bad Jacobian supplied or wrong choice of integration method or tolerances)";
00359 break;
00360
00361 case -6:
00362 retval = std::string ("error weight became zero during problem. (t = ")
00363 + t_curr
00364 + "; solution component i vanished, and atol or atol(i) == 0)";
00365 break;
00366
00367 case -13:
00368 retval = "return requested in user-supplied function (t = "
00369 + t_curr + ")";
00370 break;
00371
00372 default:
00373 retval = "unknown error state";
00374 break;
00375 }
00376
00377 return retval;
00378 }
00379
00380 Matrix
00381 LSODE::do_integrate (const ColumnVector& tout)
00382 {
00383 Matrix retval;
00384
00385 octave_idx_type n_out = tout.capacity ();
00386 octave_idx_type n = size ();
00387
00388 if (n_out > 0 && n > 0)
00389 {
00390 retval.resize (n_out, n);
00391
00392 for (octave_idx_type i = 0; i < n; i++)
00393 retval.elem (0, i) = x.elem (i);
00394
00395 for (octave_idx_type j = 1; j < n_out; j++)
00396 {
00397 ColumnVector x_next = do_integrate (tout.elem (j));
00398
00399 if (integration_error)
00400 return retval;
00401
00402 for (octave_idx_type i = 0; i < n; i++)
00403 retval.elem (j, i) = x_next.elem (i);
00404 }
00405 }
00406
00407 return retval;
00408 }
00409
00410 Matrix
00411 LSODE::do_integrate (const ColumnVector& tout, const ColumnVector& tcrit)
00412 {
00413 Matrix retval;
00414
00415 octave_idx_type n_out = tout.capacity ();
00416 octave_idx_type n = size ();
00417
00418 if (n_out > 0 && n > 0)
00419 {
00420 retval.resize (n_out, n);
00421
00422 for (octave_idx_type i = 0; i < n; i++)
00423 retval.elem (0, i) = x.elem (i);
00424
00425 octave_idx_type n_crit = tcrit.capacity ();
00426
00427 if (n_crit > 0)
00428 {
00429 octave_idx_type i_crit = 0;
00430 octave_idx_type i_out = 1;
00431 double next_crit = tcrit.elem (0);
00432 double next_out;
00433 while (i_out < n_out)
00434 {
00435 bool do_restart = false;
00436
00437 next_out = tout.elem (i_out);
00438 if (i_crit < n_crit)
00439 next_crit = tcrit.elem (i_crit);
00440
00441 octave_idx_type save_output;
00442 double t_out;
00443
00444 if (next_crit == next_out)
00445 {
00446 set_stop_time (next_crit);
00447 t_out = next_out;
00448 save_output = 1;
00449 i_out++;
00450 i_crit++;
00451 do_restart = true;
00452 }
00453 else if (next_crit < next_out)
00454 {
00455 if (i_crit < n_crit)
00456 {
00457 set_stop_time (next_crit);
00458 t_out = next_crit;
00459 save_output = 0;
00460 i_crit++;
00461 do_restart = true;
00462 }
00463 else
00464 {
00465 clear_stop_time ();
00466 t_out = next_out;
00467 save_output = 1;
00468 i_out++;
00469 }
00470 }
00471 else
00472 {
00473 set_stop_time (next_crit);
00474 t_out = next_out;
00475 save_output = 1;
00476 i_out++;
00477 }
00478
00479 ColumnVector x_next = do_integrate (t_out);
00480
00481 if (integration_error)
00482 return retval;
00483
00484 if (save_output)
00485 {
00486 for (octave_idx_type i = 0; i < n; i++)
00487 retval.elem (i_out-1, i) = x_next.elem (i);
00488 }
00489
00490 if (do_restart)
00491 force_restart ();
00492 }
00493 }
00494 else
00495 {
00496 retval = do_integrate (tout);
00497
00498 if (integration_error)
00499 return retval;
00500 }
00501 }
00502
00503 return retval;
00504 }