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 "DASPK.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 (*daspk_fcn_ptr) (const double&, const double*,
00038 const double*, const double&,
00039 double*, octave_idx_type&,
00040 double*, octave_idx_type*);
00041
00042 typedef octave_idx_type (*daspk_jac_ptr) (const double&, const double*,
00043 const double*, double*,
00044 const double&, double*,
00045 octave_idx_type*);
00046
00047 typedef octave_idx_type (*daspk_psol_ptr) (const octave_idx_type&,
00048 const double&, const double*,
00049 const double*, const double*,
00050 const double&, const double*,
00051 double*, octave_idx_type*,
00052 double*, const double&,
00053 octave_idx_type&, double*,
00054 octave_idx_type*);
00055
00056 extern "C"
00057 {
00058 F77_RET_T
00059 F77_FUNC (ddaspk, DDASPK) (daspk_fcn_ptr, const octave_idx_type&,
00060 double&, double*, double*, double&,
00061 const octave_idx_type*, const double*,
00062 const double*, octave_idx_type&,
00063 double*, const octave_idx_type&,
00064 octave_idx_type*, const octave_idx_type&,
00065 const double*, const octave_idx_type*,
00066 daspk_jac_ptr, daspk_psol_ptr);
00067 }
00068
00069 static DAEFunc::DAERHSFunc user_fun;
00070 static DAEFunc::DAEJacFunc user_jac;
00071 static octave_idx_type nn;
00072
00073 static octave_idx_type
00074 ddaspk_f (const double& time, const double *state, const double *deriv,
00075 const double&, double *delta, octave_idx_type& ires, double *,
00076 octave_idx_type *)
00077 {
00078 BEGIN_INTERRUPT_WITH_EXCEPTIONS;
00079
00080 ColumnVector tmp_deriv (nn);
00081 ColumnVector tmp_state (nn);
00082 ColumnVector tmp_delta (nn);
00083
00084 for (octave_idx_type i = 0; i < nn; i++)
00085 {
00086 tmp_deriv.elem (i) = deriv [i];
00087 tmp_state.elem (i) = state [i];
00088 }
00089
00090 tmp_delta = user_fun (tmp_state, tmp_deriv, time, ires);
00091
00092 if (ires >= 0)
00093 {
00094 if (tmp_delta.length () == 0)
00095 ires = -2;
00096 else
00097 {
00098 for (octave_idx_type i = 0; i < nn; i++)
00099 delta [i] = tmp_delta.elem (i);
00100 }
00101 }
00102
00103 END_INTERRUPT_WITH_EXCEPTIONS;
00104
00105 return 0;
00106 }
00107
00108
00109
00110
00111 static octave_idx_type
00112 ddaspk_psol (const octave_idx_type&, const double&, const double *,
00113 const double *, const double *, const double&,
00114 const double *, double *, octave_idx_type *, double *,
00115 const double&, octave_idx_type&, double *, octave_idx_type*)
00116 {
00117 BEGIN_INTERRUPT_WITH_EXCEPTIONS;
00118
00119 abort ();
00120
00121 END_INTERRUPT_WITH_EXCEPTIONS;
00122
00123 return 0;
00124 }
00125
00126
00127 static octave_idx_type
00128 ddaspk_j (const double& time, const double *state, const double *deriv,
00129 double *pd, const double& cj, double *, octave_idx_type *)
00130 {
00131 BEGIN_INTERRUPT_WITH_EXCEPTIONS;
00132
00133
00134
00135 ColumnVector tmp_state (nn);
00136 ColumnVector tmp_deriv (nn);
00137
00138 for (octave_idx_type i = 0; i < nn; i++)
00139 {
00140 tmp_deriv.elem (i) = deriv [i];
00141 tmp_state.elem (i) = state [i];
00142 }
00143
00144 Matrix tmp_pd = user_jac (tmp_state, tmp_deriv, time, cj);
00145
00146 for (octave_idx_type j = 0; j < nn; j++)
00147 for (octave_idx_type i = 0; i < nn; i++)
00148 pd [nn * j + i] = tmp_pd.elem (i, j);
00149
00150 END_INTERRUPT_WITH_EXCEPTIONS;
00151
00152 return 0;
00153 }
00154
00155 ColumnVector
00156 DASPK::do_integrate (double tout)
00157 {
00158
00159
00160
00161 ColumnVector retval;
00162
00163 if (! initialized || restart || DAEFunc::reset|| DASPK_options::reset)
00164 {
00165 integration_error = false;
00166
00167 initialized = true;
00168
00169 info.resize (dim_vector (20, 1));
00170
00171 for (octave_idx_type i = 0; i < 20; i++)
00172 info(i) = 0;
00173
00174 octave_idx_type n = size ();
00175
00176 nn = n;
00177
00178 info(0) = 0;
00179
00180 if (stop_time_set)
00181 {
00182 rwork(0) = stop_time;
00183 info(3) = 1;
00184 }
00185 else
00186 info(3) = 0;
00187
00188
00189
00190 user_fun = DAEFunc::function ();
00191 user_jac = DAEFunc::jacobian_function ();
00192
00193 if (user_fun)
00194 {
00195 octave_idx_type ires = 0;
00196
00197 ColumnVector res = (*user_fun) (x, xdot, t, ires);
00198
00199 if (res.length () != x.length ())
00200 {
00201 (*current_liboctave_error_handler)
00202 ("daspk: inconsistent sizes for state and residual vectors");
00203
00204 integration_error = true;
00205 return retval;
00206 }
00207 }
00208 else
00209 {
00210 (*current_liboctave_error_handler)
00211 ("daspk: no user supplied RHS subroutine!");
00212
00213 integration_error = true;
00214 return retval;
00215 }
00216
00217 info(4) = user_jac ? 1 : 0;
00218
00219 DAEFunc::reset = false;
00220
00221 octave_idx_type eiq = enforce_inequality_constraints ();
00222 octave_idx_type ccic = compute_consistent_initial_condition ();
00223 octave_idx_type eavfet = exclude_algebraic_variables_from_error_test ();
00224
00225 liw = 40 + n;
00226 if (eiq == 1 || eiq == 3)
00227 liw += n;
00228 if (ccic == 1 || eavfet == 1)
00229 liw += n;
00230
00231 lrw = 50 + 9*n + n*n;
00232 if (eavfet == 1)
00233 lrw += n;
00234
00235 iwork.resize (dim_vector (liw, 1));
00236 rwork.resize (dim_vector (lrw, 1));
00237
00238
00239
00240 abs_tol = absolute_tolerance ();
00241 rel_tol = relative_tolerance ();
00242
00243 octave_idx_type abs_tol_len = abs_tol.length ();
00244 octave_idx_type rel_tol_len = rel_tol.length ();
00245
00246 if (abs_tol_len == 1 && rel_tol_len == 1)
00247 {
00248 info(1) = 0;
00249 }
00250 else if (abs_tol_len == n && rel_tol_len == n)
00251 {
00252 info(1) = 1;
00253 }
00254 else
00255 {
00256 (*current_liboctave_error_handler)
00257 ("daspk: inconsistent sizes for tolerance arrays");
00258
00259 integration_error = true;
00260 return retval;
00261 }
00262
00263 double hmax = maximum_step_size ();
00264 if (hmax >= 0.0)
00265 {
00266 rwork(1) = hmax;
00267 info(6) = 1;
00268 }
00269 else
00270 info(6) = 0;
00271
00272 double h0 = initial_step_size ();
00273 if (h0 >= 0.0)
00274 {
00275 rwork(2) = h0;
00276 info(7) = 1;
00277 }
00278 else
00279 info(7) = 0;
00280
00281 octave_idx_type maxord = maximum_order ();
00282 if (maxord >= 0)
00283 {
00284 if (maxord > 0 && maxord < 6)
00285 {
00286 info(8) = 1;
00287 iwork(2) = maxord;
00288 }
00289 else
00290 {
00291 (*current_liboctave_error_handler)
00292 ("daspk: invalid value for maximum order");
00293 integration_error = true;
00294 return retval;
00295 }
00296 }
00297
00298 switch (eiq)
00299 {
00300 case 1:
00301 case 3:
00302 {
00303 Array<octave_idx_type> ict = inequality_constraint_types ();
00304
00305 if (ict.length () == n)
00306 {
00307 for (octave_idx_type i = 0; i < n; i++)
00308 {
00309 octave_idx_type val = ict(i);
00310 if (val < -2 || val > 2)
00311 {
00312 (*current_liboctave_error_handler)
00313 ("daspk: invalid value for inequality constraint type");
00314 integration_error = true;
00315 return retval;
00316 }
00317 iwork(40+i) = val;
00318 }
00319 }
00320 else
00321 {
00322 (*current_liboctave_error_handler)
00323 ("daspk: inequality constraint types size mismatch");
00324 integration_error = true;
00325 return retval;
00326 }
00327 }
00328
00329
00330 case 0:
00331 case 2:
00332 info(9) = eiq;
00333 break;
00334
00335 default:
00336 (*current_liboctave_error_handler)
00337 ("daspk: invalid value for enforce inequality constraints option");
00338 integration_error = true;
00339 return retval;
00340 }
00341
00342 if (ccic)
00343 {
00344 if (ccic == 1)
00345 {
00346
00347
00348 Array<octave_idx_type> av = algebraic_variables ();
00349
00350 if (av.length () == n)
00351 {
00352 octave_idx_type lid;
00353 if (eiq == 0 || eiq == 2)
00354 lid = 40;
00355 else if (eiq == 1 || eiq == 3)
00356 lid = 40 + n;
00357 else
00358 abort ();
00359
00360 for (octave_idx_type i = 0; i < n; i++)
00361 iwork(lid+i) = av(i) ? -1 : 1;
00362 }
00363 else
00364 {
00365 (*current_liboctave_error_handler)
00366 ("daspk: algebraic variables size mismatch");
00367 integration_error = true;
00368 return retval;
00369 }
00370 }
00371 else if (ccic != 2)
00372 {
00373 (*current_liboctave_error_handler)
00374 ("daspk: invalid value for compute consistent initial condition option");
00375 integration_error = true;
00376 return retval;
00377 }
00378
00379 info(10) = ccic;
00380 }
00381
00382 if (eavfet)
00383 {
00384 info(15) = 1;
00385
00386
00387
00388 Array<octave_idx_type> av = algebraic_variables ();
00389
00390 if (av.length () == n)
00391 {
00392 octave_idx_type lid;
00393 if (eiq == 0 || eiq == 2)
00394 lid = 40;
00395 else if (eiq == 1 || eiq == 3)
00396 lid = 40 + n;
00397 else
00398 abort ();
00399
00400 for (octave_idx_type i = 0; i < n; i++)
00401 iwork(lid+i) = av(i) ? -1 : 1;
00402 }
00403 }
00404
00405 if (use_initial_condition_heuristics ())
00406 {
00407 Array<double> ich = initial_condition_heuristics ();
00408
00409 if (ich.length () == 6)
00410 {
00411 iwork(31) = NINTbig (ich(0));
00412 iwork(32) = NINTbig (ich(1));
00413 iwork(33) = NINTbig (ich(2));
00414 iwork(34) = NINTbig (ich(3));
00415
00416 rwork(13) = ich(4);
00417 rwork(14) = ich(5);
00418 }
00419 else
00420 {
00421 (*current_liboctave_error_handler)
00422 ("daspk: invalid initial condition heuristics option");
00423 integration_error = true;
00424 return retval;
00425 }
00426
00427 info(16) = 1;
00428 }
00429
00430 octave_idx_type pici = print_initial_condition_info ();
00431 switch (pici)
00432 {
00433 case 0:
00434 case 1:
00435 case 2:
00436 info(17) = pici;
00437 break;
00438
00439 default:
00440 (*current_liboctave_error_handler)
00441 ("daspk: invalid value for print initial condition info option");
00442 integration_error = true;
00443 return retval;
00444 break;
00445 }
00446
00447 DASPK_options::reset = false;
00448
00449 restart = false;
00450 }
00451
00452 double *px = x.fortran_vec ();
00453 double *pxdot = xdot.fortran_vec ();
00454
00455 octave_idx_type *pinfo = info.fortran_vec ();
00456
00457 double *prel_tol = rel_tol.fortran_vec ();
00458 double *pabs_tol = abs_tol.fortran_vec ();
00459
00460 double *prwork = rwork.fortran_vec ();
00461 octave_idx_type *piwork = iwork.fortran_vec ();
00462
00463 double *dummy = 0;
00464 octave_idx_type *idummy = 0;
00465
00466 F77_XFCN (ddaspk, DDASPK, (ddaspk_f, nn, t, px, pxdot, tout, pinfo,
00467 prel_tol, pabs_tol, istate, prwork, lrw,
00468 piwork, liw, dummy, idummy, ddaspk_j,
00469 ddaspk_psol));
00470
00471 switch (istate)
00472 {
00473 case 1:
00474
00475 case 2:
00476
00477 case 3:
00478
00479
00480 case 4:
00481
00482
00483
00484 retval = x;
00485 t = tout;
00486 break;
00487
00488 case -1:
00489 case -2:
00490 case -3:
00491
00492
00493
00494
00495 case -6:
00496
00497 case -7:
00498 case -8:
00499 case -9:
00500
00501 case -10:
00502
00503 case -11:
00504
00505 case -12:
00506 case -13:
00507
00508
00509 case -14:
00510
00511 case -33:
00512
00513
00514
00515 integration_error = true;
00516 break;
00517
00518 default:
00519 integration_error = true;
00520 (*current_liboctave_error_handler)
00521 ("unrecognized value of istate (= %d) returned from ddaspk",
00522 istate);
00523 break;
00524 }
00525
00526 return retval;
00527 }
00528
00529 Matrix
00530 DASPK::do_integrate (const ColumnVector& tout)
00531 {
00532 Matrix dummy;
00533 return integrate (tout, dummy);
00534 }
00535
00536 Matrix
00537 DASPK::integrate (const ColumnVector& tout, Matrix& xdot_out)
00538 {
00539 Matrix retval;
00540
00541 octave_idx_type n_out = tout.capacity ();
00542 octave_idx_type n = size ();
00543
00544 if (n_out > 0 && n > 0)
00545 {
00546 retval.resize (n_out, n);
00547 xdot_out.resize (n_out, n);
00548
00549 for (octave_idx_type i = 0; i < n; i++)
00550 {
00551 retval.elem (0, i) = x.elem (i);
00552 xdot_out.elem (0, i) = xdot.elem (i);
00553 }
00554
00555 for (octave_idx_type j = 1; j < n_out; j++)
00556 {
00557 ColumnVector x_next = do_integrate (tout.elem (j));
00558
00559 if (integration_error)
00560 return retval;
00561
00562 for (octave_idx_type i = 0; i < n; i++)
00563 {
00564 retval.elem (j, i) = x_next.elem (i);
00565 xdot_out.elem (j, i) = xdot.elem (i);
00566 }
00567 }
00568 }
00569
00570 return retval;
00571 }
00572
00573 Matrix
00574 DASPK::do_integrate (const ColumnVector& tout, const ColumnVector& tcrit)
00575 {
00576 Matrix dummy;
00577 return integrate (tout, dummy, tcrit);
00578 }
00579
00580 Matrix
00581 DASPK::integrate (const ColumnVector& tout, Matrix& xdot_out,
00582 const ColumnVector& tcrit)
00583 {
00584 Matrix retval;
00585
00586 octave_idx_type n_out = tout.capacity ();
00587 octave_idx_type n = size ();
00588
00589 if (n_out > 0 && n > 0)
00590 {
00591 retval.resize (n_out, n);
00592 xdot_out.resize (n_out, n);
00593
00594 for (octave_idx_type i = 0; i < n; i++)
00595 {
00596 retval.elem (0, i) = x.elem (i);
00597 xdot_out.elem (0, i) = xdot.elem (i);
00598 }
00599
00600 octave_idx_type n_crit = tcrit.capacity ();
00601
00602 if (n_crit > 0)
00603 {
00604 octave_idx_type i_crit = 0;
00605 octave_idx_type i_out = 1;
00606 double next_crit = tcrit.elem (0);
00607 double next_out;
00608 while (i_out < n_out)
00609 {
00610 bool do_restart = false;
00611
00612 next_out = tout.elem (i_out);
00613 if (i_crit < n_crit)
00614 next_crit = tcrit.elem (i_crit);
00615
00616 bool save_output;
00617 double t_out;
00618
00619 if (next_crit == next_out)
00620 {
00621 set_stop_time (next_crit);
00622 t_out = next_out;
00623 save_output = true;
00624 i_out++;
00625 i_crit++;
00626 do_restart = true;
00627 }
00628 else if (next_crit < next_out)
00629 {
00630 if (i_crit < n_crit)
00631 {
00632 set_stop_time (next_crit);
00633 t_out = next_crit;
00634 save_output = false;
00635 i_crit++;
00636 do_restart = true;
00637 }
00638 else
00639 {
00640 clear_stop_time ();
00641 t_out = next_out;
00642 save_output = true;
00643 i_out++;
00644 }
00645 }
00646 else
00647 {
00648 set_stop_time (next_crit);
00649 t_out = next_out;
00650 save_output = true;
00651 i_out++;
00652 }
00653
00654 ColumnVector x_next = do_integrate (t_out);
00655
00656 if (integration_error)
00657 return retval;
00658
00659 if (save_output)
00660 {
00661 for (octave_idx_type i = 0; i < n; i++)
00662 {
00663 retval.elem (i_out-1, i) = x_next.elem (i);
00664 xdot_out.elem (i_out-1, i) = xdot.elem (i);
00665 }
00666 }
00667
00668 if (do_restart)
00669 force_restart ();
00670 }
00671 }
00672 else
00673 {
00674 retval = integrate (tout, xdot_out);
00675
00676 if (integration_error)
00677 return retval;
00678 }
00679 }
00680
00681 return retval;
00682 }
00683
00684 std::string
00685 DASPK::error_message (void) const
00686 {
00687 std::string retval;
00688
00689 std::ostringstream buf;
00690 buf << t;
00691 std::string t_curr = buf.str ();
00692
00693 switch (istate)
00694 {
00695 case 1:
00696 retval = "a step was successfully taken in intermediate-output mode.";
00697 break;
00698
00699 case 2:
00700 retval = "integration completed by stepping exactly to TOUT";
00701 break;
00702
00703 case 3:
00704 retval = "integration to tout completed by stepping past TOUT";
00705 break;
00706
00707 case 4:
00708 retval = "initial condition calculation completed successfully";
00709 break;
00710
00711 case -1:
00712 retval = std::string ("a large amount of work has been expended (t =")
00713 + t_curr + ")";
00714 break;
00715
00716 case -2:
00717 retval = "the error tolerances are too stringent";
00718 break;
00719
00720 case -3:
00721 retval = std::string ("error weight became zero during problem. (t = ")
00722 + t_curr
00723 + "; solution component i vanished, and atol or atol(i) == 0)";
00724 break;
00725
00726 case -6:
00727 retval = std::string ("repeated error test failures on the last attempted step (t = ")
00728 + t_curr + ")";
00729 break;
00730
00731 case -7:
00732 retval = std::string ("the corrector could not converge (t = ")
00733 + t_curr + ")";
00734 break;
00735
00736 case -8:
00737 retval = std::string ("the matrix of partial derivatives is singular (t = ")
00738 + t_curr + ")";
00739 break;
00740
00741 case -9:
00742 retval = std::string ("the corrector could not converge (t = ")
00743 + t_curr + "; repeated test failures)";
00744 break;
00745
00746 case -10:
00747 retval = std::string ("corrector could not converge because IRES was -1 (t = ")
00748 + t_curr + ")";
00749 break;
00750
00751 case -11:
00752 retval = std::string ("return requested in user-supplied function (t = ")
00753 + t_curr + ")";
00754 break;
00755
00756 case -12:
00757 retval = "failed to compute consistent initial conditions";
00758 break;
00759
00760 case -13:
00761 retval = std::string ("unrecoverable error encountered inside user's PSOL function (t = ")
00762 + t_curr + ")";
00763 break;
00764
00765 case -14:
00766 retval = std::string ("the Krylov linear system solver failed to converge (t = ")
00767 + t_curr + ")";
00768 break;
00769
00770 case -33:
00771 retval = "unrecoverable error (see printed message)";
00772 break;
00773
00774 default:
00775 retval = "unknown error state";
00776 break;
00777 }
00778
00779 return retval;
00780 }