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