DASRT.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2002-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 "DASRT.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 (*dasrt_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 (*dasrt_jac_ptr) (const double&, const double*,
00043                                           const double*, double*,
00044                                           const double&, double*,
00045                                           octave_idx_type*);
00046 
00047 typedef octave_idx_type (*dasrt_constr_ptr) (const octave_idx_type&,
00048                                              const double&, const double*,
00049                                              const octave_idx_type&,
00050                                              double*, double*,
00051                                              octave_idx_type*);
00052 
00053 extern "C"
00054 {
00055   F77_RET_T
00056   F77_FUNC (ddasrt, DDASRT) (dasrt_fcn_ptr, const octave_idx_type&,
00057                              double&, double*, double*, const double&,
00058                              octave_idx_type*, const double*,
00059                              const double*, octave_idx_type&, double*,
00060                              const octave_idx_type&, octave_idx_type*,
00061                              const octave_idx_type&, double*,
00062                              octave_idx_type*, dasrt_jac_ptr,
00063                              dasrt_constr_ptr, const octave_idx_type&,
00064                              octave_idx_type*);
00065 }
00066 
00067 static DAEFunc::DAERHSFunc user_fsub;
00068 static DAEFunc::DAEJacFunc user_jsub;
00069 static DAERTFunc::DAERTConstrFunc user_csub;
00070 
00071 static octave_idx_type nn;
00072 
00073 static octave_idx_type
00074 ddasrt_f (const double& t, const double *state, const double *deriv,
00075           double *delta, octave_idx_type& ires, double *, octave_idx_type *)
00076 {
00077   BEGIN_INTERRUPT_WITH_EXCEPTIONS;
00078 
00079   ColumnVector tmp_state (nn);
00080   ColumnVector tmp_deriv (nn);
00081 
00082   for (octave_idx_type i = 0; i < nn; i++)
00083     {
00084       tmp_state(i) = state[i];
00085       tmp_deriv(i) = deriv[i];
00086     }
00087 
00088   ColumnVector tmp_fval = (*user_fsub) (tmp_state, tmp_deriv, t, ires);
00089 
00090   if (tmp_fval.length () == 0)
00091     ires = -2;
00092   else
00093     {
00094       for (octave_idx_type i = 0; i < nn; i++)
00095         delta[i] = tmp_fval(i);
00096     }
00097 
00098   END_INTERRUPT_WITH_EXCEPTIONS;
00099 
00100   return 0;
00101 }
00102 
00103 octave_idx_type
00104 ddasrt_j (const double& time, const double *state, const double *deriv,
00105           double *pd, const double& cj, double *, octave_idx_type *)
00106 {
00107   BEGIN_INTERRUPT_WITH_EXCEPTIONS;
00108 
00109   // FIXME -- would be nice to avoid copying the data.
00110 
00111   ColumnVector tmp_state (nn);
00112   ColumnVector tmp_deriv (nn);
00113 
00114   for (octave_idx_type i = 0; i < nn; i++)
00115     {
00116       tmp_deriv.elem (i) = deriv [i];
00117       tmp_state.elem (i) = state [i];
00118     }
00119 
00120   Matrix tmp_pd = (*user_jsub) (tmp_state, tmp_deriv, time, cj);
00121 
00122   for (octave_idx_type j = 0; j < nn; j++)
00123     for (octave_idx_type i = 0; i < nn; i++)
00124       pd [nn * j + i] = tmp_pd.elem (i, j);
00125 
00126   END_INTERRUPT_WITH_EXCEPTIONS;
00127 
00128   return 0;
00129 }
00130 
00131 static octave_idx_type
00132 ddasrt_g (const octave_idx_type& neq, const double& t, const double *state,
00133           const octave_idx_type& ng, double *gout, double *, octave_idx_type *)
00134 {
00135   BEGIN_INTERRUPT_WITH_EXCEPTIONS;
00136 
00137   octave_idx_type n = neq;
00138 
00139   ColumnVector tmp_state (n);
00140   for (octave_idx_type i = 0; i < n; i++)
00141     tmp_state(i) = state[i];
00142 
00143   ColumnVector tmp_fval = (*user_csub) (tmp_state, t);
00144 
00145   for (octave_idx_type i = 0; i < ng; i++)
00146     gout[i] = tmp_fval(i);
00147 
00148   END_INTERRUPT_WITH_EXCEPTIONS;
00149 
00150   return 0;
00151 }
00152 
00153 void
00154 DASRT::integrate (double tout)
00155 {
00156   DASRT_result retval;
00157 
00158   // I suppose this is the safe thing to do.  If this is the first
00159   // call, or if anything about the problem has changed, we should
00160   // start completely fresh.
00161 
00162   if (! initialized || restart
00163       || DAEFunc::reset || DAERTFunc::reset || DASRT_options::reset)
00164     {
00165       integration_error = false;
00166 
00167       initialized = true;
00168 
00169       info.resize (dim_vector (15, 1));
00170 
00171       for (octave_idx_type i = 0; i < 15; i++)
00172         info(i) = 0;
00173 
00174       octave_idx_type n = size ();
00175 
00176       nn = n;
00177 
00178       // DAERTFunc
00179 
00180       user_csub = DAERTFunc::constraint_function ();
00181 
00182       if (user_csub)
00183         {
00184           ColumnVector tmp = (*user_csub) (x, t);
00185           ng = tmp.length ();
00186         }
00187       else
00188         ng = 0;
00189 
00190       octave_idx_type maxord = maximum_order ();
00191       if (maxord >= 0)
00192         {
00193           if (maxord > 0 && maxord < 6)
00194             {
00195               info(8) = 1;
00196               iwork(2) = maxord;
00197             }
00198           else
00199             {
00200               (*current_liboctave_error_handler)
00201                 ("dassl: invalid value for maximum order");
00202               integration_error = true;
00203               return;
00204             }
00205         }
00206 
00207       liw = 21 + n;
00208       lrw = 50 + 9*n + n*n + 3*ng;
00209 
00210       iwork.resize (dim_vector (liw, 1));
00211       rwork.resize (dim_vector (lrw, 1));
00212 
00213       info(0) = 0;
00214 
00215       if (stop_time_set)
00216         {
00217           info(3) = 1;
00218           rwork(0) = stop_time;
00219         }
00220       else
00221         info(3) = 0;
00222 
00223       restart = false;
00224 
00225       // DAEFunc
00226 
00227       user_fsub = DAEFunc::function ();
00228       user_jsub = DAEFunc::jacobian_function ();
00229 
00230       if (user_fsub)
00231         {
00232           octave_idx_type ires = 0;
00233 
00234           ColumnVector fval = (*user_fsub) (x, xdot, t, ires);
00235 
00236           if (fval.length () != x.length ())
00237             {
00238               (*current_liboctave_error_handler)
00239                 ("dasrt: inconsistent sizes for state and residual vectors");
00240 
00241               integration_error = true;
00242               return;
00243             }
00244         }
00245       else
00246         {
00247           (*current_liboctave_error_handler)
00248             ("dasrt: no user supplied RHS subroutine!");
00249 
00250           integration_error = true;
00251           return;
00252         }
00253 
00254       info(4) = user_jsub ? 1 : 0;
00255 
00256       DAEFunc::reset = false;
00257 
00258       jroot.resize (dim_vector (ng, 1), 1);
00259 
00260       DAERTFunc::reset = false;
00261 
00262       // DASRT_options
00263 
00264       double mss = maximum_step_size ();
00265       if (mss >= 0.0)
00266         {
00267           rwork(1) = mss;
00268           info(6) = 1;
00269         }
00270       else
00271         info(6) = 0;
00272 
00273       double iss = initial_step_size ();
00274       if (iss >= 0.0)
00275         {
00276           rwork(2) = iss;
00277           info(7) = 1;
00278         }
00279       else
00280         info(7) = 0;
00281 
00282       if (step_limit () >= 0)
00283         {
00284           info(11) = 1;
00285           iwork(20) = step_limit ();
00286         }
00287       else
00288         info(11) = 0;
00289 
00290       abs_tol = absolute_tolerance ();
00291       rel_tol = relative_tolerance ();
00292 
00293       octave_idx_type abs_tol_len = abs_tol.length ();
00294       octave_idx_type rel_tol_len = rel_tol.length ();
00295 
00296       if (abs_tol_len == 1 && rel_tol_len == 1)
00297         {
00298           info.elem (1) = 0;
00299         }
00300       else if (abs_tol_len == n && rel_tol_len == n)
00301         {
00302           info.elem (1) = 1;
00303         }
00304       else
00305         {
00306           (*current_liboctave_error_handler)
00307             ("dasrt: inconsistent sizes for tolerance arrays");
00308 
00309           integration_error = true;
00310           return;
00311         }
00312 
00313       DASRT_options::reset = false;
00314     }
00315 
00316   double *px = x.fortran_vec ();
00317   double *pxdot = xdot.fortran_vec ();
00318 
00319   octave_idx_type *pinfo = info.fortran_vec ();
00320 
00321   double *prel_tol = rel_tol.fortran_vec ();
00322   double *pabs_tol = abs_tol.fortran_vec ();
00323 
00324   double *prwork = rwork.fortran_vec ();
00325   octave_idx_type *piwork = iwork.fortran_vec ();
00326 
00327   octave_idx_type *pjroot = jroot.fortran_vec ();
00328 
00329   double *dummy = 0;
00330   octave_idx_type *idummy = 0;
00331 
00332   F77_XFCN (ddasrt, DDASRT, (ddasrt_f, nn, t, px, pxdot, tout, pinfo,
00333                              prel_tol, pabs_tol, istate, prwork, lrw,
00334                              piwork, liw, dummy, idummy, ddasrt_j,
00335                              ddasrt_g, ng, pjroot));
00336 
00337   switch (istate)
00338     {
00339     case 1: // A step was successfully taken in intermediate-output
00340             // mode. The code has not yet reached TOUT.
00341     case 2: // The integration to TOUT was successfully completed
00342             // (T=TOUT) by stepping exactly to TOUT.
00343     case 3: // The integration to TOUT was successfully completed
00344             // (T=TOUT) by stepping past TOUT.  Y(*) is obtained by
00345             // interpolation.  YPRIME(*) is obtained by interpolation.
00346       t = tout;
00347       break;
00348 
00349     case 4: //  The integration was successfully completed
00350             // by finding one or more roots of G at T.
00351       break;
00352 
00353     case -1: // A large amount of work has been expended.
00354     case -2: // The error tolerances are too stringent.
00355     case -3: // The local error test cannot be satisfied because you
00356              // specified a zero component in ATOL and the
00357              // corresponding computed solution component is zero.
00358              // Thus, a pure relative error test is impossible for
00359              // this component.
00360     case -6: // DDASRT had repeated error test failures on the last
00361              // attempted step.
00362     case -7: // The corrector could not converge.
00363     case -8: // The matrix of partial derivatives is singular.
00364     case -9: // The corrector could not converge.  There were repeated
00365              // error test failures in this step.
00366     case -10: // The corrector could not converge because IRES was
00367               // equal to minus one.
00368     case -11: // IRES equal to -2 was encountered and control is being
00369               // returned to the calling program.
00370     case -12: // DASSL failed to compute the initial YPRIME.
00371     case -33: // The code has encountered trouble from which it cannot
00372               // recover. A message is printed explaining the trouble
00373               // and control is returned to the calling program. For
00374               // example, this occurs when invalid input is detected.
00375       integration_error = true;
00376       break;
00377 
00378     default:
00379       integration_error = true;
00380       (*current_liboctave_error_handler)
00381         ("unrecognized value of istate (= %d) returned from ddasrt",
00382          istate);
00383       break;
00384     }
00385 }
00386 
00387 DASRT_result
00388 DASRT::integrate (const ColumnVector& tout)
00389 {
00390   DASRT_result retval;
00391 
00392   Matrix x_out;
00393   Matrix xdot_out;
00394   ColumnVector t_out = tout;
00395 
00396   octave_idx_type n_out = tout.capacity ();
00397   octave_idx_type n = size ();
00398 
00399   if (n_out > 0 && n > 0)
00400     {
00401       x_out.resize (n_out, n);
00402       xdot_out.resize (n_out, n);
00403 
00404       for (octave_idx_type i = 0; i < n; i++)
00405         {
00406           x_out(0,i) = x(i);
00407           xdot_out(0,i) = xdot(i);
00408         }
00409 
00410       for (octave_idx_type j = 1; j < n_out; j++)
00411         {
00412           integrate (tout(j));
00413 
00414           if (integration_error)
00415             {
00416               retval = DASRT_result (x_out, xdot_out, t_out);
00417               return retval;
00418             }
00419 
00420           if (istate == 4)
00421             t_out(j) = t;
00422           else
00423             t_out(j) = tout(j);
00424 
00425           for (octave_idx_type i = 0; i < n; i++)
00426             {
00427               x_out(j,i) = x(i);
00428               xdot_out(j,i) = xdot(i);
00429             }
00430 
00431           if (istate == 4)
00432             {
00433               x_out.resize (j+1, n);
00434               xdot_out.resize (j+1, n);
00435               t_out.resize (j+1);
00436               break;
00437             }
00438         }
00439     }
00440 
00441   retval = DASRT_result (x_out, xdot_out, t_out);
00442 
00443   return retval;
00444 }
00445 
00446 DASRT_result
00447 DASRT::integrate (const ColumnVector& tout, const ColumnVector& tcrit)
00448 {
00449   DASRT_result retval;
00450 
00451   Matrix x_out;
00452   Matrix xdot_out;
00453   ColumnVector t_outs = tout;
00454 
00455   octave_idx_type n_out = tout.capacity ();
00456   octave_idx_type n = size ();
00457 
00458   if (n_out > 0 && n > 0)
00459     {
00460       x_out.resize (n_out, n);
00461       xdot_out.resize (n_out, n);
00462 
00463       octave_idx_type n_crit = tcrit.capacity ();
00464 
00465       if (n_crit > 0)
00466         {
00467           octave_idx_type i_crit = 0;
00468           octave_idx_type i_out = 1;
00469           double next_crit = tcrit(0);
00470           double next_out;
00471           while (i_out < n_out)
00472             {
00473               bool do_restart = false;
00474 
00475               next_out = tout(i_out);
00476               if (i_crit < n_crit)
00477                 next_crit = tcrit(i_crit);
00478 
00479               octave_idx_type save_output;
00480               double t_out;
00481 
00482               if (next_crit == next_out)
00483                 {
00484                   set_stop_time (next_crit);
00485                   t_out = next_out;
00486                   save_output = 1;
00487                   i_out++;
00488                   i_crit++;
00489                   do_restart = true;
00490                 }
00491               else if (next_crit < next_out)
00492                 {
00493                   if (i_crit < n_crit)
00494                     {
00495                       set_stop_time (next_crit);
00496                       t_out = next_crit;
00497                       save_output = 0;
00498                       i_crit++;
00499                       do_restart = true;
00500                     }
00501                   else
00502                     {
00503                       clear_stop_time ();
00504                       t_out = next_out;
00505                       save_output = 1;
00506                       i_out++;
00507                     }
00508                 }
00509               else
00510                 {
00511                   set_stop_time (next_crit);
00512                   t_out = next_out;
00513                   save_output = 1;
00514                   i_out++;
00515                 }
00516 
00517               integrate (t_out);
00518 
00519               if (integration_error)
00520                 {
00521                   retval = DASRT_result (x_out, xdot_out, t_outs);
00522                   return retval;
00523                 }
00524 
00525               if (istate == 4)
00526                 t_out = t;
00527 
00528               if (save_output)
00529                 {
00530                   for (octave_idx_type i = 0; i < n; i++)
00531                     {
00532                       x_out(i_out-1,i) = x(i);
00533                       xdot_out(i_out-1,i) = xdot(i);
00534                     }
00535 
00536                   t_outs(i_out-1) = t_out;
00537 
00538                   if (istate == 4)
00539                     {
00540                       x_out.resize (i_out, n);
00541                       xdot_out.resize (i_out, n);
00542                       t_outs.resize (i_out);
00543                       i_out = n_out;
00544                     }
00545                 }
00546 
00547               if (do_restart)
00548                 force_restart ();
00549             }
00550 
00551           retval = DASRT_result (x_out, xdot_out, t_outs);
00552         }
00553       else
00554         {
00555           retval = integrate (tout);
00556 
00557           if (integration_error)
00558             return retval;
00559         }
00560     }
00561 
00562   return retval;
00563 }
00564 
00565 std::string
00566 DASRT::error_message (void) const
00567 {
00568   std::string retval;
00569 
00570   std::ostringstream buf;
00571   buf << t;
00572   std::string t_curr = buf.str ();
00573 
00574   switch (istate)
00575     {
00576     case 1:
00577       retval = "a step was successfully taken in intermediate-output mode.";
00578       break;
00579 
00580     case 2:
00581       retval = "integration completed by stepping exactly to TOUT";
00582       break;
00583 
00584     case 3:
00585       retval = "integration to tout completed by stepping past TOUT";
00586       break;
00587 
00588     case 4:
00589       retval = "integration completed by finding one or more roots of G at T";
00590       break;
00591 
00592     case -1:
00593       retval = std::string ("a large amount of work has been expended (t =")
00594         + t_curr + ")";
00595       break;
00596 
00597     case -2:
00598       retval = "the error tolerances are too stringent";
00599       break;
00600 
00601     case -3:
00602       retval = std::string ("error weight became zero during problem. (t = ")
00603         + t_curr
00604         + "; solution component i vanished, and atol or atol(i) == 0)";
00605       break;
00606 
00607     case -6:
00608       retval = std::string ("repeated error test failures on the last attempted step (t = ")
00609         + t_curr + ")";
00610       break;
00611 
00612     case -7:
00613       retval = std::string ("the corrector could not converge (t = ")
00614         + t_curr + ")";
00615       break;
00616 
00617     case -8:
00618       retval = std::string ("the matrix of partial derivatives is singular (t = ")
00619         + t_curr + ")";
00620       break;
00621 
00622     case -9:
00623       retval = std::string ("the corrector could not converge (t = ")
00624         + t_curr + "; repeated test failures)";
00625       break;
00626 
00627     case -10:
00628       retval = std::string ("corrector could not converge because IRES was -1 (t = ")
00629         + t_curr + ")";
00630       break;
00631 
00632     case -11:
00633       retval = std::string ("return requested in user-supplied function (t = ")
00634         + t_curr + ")";
00635       break;
00636 
00637     case -12:
00638       retval = "failed to compute consistent initial conditions";
00639       break;
00640 
00641     case -33:
00642       retval = "unrecoverable error (see printed message)";
00643       break;
00644 
00645     default:
00646       retval = "unknown error state";
00647       break;
00648     }
00649 
00650   return retval;
00651 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines