DASPK.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 1996-2012 John W. Eaton
00004 
00005 This file is part of Octave.
00006 
00007 Octave is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 3 of the License, or (at your
00010 option) any later version.
00011 
00012 Octave is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Octave; see the file COPYING.  If not, see
00019 <http://www.gnu.org/licenses/>.
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 //NEQ, T, Y, YPRIME, SAVR, WK, CJ, WGHT,
00109 //C                          WP, IWP, B, EPLIN, IER, RPAR, IPAR)
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   // FIXME -- would be nice to avoid copying the data.
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   // FIXME -- should handle all this option stuff just once
00159   // for each new problem.
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       // DAEFunc
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       // DASPK_options
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           // Fall through...
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               // FIXME -- this code is duplicated below.
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           // FIXME -- this code is duplicated above.
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: // A step was successfully taken in intermediate-output
00474             // mode. The code has not yet reached TOUT.
00475     case 2: // The integration to TSTOP was successfully completed
00476             // (T=TSTOP) by stepping exactly to TSTOP.
00477     case 3: // The integration to TOUT was successfully completed
00478             // (T=TOUT) by stepping past TOUT.  Y(*) is obtained by
00479             // interpolation.  YPRIME(*) is obtained by interpolation.
00480     case 4: // The initial condition calculation, with
00481             // INFO(11) > 0, was successful, and INFO(14) = 1.
00482             // No integration steps were taken, and the solution
00483             // is not considered to have been started.
00484       retval = x;
00485       t = tout;
00486       break;
00487 
00488     case -1: // A large amount of work has been expended.  (~500 steps).
00489     case -2: // The error tolerances are too stringent.
00490     case -3: // The local error test cannot be satisfied because you
00491              // specified a zero component in ATOL and the
00492              // corresponding computed solution component is zero.
00493              // Thus, a pure relative error test is impossible for
00494              // this component.
00495     case -6: // DDASPK had repeated error test failures on the last
00496              // attempted step.
00497     case -7: // The corrector could not converge.
00498     case -8: // The matrix of partial derivatives is singular.
00499     case -9: // The corrector could not converge.  There were repeated
00500              // error test failures in this step.
00501     case -10: // The corrector could not converge because IRES was
00502               // equal to minus one.
00503     case -11: // IRES equal to -2 was encountered and control is being
00504               // returned to the calling program.
00505     case -12: // DDASPK failed to compute the initial YPRIME.
00506     case -13: // Unrecoverable error encountered inside user's
00507               // PSOL routine, and control is being returned to
00508               // the calling program.
00509     case -14: // The Krylov linear system solver could not
00510               // achieve convergence.
00511     case -33: // The code has encountered trouble from which it cannot
00512               // recover. A message is printed explaining the trouble
00513               // and control is returned to the calling program. For
00514               // example, this occurs when invalid input is detected.
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 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines