gsl_rkck.h

00001 /*
00002   -------------------------------------------------------------------
00003   
00004   Copyright (C) 2006, 2007, 2008, 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 
00024 #ifndef O2SCL_GSL_RKCK_H
00025 #define O2SCL_GSL_RKCK_H
00026 
00027 #include <o2scl/err_hnd.h>
00028 #include <o2scl/odestep.h>
00029 
00030 #ifndef DOXYGENP
00031 namespace o2scl {
00032 #endif
00033 
00034   /** \brief Cash-Karp embedded Runge-Kutta ODE stepper (GSL)
00035    */
00036   template<class param_t, class func_t, class vec_t=ovector_view, 
00037     class alloc_vec_t=ovector, class alloc_t=ovector_alloc> class gsl_rkck : 
00038   public odestep<param_t,func_t,vec_t> {
00039 
00040   protected:
00041   
00042     /// \name Storage for the intermediate steps
00043     //@{
00044     alloc_vec_t k2, k3, k4, k5, k6, ytmp;
00045     //@}
00046       
00047     /// Size of allocated vectors
00048     size_t ndim;
00049 
00050     /// Memory allocator for objects of type \c alloc_vec_t
00051     alloc_t ao;
00052 
00053     /** \name Storage for the coefficients
00054      */
00055     //@{
00056     double ah[5], b3[2], b4[3], b5[4], b6[5], ec[7];
00057     double b21, c1, c3, c4, c6;
00058     //@}
00059       
00060   public:
00061 
00062     gsl_rkck() {
00063       this->order=5;
00064 
00065       ah[0]=1.0/5.0;
00066       ah[1]=3.0/10.0;
00067       ah[2]=3.0/5.0;
00068       ah[3]=1.0;
00069       ah[4]=7.0/8.0;
00070       b3[0]=3.0/40.0;
00071       b3[1]=9.0/40.0;
00072       b4[0]=3.0/10.0;
00073       b4[1]=-9.0/10.0;
00074       b4[2]=12.0/10.0;
00075       b5[0]=-11.0/54.0;
00076       b5[1]=5.0/2.0;
00077       b5[2]=-70.0/27.0;
00078       b5[3]=35.0/27.0;
00079       b6[0]=1631.0/55296.0;
00080       b6[1]=175.0/512.0;
00081       b6[2]=575.0/13824.0;
00082       b6[3]=44275.0/110592.0;
00083       b6[4]=253.0/4096.0;
00084       ec[0]=0.0;
00085       ec[1]=37.0/378.0-2825.0/27648.0;
00086       ec[2]=0.0;
00087       ec[3]=250.0/621.0-18575.0/48384.0;
00088       ec[4]=125.0/594.0-13525.0/55296.0;
00089       ec[5]=-277.0/14336.0;
00090       ec[6]=512.0/1771.0-1.0/4.0;
00091 
00092       b21=1.0/5.0;
00093       c1=37.0/378.0;
00094       c3=250.0/621.0;
00095       c4=125.0/594.0;
00096       c6=512.0/1771.0;
00097         
00098       ndim=0;
00099     }
00100       
00101     virtual ~gsl_rkck() {
00102       if (ndim!=0) {
00103         ao.free(k2);
00104         ao.free(k3);
00105         ao.free(k4);
00106         ao.free(k5);
00107         ao.free(k6);
00108         ao.free(ytmp);
00109       }
00110     }
00111 
00112     /** 
00113         \brief Perform an integration step
00114 
00115         Given initial value of the n-dimensional function in \c y and
00116         the derivative in \c dydx (which must generally be computed
00117         beforehand) at the point \c x, take a step of size \c h giving
00118         the result in \c yout, the uncertainty in \c yerr, and the new
00119         derivative in \c dydx_out using function \c derivs to
00120         calculate derivatives. The parameters \c yout and \c y and the
00121         parameters \c dydx_out and \c dydx may refer to the same
00122         object.
00123     */
00124     virtual int step(double x, double h, size_t n, vec_t &y, vec_t &dydx, 
00125                      vec_t &yout, vec_t &yerr, vec_t &dydx_out, param_t &pa, 
00126                      func_t &derivs) {
00127         
00128       int ret=0;
00129       size_t i;
00130       
00131       if (ndim!=n) {
00132         if (ndim>0) {
00133           ao.free(k2);
00134           ao.free(k3);
00135           ao.free(k4);
00136           ao.free(k5);
00137           ao.free(k6);
00138           ao.free(ytmp);
00139         }
00140         ao.allocate(k2,n);
00141         ao.allocate(k3,n);
00142         ao.allocate(k4,n);
00143         ao.allocate(k5,n);
00144         ao.allocate(k6,n);
00145         ao.allocate(ytmp,n);
00146 
00147         ndim=n;
00148       }
00149 
00150       for (i=0;i<n;i++) {
00151         ytmp[i]=y[i]+b21*h*dydx[i];
00152       }
00153         
00154       o2scl::error_update(ret,derivs(x+ah[0]*h,n,ytmp,k2,pa));
00155 
00156       for (i=0;i<n;i++) {
00157         ytmp[i]=y[i]+h*(b3[0]*dydx[i]+b3[1]*k2[i]);
00158       }
00159       
00160       o2scl::error_update(ret,derivs(x+ah[1]*h,n,ytmp,k3,pa));
00161       
00162       for (i=0;i<n;i++) {
00163         ytmp[i]=y[i]+h*(b4[0]*dydx[i]+b4[1]*k2[i]+b4[2]*k3[i]);
00164       }
00165 
00166       o2scl::error_update(ret,derivs(x+ah[2]*h,n,ytmp,k4,pa));
00167 
00168       for (i=0;i<n;i++) {
00169         ytmp[i]=y[i]+h*(b5[0]*dydx[i]+b5[1]*k2[i]+b5[2]*k3[i]+
00170                         b5[3]*k4[i]);
00171       }
00172         
00173       o2scl::error_update(ret,derivs(x+ah[3]*h,n,ytmp,k5,pa));
00174       
00175       for (i=0;i<n;i++) {
00176         ytmp[i]=y[i]+h*(b6[0]*dydx[i]+b6[1]*k2[i]+b6[2]*k3[i]+
00177                         b6[3]*k4[i]+b6[4]*k5[i]);
00178       }
00179       
00180       o2scl::error_update(ret,derivs(x+ah[4]*h,n,ytmp,k6,pa));
00181       
00182       for (i=0;i<n;i++) {
00183         yout[i]=y[i]+h*(c1*dydx[i]+c3*k3[i]+c4*k4[i]+c6*k6[i]);
00184       }
00185       
00186       // We put this before the last function evaluation, in contrast
00187       // to the GSL version, so that the dydx[i] that appears in the
00188       // for loop below isn't modified by the subsequent derivative
00189       // evaluation using dydx_out. (The user could have given the
00190       // same vector for both)
00191       for (i=0;i<n;i++) {
00192         yerr[i]=h*(ec[1]*dydx[i]+ec[3]*k3[i]+ec[4]*k4[i]+ec[5]*k5[i]+
00193                    ec[6]*k6[i]);
00194       }
00195 
00196       o2scl::error_update(ret,derivs(x+h,n,yout,dydx_out,pa));
00197       
00198       return ret;
00199     }
00200     
00201   };
00202   
00203   /** \brief Faster Cash-Karp embedded Runge-Kutta ODE stepper (GSL)
00204 
00205       This a faster version of \ref gsl_rkck, which is a stepper for a
00206       fixed number of ODEs. It ignores the error values returned by
00207       the \c derivs argument. The argument \c n to step() should
00208       always be equal to the template parameter \c N, and the vector
00209       parameters to step must have space allocated for at least \c N
00210       elements. No error checking is performed to ensure that this is
00211       the case.
00212   */
00213   template<size_t N, class param_t, class func_t, class vec_t=ovector_view, 
00214     class alloc_vec_t=ovector, class alloc_t=ovector_alloc> 
00215     class gsl_rkck_fast : 
00216   public odestep<param_t,func_t,vec_t> {
00217     
00218   protected:
00219     
00220     /// \name Storage for the intermediate steps
00221     //@{
00222     alloc_vec_t k2, k3, k4, k5, k6, ytmp;
00223     //@}
00224     
00225     /// Memory allocator for objects of type \c alloc_vec_t
00226     alloc_t ao;
00227 
00228     /** \name Storage for the coefficients
00229      */
00230     //@{
00231     double ah[5], b3[2], b4[3], b5[4], b6[5], ec[7];
00232     double b21, c1, c3, c4, c6;
00233     //@}
00234       
00235   public:
00236 
00237     gsl_rkck_fast() {
00238       this->order=5;
00239 
00240       ah[0]=1.0/5.0;
00241       ah[1]=3.0/10.0;
00242       ah[2]=3.0/5.0;
00243       ah[3]=1.0;
00244       ah[4]=7.0/8.0;
00245       b3[0]=3.0/40.0;
00246       b3[1]=9.0/40.0;
00247       b4[0]=3.0/10.0;
00248       b4[1]=-9.0/10.0;
00249       b4[2]=12.0/10.0;
00250       b5[0]=-11.0/54.0;
00251       b5[1]=5.0/2.0;
00252       b5[2]=-70.0/27.0;
00253       b5[3]=35.0/27.0;
00254       b6[0]=1631.0/55296.0;
00255       b6[1]=175.0/512.0;
00256       b6[2]=575.0/13824.0;
00257       b6[3]=44275.0/110592.0;
00258       b6[4]=253.0/4096.0;
00259       ec[0]=0.0;
00260       ec[1]=37.0/378.0-2825.0/27648.0;
00261       ec[2]=0.0;
00262       ec[3]=250.0/621.0-18575.0/48384.0;
00263       ec[4]=125.0/594.0-13525.0/55296.0;
00264       ec[5]=-277.0/14336.0;
00265       ec[6]=512.0/1771.0-1.0/4.0;
00266 
00267       b21=1.0/5.0;
00268       c1=37.0/378.0;
00269       c3=250.0/621.0;
00270       c4=125.0/594.0;
00271       c6=512.0/1771.0;
00272 
00273       ao.allocate(k2,N);
00274       ao.allocate(k3,N);
00275       ao.allocate(k4,N);
00276       ao.allocate(k5,N);
00277       ao.allocate(k6,N);
00278       ao.allocate(ytmp,N);
00279         
00280     }
00281       
00282     virtual ~gsl_rkck_fast() {
00283 
00284       ao.free(k2);
00285       ao.free(k3);
00286       ao.free(k4);
00287       ao.free(k5);
00288       ao.free(k6);
00289       ao.free(ytmp);
00290     }
00291 
00292     /** 
00293         \brief Perform an integration step
00294 
00295         Given initial value of the n-dimensional function in \c y and
00296         the derivative in \c dydx (which must generally be computed
00297         beforehand) at the point \c x, take a step of size \c h giving
00298         the result in \c yout, the uncertainty in \c yerr, and the new
00299         derivative in \c dydx_out using function \c derivs to
00300         calculate derivatives. The parameters \c yout and \c y and the
00301         parameters \c dydx_out and \c dydx may refer to the same
00302         object.
00303 
00304         \note The value of the parameter \c n should be equal to 
00305         the template parameter \c N.
00306     */
00307     virtual int step(double x, double h, size_t n, vec_t &y, vec_t &dydx, 
00308                      vec_t &yout, vec_t &yerr, vec_t &dydx_out, param_t &pa, 
00309                      func_t &derivs) {
00310       
00311       size_t i;
00312       
00313       for (i=0;i<N;i++) {
00314         ytmp[i]=y[i]+b21*h*dydx[i];
00315       }
00316         
00317       derivs(x+ah[0]*h,N,ytmp,k2,pa);
00318 
00319       for (i=0;i<N;i++) {
00320         ytmp[i]=y[i]+h*(b3[0]*dydx[i]+b3[1]*k2[i]);
00321       }
00322         
00323       derivs(x+ah[1]*h,N,ytmp,k3,pa);
00324 
00325       for (i=0;i<N;i++) {
00326         ytmp[i]=y[i]+h*(b4[0]*dydx[i]+b4[1]*k2[i]+b4[2]*k3[i]);
00327       }
00328 
00329       derivs(x+ah[2]*h,N,ytmp,k4,pa);
00330 
00331       for (i=0;i<N;i++) {
00332         ytmp[i]=y[i]+h*(b5[0]*dydx[i]+b5[1]*k2[i]+b5[2]*k3[i]+
00333                         b5[3]*k4[i]);
00334       }
00335         
00336       derivs(x+ah[3]*h,N,ytmp,k5,pa);
00337 
00338       for (i=0;i<N;i++) {
00339         ytmp[i]=y[i]+h*(b6[0]*dydx[i]+b6[1]*k2[i]+b6[2]*k3[i]+
00340                         b6[3]*k4[i]+b6[4]*k5[i]);
00341       }
00342     
00343       derivs(x+ah[4]*h,N,ytmp,k6,pa);
00344 
00345       for (i=0;i<n;i++) {
00346         yout[i]=y[i]+h*(c1*dydx[i]+c3*k3[i]+c4*k4[i]+c6*k6[i]);
00347       }
00348       
00349       // We put this before the last function evaluation, in contrast
00350       // to the GSL version, so that the dydx[i] that appears in the
00351       // for loop below isn't modified by the subsequent derivative
00352       // evaluation using dydx_out. (The user could have given the
00353       // same vector for both)
00354       for (i=0;i<n;i++) {
00355         yerr[i]=h*(ec[1]*dydx[i]+ec[3]*k3[i]+ec[4]*k4[i]+ec[5]*k5[i]+
00356                    ec[6]*k6[i]);
00357       }
00358       
00359       derivs(x+h,n,yout,dydx_out,pa);
00360       
00361       return 0;
00362     }
00363     
00364   };
00365 
00366 #ifndef DOXYGENP
00367 }
00368 #endif
00369 
00370 #endif

Documentation generated with Doxygen and provided under the GNU Free Documentation License. See License Information for details.

Project hosting provided by SourceForge.net Logo, O2scl Sourceforge Project Page