gsl_rkck.h

00001 /*
00002   -------------------------------------------------------------------
00003   
00004   Copyright (C) 2006, 2007, 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         yerr[i]=h*(ec[1]*dydx[i]+ec[3]*k3[i]+ec[4]*k4[i]+ec[5]*k5[i]+
00184                    ec[6]*k6[i]);
00185       }
00186 
00187       for (i=0;i<n;i++) {
00188         dydx_out[i]=c1*dydx[i]+c3*k3[i]+c4*k4[i]+c6*k6[i];
00189         
00190         yout[i]=y[i]+h*dydx_out[i];
00191       }
00192       
00193       return ret;
00194     }
00195     
00196   };
00197   
00198   /** \brief Faster Cash-Karp embedded Runge-Kutta ODE stepper (GSL)
00199 
00200       This a faster version of \ref gsl_rkck, which is a stepper for a
00201       fixed number of ODEs. It ignores the error values returned by
00202       the \c derivs argument. The argument \c n to step() should
00203       always be equal to the template parameter \c N, and the vector
00204       parameters to step must have space allocated for at least \c N
00205       elements. No error checking is performed to ensure that this is
00206       the case.
00207   */
00208   template<size_t N, class param_t, class func_t, class vec_t=ovector_view, 
00209     class alloc_vec_t=ovector, class alloc_t=ovector_alloc> 
00210     class gsl_rkck_fast : 
00211   public odestep<param_t,func_t,vec_t> {
00212     
00213   protected:
00214     
00215     /// \name Storage for the intermediate steps
00216     //@{
00217     alloc_vec_t k2, k3, k4, k5, k6, ytmp;
00218     //@}
00219     
00220     /// Memory allocator for objects of type \c alloc_vec_t
00221     alloc_t ao;
00222 
00223     /** \name Storage for the coefficients
00224      */
00225     //@{
00226     double ah[5], b3[2], b4[3], b5[4], b6[5], ec[7];
00227     double b21, c1, c3, c4, c6;
00228     //@}
00229       
00230   public:
00231 
00232     gsl_rkck_fast() {
00233       this->order=5;
00234 
00235       ah[0]=1.0/5.0;
00236       ah[1]=3.0/10.0;
00237       ah[2]=3.0/5.0;
00238       ah[3]=1.0;
00239       ah[4]=7.0/8.0;
00240       b3[0]=3.0/40.0;
00241       b3[1]=9.0/40.0;
00242       b4[0]=3.0/10.0;
00243       b4[1]=-9.0/10.0;
00244       b4[2]=12.0/10.0;
00245       b5[0]=-11.0/54.0;
00246       b5[1]=5.0/2.0;
00247       b5[2]=-70.0/27.0;
00248       b5[3]=35.0/27.0;
00249       b6[0]=1631.0/55296.0;
00250       b6[1]=175.0/512.0;
00251       b6[2]=575.0/13824.0;
00252       b6[3]=44275.0/110592.0;
00253       b6[4]=253.0/4096.0;
00254       ec[0]=0.0;
00255       ec[1]=37.0/378.0-2825.0/27648.0;
00256       ec[2]=0.0;
00257       ec[3]=250.0/621.0-18575.0/48384.0;
00258       ec[4]=125.0/594.0-13525.0/55296.0;
00259       ec[5]=-277.0/14336.0;
00260       ec[6]=512.0/1771.0-1.0/4.0;
00261 
00262       b21=1.0/5.0;
00263       c1=37.0/378.0;
00264       c3=250.0/621.0;
00265       c4=125.0/594.0;
00266       c6=512.0/1771.0;
00267 
00268       ao.allocate(k2,N);
00269       ao.allocate(k3,N);
00270       ao.allocate(k4,N);
00271       ao.allocate(k5,N);
00272       ao.allocate(k6,N);
00273       ao.allocate(ytmp,N);
00274         
00275     }
00276       
00277     virtual ~gsl_rkck_fast() {
00278 
00279       ao.free(k2);
00280       ao.free(k3);
00281       ao.free(k4);
00282       ao.free(k5);
00283       ao.free(k6);
00284       ao.free(ytmp);
00285     }
00286 
00287     /** 
00288         \brief Perform an integration step
00289 
00290         Given initial value of the n-dimensional function in \c y and
00291         the derivative in \c dydx (which must generally be computed
00292         beforehand) at the point \c x, take a step of size \c h giving
00293         the result in \c yout, the uncertainty in \c yerr, and the new
00294         derivative in \c dydx_out using function \c derivs to
00295         calculate derivatives. The parameters \c yout and \c y and the
00296         parameters \c dydx_out and \c dydx may refer to the same
00297         object.
00298 
00299         \note The value of the parameter \c n should be equal to 
00300         the template parameter \c N.
00301     */
00302     virtual int step(double x, double h, size_t n, vec_t &y, vec_t &dydx, 
00303                      vec_t &yout, vec_t &yerr, vec_t &dydx_out, param_t &pa, 
00304                      func_t &derivs) {
00305       
00306       size_t i;
00307       
00308       for (i=0;i<N;i++) {
00309         ytmp[i]=y[i]+b21*h*dydx[i];
00310       }
00311         
00312       derivs(x+ah[0]*h,N,ytmp,k2,pa);
00313 
00314       for (i=0;i<N;i++) {
00315         ytmp[i]=y[i]+h*(b3[0]*dydx[i]+b3[1]*k2[i]);
00316       }
00317         
00318       derivs(x+ah[1]*h,N,ytmp,k3,pa);
00319 
00320       for (i=0;i<N;i++) {
00321         ytmp[i]=y[i]+h*(b4[0]*dydx[i]+b4[1]*k2[i]+b4[2]*k3[i]);
00322       }
00323 
00324       derivs(x+ah[2]*h,N,ytmp,k4,pa);
00325 
00326       for (i=0;i<N;i++) {
00327         ytmp[i]=y[i]+h*(b5[0]*dydx[i]+b5[1]*k2[i]+b5[2]*k3[i]+
00328                         b5[3]*k4[i]);
00329       }
00330         
00331       derivs(x+ah[3]*h,N,ytmp,k5,pa);
00332 
00333       for (i=0;i<N;i++) {
00334         ytmp[i]=y[i]+h*(b6[0]*dydx[i]+b6[1]*k2[i]+b6[2]*k3[i]+
00335                         b6[3]*k4[i]+b6[4]*k5[i]);
00336       }
00337     
00338       derivs(x+ah[4]*h,N,ytmp,k6,pa);
00339 
00340       for (i=0;i<N;i++) {
00341         yerr[i]=h*(ec[1]*dydx[i]+ec[3]*k3[i]+ec[4]*k4[i]+ec[5]*k5[i]+
00342                    ec[6]*k6[i]);
00343       }
00344 
00345       for (i=0;i<N;i++) {
00346         dydx_out[i]=c1*dydx[i]+c3*k3[i]+c4*k4[i]+c6*k6[i];
00347         yout[i]=y[i]+h*dydx_out[i];
00348       }
00349 
00350       return 0;
00351     }
00352     
00353   };
00354 
00355 #ifndef DOXYGENP
00356 }
00357 #endif
00358 
00359 #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