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/rkck.c 00024 * 00025 * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman 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_RKCK_H 00043 #define O2SCL_GSL_RKCK_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 Cash-Karp embedded Runge-Kutta ODE stepper (GSL) 00054 00055 Based on \ref Cash90 . 00056 */ 00057 template<class param_t, class func_t=ode_funct<param_t>, 00058 class vec_t=ovector_base, class alloc_vec_t=ovector, 00059 class alloc_t=ovector_alloc> class gsl_rkck : 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], ec[7]; 00079 double b21, c1, c3, c4, c6; 00080 //@} 00081 00082 public: 00083 00084 gsl_rkck() { 00085 this->order=5; 00086 00087 ah[0]=1.0/5.0; 00088 ah[1]=3.0/10.0; 00089 ah[2]=3.0/5.0; 00090 ah[3]=1.0; 00091 ah[4]=7.0/8.0; 00092 00093 b3[0]=3.0/40.0; 00094 b3[1]=9.0/40.0; 00095 00096 b4[0]=3.0/10.0; 00097 b4[1]=-9.0/10.0; 00098 b4[2]=12.0/10.0; 00099 00100 b5[0]=-11.0/54.0; 00101 b5[1]=5.0/2.0; 00102 b5[2]=-70.0/27.0; 00103 b5[3]=35.0/27.0; 00104 00105 b6[0]=1631.0/55296.0; 00106 b6[1]=175.0/512.0; 00107 b6[2]=575.0/13824.0; 00108 b6[3]=44275.0/110592.0; 00109 b6[4]=253.0/4096.0; 00110 00111 ec[0]=0.0; 00112 ec[1]=37.0/378.0-2825.0/27648.0; 00113 ec[2]=0.0; 00114 ec[3]=250.0/621.0-18575.0/48384.0; 00115 ec[4]=125.0/594.0-13525.0/55296.0; 00116 ec[5]=-277.0/14336.0; 00117 ec[6]=512.0/1771.0-1.0/4.0; 00118 00119 b21=1.0/5.0; 00120 00121 c1=37.0/378.0; 00122 c3=250.0/621.0; 00123 c4=125.0/594.0; 00124 c6=512.0/1771.0; 00125 00126 ndim=0; 00127 } 00128 00129 virtual ~gsl_rkck() { 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 for (i=0;i<n;i++) { 00184 ytmp[i]=y[i]+b21*h*dydx[i]; 00185 } 00186 00187 o2scl::error_update(ret,derivs(x+ah[0]*h,n,ytmp,k2,pa)); 00188 00189 for (i=0;i<n;i++) { 00190 ytmp[i]=y[i]+h*(b3[0]*dydx[i]+b3[1]*k2[i]); 00191 } 00192 00193 o2scl::error_update(ret,derivs(x+ah[1]*h,n,ytmp,k3,pa)); 00194 00195 for (i=0;i<n;i++) { 00196 ytmp[i]=y[i]+h*(b4[0]*dydx[i]+b4[1]*k2[i]+b4[2]*k3[i]); 00197 } 00198 00199 o2scl::error_update(ret,derivs(x+ah[2]*h,n,ytmp,k4,pa)); 00200 00201 for (i=0;i<n;i++) { 00202 ytmp[i]=y[i]+h*(b5[0]*dydx[i]+b5[1]*k2[i]+b5[2]*k3[i]+ 00203 b5[3]*k4[i]); 00204 } 00205 00206 o2scl::error_update(ret,derivs(x+ah[3]*h,n,ytmp,k5,pa)); 00207 00208 for (i=0;i<n;i++) { 00209 ytmp[i]=y[i]+h*(b6[0]*dydx[i]+b6[1]*k2[i]+b6[2]*k3[i]+ 00210 b6[3]*k4[i]+b6[4]*k5[i]); 00211 } 00212 00213 o2scl::error_update(ret,derivs(x+ah[4]*h,n,ytmp,k6,pa)); 00214 00215 for (i=0;i<n;i++) { 00216 yout[i]=y[i]+h*(c1*dydx[i]+c3*k3[i]+c4*k4[i]+c6*k6[i]); 00217 } 00218 00219 // We put this before the last function evaluation, in contrast 00220 // to the GSL version, so that the dydx[i] that appears in the 00221 // for loop below isn't modified by the subsequent derivative 00222 // evaluation using dydx_out. (The user could have given the 00223 // same vector for both) 00224 for (i=0;i<n;i++) { 00225 yerr[i]=h*(ec[1]*dydx[i]+ec[3]*k3[i]+ec[4]*k4[i]+ec[5]*k5[i]+ 00226 ec[6]*k6[i]); 00227 } 00228 00229 o2scl::error_update(ret,derivs(x+h,n,yout,dydx_out,pa)); 00230 00231 return ret; 00232 } 00233 00234 }; 00235 00236 /** \brief Faster Cash-Karp embedded Runge-Kutta ODE stepper (GSL) 00237 00238 This a faster version of \ref gsl_rkck, which is a stepper for a 00239 fixed number of ODEs. It ignores the error values returned by 00240 the \c derivs argument. The argument \c n to step() should 00241 always be equal to the template parameter \c N, and the vector 00242 parameters to step must have space allocated for at least \c N 00243 elements. No error checking is performed to ensure that this is 00244 the case. 00245 00246 Based on \ref Cash90 . 00247 */ 00248 template<size_t N, class param_t, class func_t=ode_funct<param_t>, 00249 class vec_t=ovector_base, class alloc_vec_t=ovector, 00250 class alloc_t=ovector_alloc> class gsl_rkck_fast : 00251 public odestep<param_t,func_t,vec_t> { 00252 00253 protected: 00254 00255 /// \name Storage for the intermediate steps 00256 //@{ 00257 alloc_vec_t k2, k3, k4, k5, k6, ytmp; 00258 //@} 00259 00260 /// Memory allocator for objects of type \c alloc_vec_t 00261 alloc_t ao; 00262 00263 /** \name Storage for the coefficients 00264 */ 00265 //@{ 00266 double ah[5], b3[2], b4[3], b5[4], b6[5], ec[7]; 00267 double b21, c1, c3, c4, c6; 00268 //@} 00269 00270 public: 00271 00272 gsl_rkck_fast() { 00273 this->order=5; 00274 00275 ah[0]=1.0/5.0; 00276 ah[1]=3.0/10.0; 00277 ah[2]=3.0/5.0; 00278 ah[3]=1.0; 00279 ah[4]=7.0/8.0; 00280 b3[0]=3.0/40.0; 00281 b3[1]=9.0/40.0; 00282 b4[0]=3.0/10.0; 00283 b4[1]=-9.0/10.0; 00284 b4[2]=12.0/10.0; 00285 b5[0]=-11.0/54.0; 00286 b5[1]=5.0/2.0; 00287 b5[2]=-70.0/27.0; 00288 b5[3]=35.0/27.0; 00289 b6[0]=1631.0/55296.0; 00290 b6[1]=175.0/512.0; 00291 b6[2]=575.0/13824.0; 00292 b6[3]=44275.0/110592.0; 00293 b6[4]=253.0/4096.0; 00294 ec[0]=0.0; 00295 ec[1]=37.0/378.0-2825.0/27648.0; 00296 ec[2]=0.0; 00297 ec[3]=250.0/621.0-18575.0/48384.0; 00298 ec[4]=125.0/594.0-13525.0/55296.0; 00299 ec[5]=-277.0/14336.0; 00300 ec[6]=512.0/1771.0-1.0/4.0; 00301 00302 b21=1.0/5.0; 00303 c1=37.0/378.0; 00304 c3=250.0/621.0; 00305 c4=125.0/594.0; 00306 c6=512.0/1771.0; 00307 00308 ao.allocate(k2,N); 00309 ao.allocate(k3,N); 00310 ao.allocate(k4,N); 00311 ao.allocate(k5,N); 00312 ao.allocate(k6,N); 00313 ao.allocate(ytmp,N); 00314 00315 } 00316 00317 virtual ~gsl_rkck_fast() { 00318 00319 ao.free(k2); 00320 ao.free(k3); 00321 ao.free(k4); 00322 ao.free(k5); 00323 ao.free(k6); 00324 ao.free(ytmp); 00325 } 00326 00327 /** 00328 \brief Perform an integration step 00329 00330 Given initial value of the n-dimensional function in \c y and 00331 the derivative in \c dydx (which must generally be computed 00332 beforehand) at the point \c x, take a step of size \c h giving 00333 the result in \c yout, the uncertainty in \c yerr, and the new 00334 derivative in \c dydx_out using function \c derivs to 00335 calculate derivatives. The parameters \c yout and \c y and the 00336 parameters \c dydx_out and \c dydx may refer to the same 00337 object. 00338 00339 \note The value of the parameter \c n must be equal to 00340 the template parameter \c N. 00341 */ 00342 virtual int step(double x, double h, size_t n, vec_t &y, vec_t &dydx, 00343 vec_t &yout, vec_t &yerr, vec_t &dydx_out, param_t &pa, 00344 func_t &derivs) { 00345 00346 size_t i; 00347 00348 for (i=0;i<N;i++) { 00349 ytmp[i]=y[i]+b21*h*dydx[i]; 00350 } 00351 00352 derivs(x+ah[0]*h,N,ytmp,k2,pa); 00353 00354 for (i=0;i<N;i++) { 00355 ytmp[i]=y[i]+h*(b3[0]*dydx[i]+b3[1]*k2[i]); 00356 } 00357 00358 derivs(x+ah[1]*h,N,ytmp,k3,pa); 00359 00360 for (i=0;i<N;i++) { 00361 ytmp[i]=y[i]+h*(b4[0]*dydx[i]+b4[1]*k2[i]+b4[2]*k3[i]); 00362 } 00363 00364 derivs(x+ah[2]*h,N,ytmp,k4,pa); 00365 00366 for (i=0;i<N;i++) { 00367 ytmp[i]=y[i]+h*(b5[0]*dydx[i]+b5[1]*k2[i]+b5[2]*k3[i]+ 00368 b5[3]*k4[i]); 00369 } 00370 00371 derivs(x+ah[3]*h,N,ytmp,k5,pa); 00372 00373 for (i=0;i<N;i++) { 00374 ytmp[i]=y[i]+h*(b6[0]*dydx[i]+b6[1]*k2[i]+b6[2]*k3[i]+ 00375 b6[3]*k4[i]+b6[4]*k5[i]); 00376 } 00377 00378 derivs(x+ah[4]*h,N,ytmp,k6,pa); 00379 00380 for (i=0;i<N;i++) { 00381 yout[i]=y[i]+h*(c1*dydx[i]+c3*k3[i]+c4*k4[i]+c6*k6[i]); 00382 } 00383 00384 // We put this before the last function evaluation, in contrast 00385 // to the GSL version, so that the dydx[i] that appears in the 00386 // for loop below isn't modified by the subsequent derivative 00387 // evaluation using dydx_out. (The user could have given the 00388 // same vector for both) 00389 for (i=0;i<N;i++) { 00390 yerr[i]=h*(ec[1]*dydx[i]+ec[3]*k3[i]+ec[4]*k4[i]+ec[5]*k5[i]+ 00391 ec[6]*k6[i]); 00392 } 00393 00394 derivs(x+h,N,yout,dydx_out,pa); 00395 00396 return 0; 00397 } 00398 00399 }; 00400 00401 #ifndef DOXYGENP 00402 } 00403 #endif 00404 00405 #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