DASSL.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 1993-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 "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   // FIXME -- would be nice to avoid copying the data.
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   // FIXME -- would be nice to avoid copying the data.
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       // DAEFunc
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       // DASSL_options
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: // A step was successfully taken in intermediate-output
00298             // mode. The code has not yet reached TOUT.
00299     case 2: // The integration to TSTOP was successfully completed
00300             // (T=TSTOP) by stepping exactly to TSTOP.
00301     case 3: // The integration to TOUT was successfully completed
00302             // (T=TOUT) by stepping past TOUT.  Y(*) is obtained by
00303             // interpolation.  YPRIME(*) is obtained by interpolation.
00304       retval = x;
00305       t = tout;
00306       break;
00307 
00308     case -1: // A large amount of work has been expended.  (~500 steps).
00309     case -2: // The error tolerances are too stringent.
00310     case -3: // The local error test cannot be satisfied because you
00311              // specified a zero component in ATOL and the
00312              // corresponding computed solution component is zero.
00313              // Thus, a pure relative error test is impossible for
00314              // this component.
00315     case -6: // DDASSL had repeated error test failures on the last
00316              // attempted step.
00317     case -7: // The corrector could not converge.
00318     case -8: // The matrix of partial derivatives is singular.
00319     case -9: // The corrector could not converge.  There were repeated
00320              // error test failures in this step.
00321     case -10: // The corrector could not converge because IRES was
00322               // equal to minus one.
00323     case -11: // IRES equal to -2 was encountered and control is being
00324               // returned to the calling program.
00325     case -12: // DDASSL failed to compute the initial YPRIME.
00326     case -33: // The code has encountered trouble from which it cannot
00327               // recover. A message is printed explaining the trouble
00328               // and control is returned to the calling program. For
00329               // example, this occurs when invalid input is detected.
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 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines