00001 /* 00002 ------------------------------------------------------------------- 00003 00004 Copyright (C) 2006, 2007, 2008, 2009, 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/odestep.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 template<class param_t, class func_t=ode_funct<param_t>, 00058 class vec_t=ovector_base, 00059 class alloc_vec_t=ovector, class alloc_t=ovector_alloc> class gsl_rkf45 : 00060 public odestep<param_t,func_t,vec_t> { 00061 00062 protected: 00063 00064 /// \name Storage for the intermediate steps 00065 //@{ 00066 alloc_vec_t k2, k3, k4, k5, k6, ytmp; 00067 //@} 00068 00069 /// Size of allocated vectors 00070 size_t ndim; 00071 00072 /// Memory allocator for objects of type \c alloc_vec_t 00073 alloc_t ao; 00074 00075 /** \name Storage for the coefficients 00076 */ 00077 //@{ 00078 double ah[5], b3[2], b4[3], b5[4], b6[5]; 00079 double c1, c3, c4, c5, c6; 00080 double ec[7]; 00081 //@} 00082 00083 public: 00084 00085 gsl_rkf45() { 00086 this->order=5; 00087 00088 ah[0]=1.0/4.0; 00089 ah[1]=3.0/8.0; 00090 ah[2]=12.0/13.0; 00091 ah[3]=1.0; 00092 ah[4]=1.0/2.0; 00093 00094 b3[0]=3.0/32.0; 00095 b3[1]=9.0/32.0; 00096 00097 b4[0]=1932.0/2197.0; 00098 b4[1]=-7200.0/2197.0; 00099 b4[2]=7296.0/2197.0; 00100 00101 b5[0]=8341.0/4104.0; 00102 b5[1]=-32832.0/4104.0; 00103 b5[2]=29440.0/4104.0; 00104 b5[3]=-845.0/4104.0; 00105 00106 b6[0]=-6080.0/20520.0; 00107 b6[1]=41040.0/20520.0; 00108 b6[2]=-28352.0/20520.0; 00109 b6[3]=9295.0/20520.0; 00110 b6[4]=-5643.0/20520.0; 00111 00112 c1=902880.0/7618050.0; 00113 c3=3953664.0/7618050.0; 00114 c4=3855735.0/7618050.0; 00115 c5=-1371249.0/7618050.0; 00116 c6=277020.0/7618050.0; 00117 00118 ec[0]=0.0; 00119 ec[1]=1.0/360.0; 00120 ec[2]=0.0; 00121 ec[3]=-128.0/4275.0; 00122 ec[4]=-2197.0/75240.0; 00123 ec[5]=1.0/50.0; 00124 ec[6]=2.0/55.0; 00125 00126 ndim=0; 00127 } 00128 00129 virtual ~gsl_rkf45() { 00130 if (ndim!=0) { 00131 ao.free(k2); 00132 ao.free(k3); 00133 ao.free(k4); 00134 ao.free(k5); 00135 ao.free(k6); 00136 ao.free(ytmp); 00137 } 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 generally be computed 00145 beforehand) at the point \c x, take a step of size \c h giving 00146 the result in \c yout, the uncertainty in \c yerr, and the new 00147 derivative in \c dydx_out using function \c derivs to 00148 calculate derivatives. The parameters \c yout and \c y and the 00149 parameters \c dydx_out and \c dydx may refer to the same 00150 object. 00151 00152 If \c derivs always returns zero, then this function will 00153 also return zero. If not, <tt>step()</tt> will return the first 00154 non-zero value which was obtained in a call to \c derivs . 00155 The error handler is never called. 00156 */ 00157 virtual int step(double x, double h, size_t n, vec_t &y, vec_t &dydx, 00158 vec_t &yout, vec_t &yerr, vec_t &dydx_out, param_t &pa, 00159 func_t &derivs) { 00160 00161 int ret=0; 00162 size_t i; 00163 00164 if (ndim!=n) { 00165 if (ndim>0) { 00166 ao.free(k2); 00167 ao.free(k3); 00168 ao.free(k4); 00169 ao.free(k5); 00170 ao.free(k6); 00171 ao.free(ytmp); 00172 } 00173 ao.allocate(k2,n); 00174 ao.allocate(k3,n); 00175 ao.allocate(k4,n); 00176 ao.allocate(k5,n); 00177 ao.allocate(k6,n); 00178 ao.allocate(ytmp,n); 00179 00180 ndim=n; 00181 } 00182 00183 // k1 step 00184 for (i=0;i<n;i++) { 00185 ytmp[i]=y[i]+ah[0]*h*dydx[i]; 00186 } 00187 00188 // k2 step 00189 o2scl::error_update(ret,derivs(x+ah[0]*h,n,ytmp,k2,pa)); 00190 00191 for (i=0;i<n;i++) { 00192 ytmp[i]=y[i]+h*(b3[0]*dydx[i]+b3[1]*k2[i]); 00193 } 00194 00195 // k3 step 00196 o2scl::error_update(ret,derivs(x+ah[1]*h,n,ytmp,k3,pa)); 00197 00198 for (i=0;i<n;i++) { 00199 ytmp[i]=y[i]+h*(b4[0]*dydx[i]+b4[1]*k2[i]+b4[2]*k3[i]); 00200 } 00201 00202 // k4 step 00203 o2scl::error_update(ret,derivs(x+ah[2]*h,n,ytmp,k4,pa)); 00204 00205 for (i=0;i<n;i++) { 00206 ytmp[i]=y[i]+h*(b5[0]*dydx[i]+b5[1]*k2[i]+b5[2]*k3[i]+ 00207 b5[3]*k4[i]); 00208 } 00209 00210 // k5 step 00211 o2scl::error_update(ret,derivs(x+ah[3]*h,n,ytmp,k5,pa)); 00212 00213 for (i=0;i<n;i++) { 00214 ytmp[i]=y[i]+h*(b6[0]*dydx[i]+b6[1]*k2[i]+b6[2]*k3[i]+ 00215 b6[3]*k4[i]+b6[4]*k5[i]); 00216 } 00217 00218 // k6 step and final sum 00219 o2scl::error_update(ret,derivs(x+ah[4]*h,n,ytmp,k6,pa)); 00220 00221 for (i=0;i<n;i++) { 00222 yout[i]=y[i]+h*(c1*dydx[i]+c3*k3[i]+c4*k4[i]+c5*k5[i]+c6*k6[i]); 00223 } 00224 00225 // We put this before the last function evaluation, in contrast 00226 // to the GSL version, so that the dydx[i] that appears in the 00227 // for loop below isn't modified by the subsequent derivative 00228 // evaluation using dydx_out. (The user could have given the 00229 // same vector for both) 00230 for (i=0;i<n;i++) { 00231 yerr[i]=h*(ec[1]*dydx[i]+ec[3]*k3[i]+ec[4]*k4[i]+ec[5]*k5[i]+ 00232 ec[6]*k6[i]); 00233 } 00234 00235 o2scl::error_update(ret,derivs(x+h,n,yout,dydx_out,pa)); 00236 00237 return ret; 00238 } 00239 00240 }; 00241 00242 /** \brief Faster Runge-Kutta-Fehlberg embedded Runge-Kutta ODE 00243 stepper (GSL) 00244 00245 This a faster version of \ref gsl_rkf45, which is a stepper for a 00246 fixed number of ODEs. It ignores the error values returned by 00247 the \c derivs argument. The argument \c n to step() should 00248 always be equal to the template parameter \c N, and the vector 00249 parameters to step must have space allocated for at least \c N 00250 elements. No error checking is performed to ensure that this is 00251 the case. 00252 00253 Based on \ref Hairer00 . 00254 */ 00255 template<size_t N, class param_t, class func_t=ode_funct<param_t>, 00256 class vec_t=ovector_base, class alloc_vec_t=ovector, 00257 class alloc_t=ovector_alloc> class gsl_rkf45_fast : 00258 public odestep<param_t,func_t,vec_t> { 00259 00260 protected: 00261 00262 /// \name Storage for the intermediate steps 00263 //@{ 00264 alloc_vec_t k2, k3, k4, k5, k6, ytmp; 00265 //@} 00266 00267 /// Memory allocator for objects of type \c alloc_vec_t 00268 alloc_t ao; 00269 00270 /** \name Storage for the coefficients 00271 */ 00272 //@{ 00273 double ah[5], b3[2], b4[3], b5[4], b6[5]; 00274 double c1, c3, c4, c5, c6; 00275 double ec[7]; 00276 //@} 00277 00278 public: 00279 00280 gsl_rkf45_fast() { 00281 this->order=5; 00282 00283 ah[0]=1.0/4.0; 00284 ah[1]=3.0/8.0; 00285 ah[2]=12.0/13.0; 00286 ah[3]=1.0; 00287 ah[4]=1.0/2.0; 00288 00289 b3[0]=3.0/32.0; 00290 b3[1]=9.0/32.0; 00291 00292 b4[0]=1932.0/2197.0; 00293 b4[1]=-7200.0/2197.0; 00294 b4[2]=7296.0/2197.0; 00295 00296 b5[0]=8341.0/4104.0; 00297 b5[1]=-32832.0/4104.0; 00298 b5[2]=29440.0/4104.0; 00299 b5[3]=-845.0/4104.0; 00300 00301 b6[0]=-6080.0/20520.0; 00302 b6[1]=41040.0/20520.0; 00303 b6[2]=-28352.0/20520.0; 00304 b6[3]=9295.0/20520.0; 00305 b6[4]=-5643.0/20520.0; 00306 00307 c1=902880.0/7618050.0; 00308 c3=3953664.0/7618050.0; 00309 c4=3855735.0/7618050.0; 00310 c5=-1371249.0/7618050.0; 00311 c6=277020.0/7618050.0; 00312 00313 ec[0]=0.0; 00314 ec[1]=1.0/360.0; 00315 ec[2]=0.0; 00316 ec[3]=-128.0/4275.0; 00317 ec[4]=-2197.0/75240.0; 00318 ec[5]=1.0/50.0; 00319 ec[6]=2.0/55.0; 00320 00321 ao.allocate(k2,N); 00322 ao.allocate(k3,N); 00323 ao.allocate(k4,N); 00324 ao.allocate(k5,N); 00325 ao.allocate(k6,N); 00326 ao.allocate(ytmp,N); 00327 00328 } 00329 00330 virtual ~gsl_rkf45_fast() { 00331 00332 ao.free(k2); 00333 ao.free(k3); 00334 ao.free(k4); 00335 ao.free(k5); 00336 ao.free(k6); 00337 ao.free(ytmp); 00338 } 00339 00340 /** 00341 \brief Perform an integration step 00342 00343 Given initial value of the n-dimensional function in \c y and 00344 the derivative in \c dydx (which must generally be computed 00345 beforehand) at the point \c x, take a step of size \c h giving 00346 the result in \c yout, the uncertainty in \c yerr, and the new 00347 derivative in \c dydx_out using function \c derivs to 00348 calculate derivatives. The parameters \c yout and \c y and the 00349 parameters \c dydx_out and \c dydx may refer to the same 00350 object. 00351 00352 \note The value of the parameter \c n should be equal to 00353 the template parameter \c N. 00354 */ 00355 virtual int step(double x, double h, size_t n, vec_t &y, vec_t &dydx, 00356 vec_t &yout, vec_t &yerr, vec_t &dydx_out, param_t &pa, 00357 func_t &derivs) { 00358 00359 size_t i; 00360 00361 // k1 step 00362 for (i=0;i<N;i++) { 00363 ytmp[i]=y[i]+ah[0]*h*dydx[i]; 00364 } 00365 00366 // k2 step 00367 derivs(x+ah[0]*h,N,ytmp,k2,pa); 00368 00369 for (i=0;i<N;i++) { 00370 ytmp[i]=y[i]+h*(b3[0]*dydx[i]+b3[1]*k2[i]); 00371 } 00372 00373 // k3 step 00374 derivs(x+ah[1]*h,N,ytmp,k3,pa); 00375 00376 for (i=0;i<N;i++) { 00377 ytmp[i]=y[i]+h*(b4[0]*dydx[i]+b4[1]*k2[i]+b4[2]*k3[i]); 00378 } 00379 00380 // k4 step 00381 derivs(x+ah[2]*h,N,ytmp,k4,pa); 00382 00383 for (i=0;i<N;i++) { 00384 ytmp[i]=y[i]+h*(b5[0]*dydx[i]+b5[1]*k2[i]+b5[2]*k3[i]+ 00385 b5[3]*k4[i]); 00386 } 00387 00388 // k5 step 00389 derivs(x+ah[3]*h,N,ytmp,k5,pa); 00390 00391 for (i=0;i<N;i++) { 00392 ytmp[i]=y[i]+h*(b6[0]*dydx[i]+b6[1]*k2[i]+b6[2]*k3[i]+ 00393 b6[3]*k4[i]+b6[4]*k5[i]); 00394 } 00395 00396 // k6 step and final sum 00397 derivs(x+ah[4]*h,N,ytmp,k6,pa); 00398 00399 for (i=0;i<n;i++) { 00400 yout[i]=y[i]+h*(c1*dydx[i]+c3*k3[i]+c4*k4[i]+c5*k5[i]+c6*k6[i]); 00401 } 00402 00403 // We put this before the last function evaluation, in contrast 00404 // to the GSL version, so that the dydx[i] that appears in the 00405 // for loop below isn't modified by the subsequent derivative 00406 // evaluation using dydx_out. (The user could have given the 00407 // same vector for both) 00408 for (i=0;i<n;i++) { 00409 yerr[i]=h*(ec[1]*dydx[i]+ec[3]*k3[i]+ec[4]*k4[i]+ec[5]*k5[i]+ 00410 ec[6]*k6[i]); 00411 } 00412 00413 derivs(x+h,n,yout,dydx_out,pa); 00414 00415 return 0; 00416 } 00417 00418 }; 00419 00420 #ifndef DOXYGENP 00421 } 00422 #endif 00423 00424 #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