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

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