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 "DASSL.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 (*dassl_fcn_ptr) (const double&, const double*,
00038 const double*, double*,
00039 octave_idx_type&, double*,
00040 octave_idx_type*);
00041
00042 typedef octave_idx_type (*dassl_jac_ptr) (const double&, const double*,
00043 const double*, double*,
00044 const double&, double*,
00045 octave_idx_type*);
00046
00047 extern "C"
00048 {
00049 F77_RET_T
00050 F77_FUNC (ddassl, DDASSL) (dassl_fcn_ptr, const octave_idx_type&,
00051 double&, double*, double*, double&,
00052 const octave_idx_type*, const double*,
00053 const double*, octave_idx_type&,
00054 double*, const octave_idx_type&,
00055 octave_idx_type*, const octave_idx_type&,
00056 const double*, const octave_idx_type*,
00057 dassl_jac_ptr);
00058 }
00059
00060 static DAEFunc::DAERHSFunc user_fun;
00061 static DAEFunc::DAEJacFunc user_jac;
00062
00063 static octave_idx_type nn;
00064
00065 static octave_idx_type
00066 ddassl_f (const double& time, const double *state, const double *deriv,
00067 double *delta, octave_idx_type& ires, double *, octave_idx_type *)
00068 {
00069 BEGIN_INTERRUPT_WITH_EXCEPTIONS;
00070
00071
00072
00073 ColumnVector tmp_deriv (nn);
00074 ColumnVector tmp_state (nn);
00075 ColumnVector tmp_delta (nn);
00076
00077 for (octave_idx_type i = 0; i < nn; i++)
00078 {
00079 tmp_deriv.elem (i) = deriv [i];
00080 tmp_state.elem (i) = state [i];
00081 }
00082
00083 tmp_delta = user_fun (tmp_state, tmp_deriv, time, ires);
00084
00085 if (ires >= 0)
00086 {
00087 if (tmp_delta.length () == 0)
00088 ires = -2;
00089 else
00090 {
00091 for (octave_idx_type i = 0; i < nn; i++)
00092 delta [i] = tmp_delta.elem (i);
00093 }
00094 }
00095
00096 END_INTERRUPT_WITH_EXCEPTIONS;
00097
00098 return 0;
00099 }
00100
00101 static octave_idx_type
00102 ddassl_j (const double& time, const double *state, const double *deriv,
00103 double *pd, const double& cj, double *, octave_idx_type *)
00104 {
00105 BEGIN_INTERRUPT_WITH_EXCEPTIONS;
00106
00107
00108
00109 ColumnVector tmp_state (nn);
00110 ColumnVector tmp_deriv (nn);
00111
00112 for (octave_idx_type i = 0; i < nn; i++)
00113 {
00114 tmp_deriv.elem (i) = deriv [i];
00115 tmp_state.elem (i) = state [i];
00116 }
00117
00118 Matrix tmp_pd = user_jac (tmp_state, tmp_deriv, time, cj);
00119
00120 for (octave_idx_type j = 0; j < nn; j++)
00121 for (octave_idx_type i = 0; i < nn; i++)
00122 pd [nn * j + i] = tmp_pd.elem (i, j);
00123
00124 END_INTERRUPT_WITH_EXCEPTIONS;
00125
00126 return 0;
00127 }
00128
00129 ColumnVector
00130 DASSL::do_integrate (double tout)
00131 {
00132 ColumnVector retval;
00133
00134 if (! initialized || restart || DAEFunc::reset|| DASSL_options::reset)
00135 {
00136 integration_error = false;
00137
00138 initialized = true;
00139
00140 info.resize (dim_vector (15, 1));
00141
00142 for (octave_idx_type i = 0; i < 15; i++)
00143 info(i) = 0;
00144
00145 octave_idx_type n = size ();
00146
00147 liw = 21 + n;
00148 lrw = 40 + 9*n + n*n;
00149
00150 nn = n;
00151
00152 iwork.resize (dim_vector (liw, 1));
00153 rwork.resize (dim_vector (lrw, 1));
00154
00155 info(0) = 0;
00156
00157 if (stop_time_set)
00158 {
00159 rwork(0) = stop_time;
00160 info(3) = 1;
00161 }
00162 else
00163 info(3) = 0;
00164
00165 restart = false;
00166
00167
00168
00169 user_fun = DAEFunc::function ();
00170 user_jac = DAEFunc::jacobian_function ();
00171
00172 if (user_fun)
00173 {
00174 octave_idx_type ires = 0;
00175
00176 ColumnVector res = (*user_fun) (x, xdot, t, ires);
00177
00178 if (res.length () != x.length ())
00179 {
00180 (*current_liboctave_error_handler)
00181 ("dassl: inconsistent sizes for state and residual vectors");
00182
00183 integration_error = true;
00184 return retval;
00185 }
00186 }
00187 else
00188 {
00189 (*current_liboctave_error_handler)
00190 ("dassl: no user supplied RHS subroutine!");
00191
00192 integration_error = true;
00193 return retval;
00194 }
00195
00196 info(4) = user_jac ? 1 : 0;
00197
00198 DAEFunc::reset = false;
00199
00200
00201
00202 double hmax = maximum_step_size ();
00203 if (hmax >= 0.0)
00204 {
00205 rwork(1) = hmax;
00206 info(6) = 1;
00207 }
00208 else
00209 info(6) = 0;
00210
00211 double h0 = initial_step_size ();
00212 if (h0 >= 0.0)
00213 {
00214 rwork(2) = h0;
00215 info(7) = 1;
00216 }
00217 else
00218 info(7) = 0;
00219
00220 if (step_limit () >= 0)
00221 {
00222 info(11) = 1;
00223 iwork(20) = step_limit ();
00224 }
00225 else
00226 info(11) = 0;
00227
00228 octave_idx_type maxord = maximum_order ();
00229 if (maxord >= 0)
00230 {
00231 if (maxord > 0 && maxord < 6)
00232 {
00233 info(8) = 1;
00234 iwork(2) = maxord;
00235 }
00236 else
00237 {
00238 (*current_liboctave_error_handler)
00239 ("dassl: invalid value for maximum order: %d", maxord);
00240 integration_error = true;
00241 return retval;
00242 }
00243 }
00244
00245 octave_idx_type enc = enforce_nonnegativity_constraints ();
00246 info(9) = enc ? 1 : 0;
00247
00248 octave_idx_type ccic = compute_consistent_initial_condition ();
00249 info(10) = ccic ? 1 : 0;
00250
00251 abs_tol = absolute_tolerance ();
00252 rel_tol = relative_tolerance ();
00253
00254 octave_idx_type abs_tol_len = abs_tol.length ();
00255 octave_idx_type rel_tol_len = rel_tol.length ();
00256
00257 if (abs_tol_len == 1 && rel_tol_len == 1)
00258 {
00259 info(1) = 0;
00260 }
00261 else if (abs_tol_len == n && rel_tol_len == n)
00262 {
00263 info(1) = 1;
00264 }
00265 else
00266 {
00267 (*current_liboctave_error_handler)
00268 ("dassl: inconsistent sizes for tolerance arrays");
00269
00270 integration_error = true;
00271 return retval;
00272 }
00273
00274 DASSL_options::reset = false;
00275 }
00276
00277 double *px = x.fortran_vec ();
00278 double *pxdot = xdot.fortran_vec ();
00279
00280 octave_idx_type *pinfo = info.fortran_vec ();
00281
00282 double *prel_tol = rel_tol.fortran_vec ();
00283 double *pabs_tol = abs_tol.fortran_vec ();
00284
00285 double *prwork = rwork.fortran_vec ();
00286 octave_idx_type *piwork = iwork.fortran_vec ();
00287
00288 double *dummy = 0;
00289 octave_idx_type *idummy = 0;
00290
00291 F77_XFCN (ddassl, DDASSL, (ddassl_f, nn, t, px, pxdot, tout, pinfo,
00292 prel_tol, pabs_tol, istate, prwork, lrw,
00293 piwork, liw, dummy, idummy, ddassl_j));
00294
00295 switch (istate)
00296 {
00297 case 1:
00298
00299 case 2:
00300
00301 case 3:
00302
00303
00304 retval = x;
00305 t = tout;
00306 break;
00307
00308 case -1:
00309 case -2:
00310 case -3:
00311
00312
00313
00314
00315 case -6:
00316
00317 case -7:
00318 case -8:
00319 case -9:
00320
00321 case -10:
00322
00323 case -11:
00324
00325 case -12:
00326 case -33:
00327
00328
00329
00330 integration_error = true;
00331 break;
00332
00333 default:
00334 integration_error = true;
00335 (*current_liboctave_error_handler)
00336 ("unrecognized value of istate (= %d) returned from ddassl",
00337 istate);
00338 break;
00339 }
00340
00341 return retval;
00342 }
00343
00344 Matrix
00345 DASSL::do_integrate (const ColumnVector& tout)
00346 {
00347 Matrix dummy;
00348 return integrate (tout, dummy);
00349 }
00350
00351 Matrix
00352 DASSL::integrate (const ColumnVector& tout, Matrix& xdot_out)
00353 {
00354 Matrix retval;
00355
00356 octave_idx_type n_out = tout.capacity ();
00357 octave_idx_type n = size ();
00358
00359 if (n_out > 0 && n > 0)
00360 {
00361 retval.resize (n_out, n);
00362 xdot_out.resize (n_out, n);
00363
00364 for (octave_idx_type i = 0; i < n; i++)
00365 {
00366 retval.elem (0, i) = x.elem (i);
00367 xdot_out.elem (0, i) = xdot.elem (i);
00368 }
00369
00370 for (octave_idx_type j = 1; j < n_out; j++)
00371 {
00372 ColumnVector x_next = do_integrate (tout.elem (j));
00373
00374 if (integration_error)
00375 return retval;
00376
00377 for (octave_idx_type i = 0; i < n; i++)
00378 {
00379 retval.elem (j, i) = x_next.elem (i);
00380 xdot_out.elem (j, i) = xdot.elem (i);
00381 }
00382 }
00383 }
00384
00385 return retval;
00386 }
00387
00388 Matrix
00389 DASSL::do_integrate (const ColumnVector& tout, const ColumnVector& tcrit)
00390 {
00391 Matrix dummy;
00392 return integrate (tout, dummy, tcrit);
00393 }
00394
00395 Matrix
00396 DASSL::integrate (const ColumnVector& tout, Matrix& xdot_out,
00397 const ColumnVector& tcrit)
00398 {
00399 Matrix retval;
00400
00401 octave_idx_type n_out = tout.capacity ();
00402 octave_idx_type n = size ();
00403
00404 if (n_out > 0 && n > 0)
00405 {
00406 retval.resize (n_out, n);
00407 xdot_out.resize (n_out, n);
00408
00409 for (octave_idx_type i = 0; i < n; i++)
00410 {
00411 retval.elem (0, i) = x.elem (i);
00412 xdot_out.elem (0, i) = xdot.elem (i);
00413 }
00414
00415 octave_idx_type n_crit = tcrit.capacity ();
00416
00417 if (n_crit > 0)
00418 {
00419 octave_idx_type i_crit = 0;
00420 octave_idx_type i_out = 1;
00421 double next_crit = tcrit.elem (0);
00422 double next_out;
00423 while (i_out < n_out)
00424 {
00425 bool do_restart = false;
00426
00427 next_out = tout.elem (i_out);
00428 if (i_crit < n_crit)
00429 next_crit = tcrit.elem (i_crit);
00430
00431 bool save_output;
00432 double t_out;
00433
00434 if (next_crit == next_out)
00435 {
00436 set_stop_time (next_crit);
00437 t_out = next_out;
00438 save_output = true;
00439 i_out++;
00440 i_crit++;
00441 do_restart = true;
00442 }
00443 else if (next_crit < next_out)
00444 {
00445 if (i_crit < n_crit)
00446 {
00447 set_stop_time (next_crit);
00448 t_out = next_crit;
00449 save_output = false;
00450 i_crit++;
00451 do_restart = true;
00452 }
00453 else
00454 {
00455 clear_stop_time ();
00456 t_out = next_out;
00457 save_output = true;
00458 i_out++;
00459 }
00460 }
00461 else
00462 {
00463 set_stop_time (next_crit);
00464 t_out = next_out;
00465 save_output = true;
00466 i_out++;
00467 }
00468
00469 ColumnVector x_next = do_integrate (t_out);
00470
00471 if (integration_error)
00472 return retval;
00473
00474 if (save_output)
00475 {
00476 for (octave_idx_type i = 0; i < n; i++)
00477 {
00478 retval.elem (i_out-1, i) = x_next.elem (i);
00479 xdot_out.elem (i_out-1, i) = xdot.elem (i);
00480 }
00481 }
00482
00483 if (do_restart)
00484 force_restart ();
00485 }
00486 }
00487 else
00488 {
00489 retval = integrate (tout, xdot_out);
00490
00491 if (integration_error)
00492 return retval;
00493 }
00494 }
00495
00496 return retval;
00497 }
00498
00499 std::string
00500 DASSL::error_message (void) const
00501 {
00502 std::string retval;
00503
00504 std::ostringstream buf;
00505 buf << t;
00506 std::string t_curr = buf.str ();
00507
00508 switch (istate)
00509 {
00510 case 1:
00511 retval = "a step was successfully taken in intermediate-output mode.";
00512 break;
00513
00514 case 2:
00515 retval = "integration completed by stepping exactly to TOUT";
00516 break;
00517
00518 case 3:
00519 retval = "integration to tout completed by stepping past TOUT";
00520 break;
00521
00522 case -1:
00523 retval = std::string ("a large amount of work has been expended (t =")
00524 + t_curr + ")";
00525 break;
00526
00527 case -2:
00528 retval = "the error tolerances are too stringent";
00529 break;
00530
00531 case -3:
00532 retval = std::string ("error weight became zero during problem. (t = ")
00533 + t_curr
00534 + "; solution component i vanished, and atol or atol(i) == 0)";
00535 break;
00536
00537 case -6:
00538 retval = std::string ("repeated error test failures on the last attempted step (t = ")
00539 + t_curr + ")";
00540 break;
00541
00542 case -7:
00543 retval = std::string ("the corrector could not converge (t = ")
00544 + t_curr + ")";
00545 break;
00546
00547 case -8:
00548 retval = std::string ("the matrix of partial derivatives is singular (t = ")
00549 + t_curr + ")";
00550 break;
00551
00552 case -9:
00553 retval = std::string ("the corrector could not converge (t = ")
00554 + t_curr + "; repeated test failures)";
00555 break;
00556
00557 case -10:
00558 retval = std::string ("corrector could not converge because IRES was -1 (t = ")
00559 + t_curr + ")";
00560 break;
00561
00562 case -11:
00563 retval = std::string ("return requested in user-supplied function (t = ")
00564 + t_curr + ")";
00565 break;
00566
00567 case -12:
00568 retval = "failed to compute consistent initial conditions";
00569 break;
00570
00571 case -33:
00572 retval = "unrecoverable error (see printed message)";
00573 break;
00574
00575 default:
00576 retval = "unknown error state";
00577 break;
00578 }
00579
00580 return retval;
00581 }