Object-oriented Scientific Computing Library: Version 0.910
gsl_rkf45.h
00001 /*
00002   -------------------------------------------------------------------
00003   
00004   Copyright (C) 2006-2012, Andrew W. Steiner
00005   
00006   This file is part of O2scl.
00007   
00008   O2scl is free software; you can redistribute it and/or modify
00009   it under the terms of the GNU General Public License as published by
00010   the Free Software Foundation; either version 3 of the License, or
00011   (at your option) any later version.
00012   
00013   O2scl is distributed in the hope that it will be useful,
00014   but WITHOUT ANY WARRANTY; without even the implied warranty of
00015   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016   GNU General Public License for more details.
00017   
00018   You should have received a copy of the GNU General Public License
00019   along with O2scl. If not, see <http://www.gnu.org/licenses/>.
00020 
00021   -------------------------------------------------------------------
00022 */
00023 /* ode-initval/rkf45.c
00024  * 
00025  * Copyright (C) 2001, 2004, 2007 Brian Gough
00026  * 
00027  * This program is free software; you can redistribute it and/or modify
00028  * it under the terms of the GNU General Public License as published by
00029  * the Free Software Foundation; either version 3 of the License, or (at
00030  * your option) any later version.
00031  * 
00032  * This program is distributed in the hope that it will be useful, but
00033  * WITHOUT ANY WARRANTY; without even the implied warranty of
00034  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00035  * General Public License for more details.
00036  * 
00037  * You should have received a copy of the GNU General Public License
00038  * along with this program; if not, write to the Free Software
00039  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
00040  * 02110-1301, USA.
00041  */
00042 #ifndef O2SCL_GSL_RKF45_H
00043 #define O2SCL_GSL_RKF45_H
00044 
00045 #include <o2scl/err_hnd.h>
00046 #include <o2scl/ode_funct.h>
00047 #include <o2scl/ode_step.h>
00048 
00049 #ifndef DOXYGENP
00050 namespace o2scl {
00051 #endif
00052 
00053   /** \brief Runge-Kutta-Fehlberg embedded Runge-Kutta ODE stepper (GSL)
00054 
00055       Based on \ref Hairer00 .
00056 
00057       \todo Check this because it may not give exact dydt_out.
00058    */
00059   template<class func_t=ode_funct<>, class vec_t=ovector_base, 
00060     class alloc_vec_t=ovector, class alloc_t=ovector_alloc> class gsl_rkf45 : 
00061   public ode_step<func_t,vec_t> {
00062     
00063   protected:
00064   
00065   /// \name Storage for the intermediate steps
00066   //@{
00067   alloc_vec_t k2, k3, k4, k5, k6, ytmp;
00068   //@}
00069   
00070   /// Size of allocated vectors
00071   size_t ndim;
00072   
00073   /// Memory allocator for objects of type \c alloc_vec_t
00074   alloc_t ao;
00075   
00076   /** \name Storage for the coefficients
00077    */
00078   //@{
00079   double ah[5], b3[2], b4[3], b5[4], b6[5];
00080   double c1, c3, c4, c5, c6;
00081   double ec[7];
00082   //@}
00083   
00084   public:
00085   
00086   gsl_rkf45() {
00087     this->order=5;
00088     
00089     ah[0]=1.0/4.0;
00090     ah[1]=3.0/8.0;
00091     ah[2]=12.0/13.0;
00092     ah[3]=1.0;
00093     ah[4]=1.0/2.0;
00094 
00095     b3[0]=3.0/32.0;
00096     b3[1]=9.0/32.0;
00097 
00098     b4[0]=1932.0/2197.0;
00099     b4[1]=-7200.0/2197.0;
00100     b4[2]=7296.0/2197.0;
00101 
00102     b5[0]=8341.0/4104.0;
00103     b5[1]=-32832.0/4104.0;
00104     b5[2]=29440.0/4104.0;
00105     b5[3]=-845.0/4104.0;
00106 
00107     b6[0]=-6080.0/20520.0;
00108     b6[1]=41040.0/20520.0;
00109     b6[2]=-28352.0/20520.0;
00110     b6[3]=9295.0/20520.0;
00111     b6[4]=-5643.0/20520.0;
00112 
00113     c1=902880.0/7618050.0;
00114     c3=3953664.0/7618050.0;
00115     c4=3855735.0/7618050.0;
00116     c5=-1371249.0/7618050.0;
00117     c6=277020.0/7618050.0;
00118 
00119     ec[0]=0.0;
00120     ec[1]=1.0/360.0;
00121     ec[2]=0.0;
00122     ec[3]=-128.0/4275.0;
00123     ec[4]=-2197.0/75240.0;
00124     ec[5]=1.0/50.0;
00125     ec[6]=2.0/55.0;
00126 
00127     ndim=0;
00128   }
00129       
00130   virtual ~gsl_rkf45() {
00131     if (ndim!=0) {
00132       ao.free(k2);
00133       ao.free(k3);
00134       ao.free(k4);
00135       ao.free(k5);
00136       ao.free(k6);
00137       ao.free(ytmp);
00138     }
00139   }
00140 
00141   /** \brief Perform an integration step
00142 
00143       Given initial value of the n-dimensional function in \c y and
00144       the derivative in \c dydx (which must be computed beforehand) at
00145       the point \c x, take a step of size \c h giving the result in \c
00146       yout, the uncertainty in \c yerr, and the new derivative in \c
00147       dydx_out using function \c derivs to calculate derivatives. The
00148       parameters \c yout and \c y and the parameters \c dydx_out and
00149       \c dydx may refer to the same object.
00150 
00151       If \c derivs always returns zero, then this function will
00152       also return zero. If not, <tt>step()</tt> will return the first
00153       non-zero value which was obtained in a call to \c derivs .
00154       The error handler is never called.
00155   */
00156   virtual int step(double x, double h, size_t n, vec_t &y, vec_t &dydx, 
00157                    vec_t &yout, vec_t &yerr, vec_t &dydx_out, 
00158                    func_t &derivs) {
00159     
00160     int ret=0;
00161     size_t i;
00162       
00163     if (ndim!=n) {
00164       if (ndim>0) {
00165         ao.free(k2);
00166         ao.free(k3);
00167         ao.free(k4);
00168         ao.free(k5);
00169         ao.free(k6);
00170         ao.free(ytmp);
00171       }
00172       ao.allocate(k2,n);
00173       ao.allocate(k3,n);
00174       ao.allocate(k4,n);
00175       ao.allocate(k5,n);
00176       ao.allocate(k6,n);
00177       ao.allocate(ytmp,n);
00178 
00179       ndim=n;
00180     }
00181 
00182     // k1 step
00183     for (i=0;i<n;i++) {
00184       ytmp[i]=y[i]+ah[0]*h*dydx[i];
00185     }
00186 
00187     // k2 step
00188     o2scl::error_update(ret,derivs(x+ah[0]*h,n,ytmp,k2));
00189 
00190     for (i=0;i<n;i++) {
00191       ytmp[i]=y[i]+h*(b3[0]*dydx[i]+b3[1]*k2[i]);
00192     }
00193       
00194     // k3 step
00195     o2scl::error_update(ret,derivs(x+ah[1]*h,n,ytmp,k3));
00196       
00197     for (i=0;i<n;i++) {
00198       ytmp[i]=y[i]+h*(b4[0]*dydx[i]+b4[1]*k2[i]+b4[2]*k3[i]);
00199     }
00200 
00201     // k4 step
00202     o2scl::error_update(ret,derivs(x+ah[2]*h,n,ytmp,k4));
00203 
00204     for (i=0;i<n;i++) {
00205       ytmp[i]=y[i]+h*(b5[0]*dydx[i]+b5[1]*k2[i]+b5[2]*k3[i]+
00206                       b5[3]*k4[i]);
00207     }
00208         
00209     // k5 step
00210     o2scl::error_update(ret,derivs(x+ah[3]*h,n,ytmp,k5));
00211       
00212     for (i=0;i<n;i++) {
00213       ytmp[i]=y[i]+h*(b6[0]*dydx[i]+b6[1]*k2[i]+b6[2]*k3[i]+
00214                       b6[3]*k4[i]+b6[4]*k5[i]);
00215     }
00216       
00217     // k6 step and final sum
00218     o2scl::error_update(ret,derivs(x+ah[4]*h,n,ytmp,k6));
00219       
00220     for (i=0;i<n;i++) {
00221       yout[i]=y[i]+h*(c1*dydx[i]+c3*k3[i]+c4*k4[i]+c5*k5[i]+c6*k6[i]);
00222     }
00223       
00224     // We put this before the last function evaluation, in contrast
00225     // to the GSL version, so that the dydx[i] that appears in the
00226     // for loop below isn't modified by the subsequent derivative
00227     // evaluation using dydx_out. (The user could have given the
00228     // same vector for both)
00229     for (i=0;i<n;i++) {
00230       yerr[i]=h*(ec[1]*dydx[i]+ec[3]*k3[i]+ec[4]*k4[i]+ec[5]*k5[i]+
00231                  ec[6]*k6[i]);
00232     }
00233 
00234     o2scl::error_update(ret,derivs(x+h,n,yout,dydx_out));
00235       
00236     return ret;
00237   }
00238     
00239   };
00240   
00241   /** \brief Faster Runge-Kutta-Fehlberg embedded Runge-Kutta ODE 
00242       stepper (GSL)
00243 
00244       This a faster version of \ref gsl_rkf45, which is a stepper for a
00245       fixed number of ODEs. It ignores the error values returned by
00246       the \c derivs argument. The argument \c n to step() should
00247       always be equal to the template parameter \c N, and the vector
00248       parameters to step must have space allocated for at least \c N
00249       elements. No error checking is performed to ensure that this is
00250       the case.
00251 
00252       Based on \ref Hairer00 .
00253   */
00254   template<size_t N, class func_t=ode_funct<>, 
00255     class vec_t=ovector_base, class alloc_vec_t=ovector, 
00256     class alloc_t=ovector_alloc> class gsl_rkf45_fast : 
00257   public ode_step<func_t,vec_t> {
00258     
00259   protected:
00260     
00261   /// \name Storage for the intermediate steps
00262   //@{
00263   alloc_vec_t k2, k3, k4, k5, k6, ytmp;
00264   //@}
00265     
00266   /// Memory allocator for objects of type \c alloc_vec_t
00267   alloc_t ao;
00268 
00269   /** \name Storage for the coefficients
00270    */
00271   //@{
00272   double ah[5], b3[2], b4[3], b5[4], b6[5];
00273   double c1, c3, c4, c5, c6;
00274   double ec[7];
00275   //@}
00276       
00277   public:
00278 
00279   gsl_rkf45_fast() {
00280     this->order=5;
00281 
00282     ah[0]=1.0/4.0;
00283     ah[1]=3.0/8.0;
00284     ah[2]=12.0/13.0;
00285     ah[3]=1.0;
00286     ah[4]=1.0/2.0;
00287 
00288     b3[0]=3.0/32.0;
00289     b3[1]=9.0/32.0;
00290 
00291     b4[0]=1932.0/2197.0;
00292     b4[1]=-7200.0/2197.0;
00293     b4[2]=7296.0/2197.0;
00294 
00295     b5[0]=8341.0/4104.0;
00296     b5[1]=-32832.0/4104.0;
00297     b5[2]=29440.0/4104.0;
00298     b5[3]=-845.0/4104.0;
00299 
00300     b6[0]=-6080.0/20520.0;
00301     b6[1]=41040.0/20520.0;
00302     b6[2]=-28352.0/20520.0;
00303     b6[3]=9295.0/20520.0;
00304     b6[4]=-5643.0/20520.0;
00305 
00306     c1=902880.0/7618050.0;
00307     c3=3953664.0/7618050.0;
00308     c4=3855735.0/7618050.0;
00309     c5=-1371249.0/7618050.0;
00310     c6=277020.0/7618050.0;
00311 
00312     ec[0]=0.0;
00313     ec[1]=1.0/360.0;
00314     ec[2]=0.0;
00315     ec[3]=-128.0/4275.0;
00316     ec[4]=-2197.0/75240.0;
00317     ec[5]=1.0/50.0;
00318     ec[6]=2.0/55.0;
00319 
00320     ao.allocate(k2,N);
00321     ao.allocate(k3,N);
00322     ao.allocate(k4,N);
00323     ao.allocate(k5,N);
00324     ao.allocate(k6,N);
00325     ao.allocate(ytmp,N);
00326         
00327   }
00328       
00329   virtual ~gsl_rkf45_fast() {
00330 
00331     ao.free(k2);
00332     ao.free(k3);
00333     ao.free(k4);
00334     ao.free(k5);
00335     ao.free(k6);
00336     ao.free(ytmp);
00337   }
00338 
00339   /** \brief Perform an integration step
00340 
00341       Given initial value of the n-dimensional function in \c y and
00342       the derivative in \c dydx (which must be computed beforehand) at
00343       the point \c x, take a step of size \c h giving the result in \c
00344       yout, the uncertainty in \c yerr, and the new derivative in \c
00345       dydx_out using function \c derivs to calculate derivatives. The
00346       parameters \c yout and \c y and the parameters \c dydx_out and
00347       \c dydx may refer to the same object.
00348 
00349       \note The value of the parameter \c n should be equal to 
00350       the template parameter \c N.
00351   */
00352   virtual int step(double x, double h, size_t n, vec_t &y, vec_t &dydx, 
00353                    vec_t &yout, vec_t &yerr, vec_t &dydx_out, 
00354                    func_t &derivs) {
00355       
00356     size_t i;
00357     
00358     // k1 step
00359     for (i=0;i<N;i++) {
00360       ytmp[i]=y[i]+ah[0]*h*dydx[i];
00361     }
00362         
00363     // k2 step
00364     derivs(x+ah[0]*h,N,ytmp,k2);
00365 
00366     for (i=0;i<N;i++) {
00367       ytmp[i]=y[i]+h*(b3[0]*dydx[i]+b3[1]*k2[i]);
00368     }
00369         
00370     // k3 step
00371     derivs(x+ah[1]*h,N,ytmp,k3);
00372 
00373     for (i=0;i<N;i++) {
00374       ytmp[i]=y[i]+h*(b4[0]*dydx[i]+b4[1]*k2[i]+b4[2]*k3[i]);
00375     }
00376 
00377     // k4 step
00378     derivs(x+ah[2]*h,N,ytmp,k4);
00379 
00380     for (i=0;i<N;i++) {
00381       ytmp[i]=y[i]+h*(b5[0]*dydx[i]+b5[1]*k2[i]+b5[2]*k3[i]+
00382                       b5[3]*k4[i]);
00383     }
00384         
00385     // k5 step
00386     derivs(x+ah[3]*h,N,ytmp,k5);
00387 
00388     for (i=0;i<N;i++) {
00389       ytmp[i]=y[i]+h*(b6[0]*dydx[i]+b6[1]*k2[i]+b6[2]*k3[i]+
00390                       b6[3]*k4[i]+b6[4]*k5[i]);
00391     }
00392     
00393     // k6 step and final sum
00394     derivs(x+ah[4]*h,N,ytmp,k6);
00395 
00396     for (i=0;i<n;i++) {
00397       yout[i]=y[i]+h*(c1*dydx[i]+c3*k3[i]+c4*k4[i]+c5*k5[i]+c6*k6[i]);
00398     }
00399       
00400     // We put this before the last function evaluation, in contrast
00401     // to the GSL version, so that the dydx[i] that appears in the
00402     // for loop below isn't modified by the subsequent derivative
00403     // evaluation using dydx_out. (The user could have given the
00404     // same vector for both)
00405     for (i=0;i<n;i++) {
00406       yerr[i]=h*(ec[1]*dydx[i]+ec[3]*k3[i]+ec[4]*k4[i]+ec[5]*k5[i]+
00407                  ec[6]*k6[i]);
00408     }
00409       
00410     derivs(x+h,n,yout,dydx_out);
00411       
00412     return 0;
00413   }
00414     
00415   };
00416 
00417 #ifndef DOXYGENP
00418 }
00419 #endif
00420 
00421 #endif
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).

Get Object-oriented Scientific Computing
Lib at SourceForge.net. Fast, secure and Free Open Source software
downloads.