Object-oriented Scientific Computing Library: Version 0.910
gsl_rkck.h
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
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).

Get Object-oriented Scientific Computing
Lib at SourceForge.net. Fast, secure and Free Open Source software
downloads.