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