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