RungeKuttaFehlberg.cpp

Go to the documentation of this file.
00001 #pragma ident "$Id: RungeKuttaFehlberg.cpp 2457 2010-08-18 14:20:12Z coandrei $"
00002 
00009 //============================================================================
00010 //
00011 //  This file is part of GPSTk, the GPS Toolkit.
00012 //
00013 //  The GPSTk is free software; you can redistribute it and/or modify
00014 //  it under the terms of the GNU Lesser General Public License as published
00015 //  by the Free Software Foundation; either version 2.1 of the License, or
00016 //  any later version.
00017 //
00018 //  The GPSTk is distributed in the hope that it will be useful,
00019 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00020 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00021 //  GNU Lesser General Public License for more details.
00022 //
00023 //  You should have received a copy of the GNU Lesser General Public
00024 //  License along with GPSTk; if not, write to the Free Software Foundation,
00025 //  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00026 //
00027 //  Wei Yan - Chinese Academy of Sciences . 2009, 2010
00028 //
00029 //============================================================================
00030 
00031 #include "RungeKuttaFehlberg.hpp"
00032 
00033 namespace gpstk
00034 {
00035    using namespace std;
00036 
00037    const double RungeKuttaFehlberg::RKF_EPS = 1.0-30; 
00038 
00039    const double RungeKuttaFehlberg::RKF_MAXSTEP = 1000000;
00040       
00041       // RKF78 parameters
00042    const struct RungeKuttaFehlberg::RKF78Param RungeKuttaFehlberg::rkf78_param =
00043    {  // a
00044       { 
00045          0.0,
00046          2.0 / 27.0,
00047          1.0 / 9.0,
00048          1.0 / 6.0,
00049          5.0 / 12.0,
00050          1.0 / 2.0,
00051          5.0 / 6.0,
00052          1.0 / 6.0,
00053          2.0 / 3.0,
00054          1.0 / 3.0,
00055          1.0,
00056          0.0,
00057          1.0,
00058       } ,
00059       // b
00060       {
00061          {              0.0,        0.0,          0.0,            0.0,
00062                         0.0,        0.0,          0.0,            0.0,
00063                         0.0,        0.0,          0.0,            0.0 } ,
00064 
00065          {       2.0 / 27.0,        0.0,          0.0,            0.0,
00066                         0.0,        0.0,          0.0,            0.0,
00067                         0.0,        0.0,          0.0,            0.0 } ,
00068 
00069          {       1.0 / 36.0, 1.0 / 12.0,          0.0,            0.0,
00070                         0.0,        0.0,          0.0,            0.0,  
00071                         0.0,        0.0,          0.0,            0.0 } ,
00072 
00073          {       1.0 / 24.0,        0.0,    1.0 / 8.0,            0.0, 
00074                         0.0,        0.0,          0.0,            0.0,  
00075                         0.0,        0.0,          0.0,            0.0 } ,
00076 
00077          {       5.0 / 12.0,        0.0, -25.0 / 16.0,    25.0 / 16.0,
00078                         0.0,        0.0,          0.0,            0.0,
00079                         0.0,        0.0,          0.0,            0.0 } ,
00080 
00081          {       1.0 / 20.0,        0.0,          0.0,      1.0 / 4.0,
00082                   1.0 / 5.0,        0.0,          0.0,            0.0,   
00083                         0.0,        0.0,          0.0,            0.0 } ,
00084 
00085          {    -25.0 / 108.0,        0.0,          0.0,  125.0 / 108.0,
00086                -65.0 / 27.0,125.0 / 54.0,         0.0,            0.0,
00087                         0.0,        0.0,          0.0,            0.0 } ,
00088 
00089          {     31.0 / 300.0,        0.0,          0.0,            0.0, 
00090                61.0 / 225.0, -2.0 / 9.0, 13.0 / 900.0,            0.0, 
00091                         0.0,        0.0,          0.0,            0.0 } ,
00092          
00093          {              2.0,        0.0,          0.0,    -53.0 / 6.0,
00094                704.0 / 45.0,-107.0 / 9.0, 67.0 / 90.0,            3.0,  
00095                         0.0,        0.0,          0.0,            0.0 } ,
00096          
00097          {    -91.0 / 108.0,        0.0,          0.0,   23.0 / 108.0,  
00098              -976.0 / 135.0,311.0 / 54.0,-19.0 / 60.0,     17.0 / 6.0,  
00099                 -1.0 / 12.0,        0.0,          0.0,            0.0 } ,
00100          
00101          {  2383.0 / 4100.0,        0.0,          0.0, -341.0 / 164.0,
00102             4496.0 / 1025.0,-301.0 / 82.0,2133.0 / 4100,  45.0 / 82.0, 
00103                45.0 / 164.0, 18.0 / 41.0,         0.0,            0.0 } ,
00104          
00105          {      3.0 / 205.0,        0.0,          0.0,            0.0,
00106                         0.0,-6.0 / 41.0, -3.0 / 205.0,    -3.0 / 41.0, 
00107                  3.0 / 41.0, 6.0 / 41.0,          0.0,            0.0 } ,
00108          
00109          { -1777.0 / 4100.0,        0.0,          0.0, -341.0 / 164.0, 
00110             4496.0 / 1025.0,-289.0 / 82.0, 2193.0 / 4100.0, 51.0 / 82.0,
00111                33.0 / 164.0, 12.0 / 41.0,         0.0,           1.0 } ,
00112       } ,
00113       // c1
00114       {
00115          41.0 / 840,
00116             0.0,
00117             0.0,
00118             0.0,
00119             0.0,
00120             34.0 / 105.0,
00121             9.0 / 35.0,
00122             9.0 / 35.0,
00123             9.0 / 280.0,
00124             9.0 / 280.0,
00125             41.0 / 840.0,
00126             0.0,
00127             0.0,
00128       } ,
00129       // c2
00130       {
00131          0.0,
00132          0.0,
00133          0.0,
00134          0.0,
00135          0.0,
00136          34.0 / 105.0,
00137          9.0 / 35.0,
00138          9.0 / 35.0,
00139          9.0 / 280.0,
00140          9.0 / 280.0,
00141          0.0,
00142          41.0 / 840.0,
00143          41.0 / 840.0,
00144      }
00145    };
00146 
00147    //---------------------------------------------------------------------------------
00148 
00149       // Default constructor
00150    RungeKuttaFehlberg::RungeKuttaFehlberg()
00151       :accuracyEps(1.0e-12),
00152       minStepSize(1.2e-10),
00153       isAdaptive(false)
00154    {
00155    }
00156 
00157 
00158 
00159       /* Take a single integration step.
00160        * @param t     tindependent variable (usually the time)
00161        * @param y     inputs (usually the state)
00162        * @param peom  Object containing the Equations of Motion
00163        * @param tf    next time
00164        * @return      containing the new state
00165        */
00166    Vector<double> RungeKuttaFehlberg::integrateTo(const double&           t, 
00167                                                   const Vector<double>&   y, 
00168                                                   EquationOfMotion*       peom,
00169                                                   const double&           tf )
00170    {
00171       if(isAdaptive)
00172       {
00173          // ATTENTION: NOT FINISHED !!!
00174          Exception e("The adaptive method not finished!!!");
00175          GPSTK_THROW(e);
00176 
00177          return integrateAdaptive(t,y,peom,tf);
00178       }
00179       else
00180       {
00181          return integrateFixedStep(t,y,peom,tf);
00182       }
00183       
00184    }  // End of 'RungeKuttaFehlberg::integrateTo()'
00185 
00186 
00187       // RKF78 single step
00188       // 0 = Success
00189       // 1 = Failed to allocate memory
00190    int RungeKuttaFehlberg::rkfs78(const double&          x,
00191                                   const Vector<double>&  y,
00192                                   const double&          h,
00193                                   EquationOfMotion*      peom,
00194                                   Vector<double>&        yout,
00195                                   Vector<double>&        yerr)
00196    {
00197       // number of variable
00198       const int n = y.size();
00199 
00200       Vector<double> dydx = peom->getDerivatives(x, y);  // ak1
00201       
00202       Vector<double> ytemp(n,0.0) ;
00203 
00204       // ak2
00205       ytemp = y + B(1,0) * h * dydx ;
00206       Vector<double> ak2 = peom->getDerivatives(x + A(1) * h, ytemp);
00207 
00208 
00209       // ak3
00210       ytemp = y + h * (B(2,0) * dydx + B(2,1) * ak2) ;
00211       Vector<double> ak3 = peom->getDerivatives(x + A(2) * h, ytemp);
00212       
00213       // ak4
00214       ytemp = y + h * (B(3,0) * dydx + B(3,1) * ak2 + B(3,2) * ak3) ;
00215       Vector<double> ak4 = peom->getDerivatives(x + A(3) * h, ytemp);
00216 
00217       // ak5
00218       ytemp = y + h * (B(4,0) * dydx + B(4,1) * ak2 + B(4,2) * ak3 + B(4,3) * ak4) ;
00219       Vector<double> ak5 = peom->getDerivatives(x + A(4) * h, ytemp);
00220       
00221       // ak6
00222       ytemp = y + h * (B(5,0) * dydx + B(5,1) * ak2 + B(5,2) * ak3 + B(5,3) * ak4 
00223          + B(5,4) * ak5) ;
00224       Vector<double> ak6 = peom->getDerivatives(x + A(5) * h, ytemp);
00225       
00226       // ak7
00227       ytemp = y + h * (B(6,0) * dydx + B(6,1) * ak2 + B(6,2) * ak3 + B(6,3) * ak4
00228          + B(6,4) * ak5 + B(6,5) * ak6) ;
00229       Vector<double> ak7 = peom->getDerivatives(x + A(6) * h, ytemp);
00230       
00231       // ak8
00232       ytemp = y + h * (B(7,0) * dydx + B(7,1) * ak2 + B(7,2) * ak3 + B(7,3) * ak4 
00233          + B(7,4) * ak5 + B(7,5) * ak6 + B(7,6) * ak7) ;
00234       Vector<double> ak8 = peom->getDerivatives(x + A(7) * h, ytemp);
00235       
00236       // ak9
00237       ytemp = y + h * (B(8,0) * dydx + B(8,1) * ak2 + B(8,2) * ak3 + B(8,3) * ak4 
00238          + B(8,4) * ak5 + B(8,5) * ak6 + B(8,6) * ak7 + B(8,7) * ak8) ;
00239       Vector<double> ak9 = peom->getDerivatives(x + A(8) * h, ytemp);
00240       
00241       // ak10
00242       ytemp = y + h * (B(9,0) * dydx + B(9,1) * ak2 + B(9,2) * ak3 + B(9,3) * ak4
00243          + B(9,4) * ak5 + B(9,5) * ak6 + B(9,6) * ak7 + B(9,7) * ak8 + B(9,8) * ak9) ;
00244       Vector<double> ak10 = peom->getDerivatives(x + A(9) * h, ytemp);
00245 
00246       // ak11
00247       ytemp = y + h * (B(10,0) * dydx + B(10,1) * ak2 + B(10,2) * ak3 + B(10,3) * ak4
00248          + B(10,4) * ak5 + B(10,5) * ak6 + B(10,6) * ak7 + B(10,7) * ak8 + B(10,8) * ak9 
00249          + B(10,9) * ak10) ;
00250       Vector<double> ak11 = peom->getDerivatives(x + A(10) * h, ytemp);
00251       
00252       // ak12
00253       ytemp = y + h * (B(11,0) * dydx + B(11,1) * ak2 + B(11,2) * ak3 + B(11,3) * ak4 
00254          + B(11,4) * ak5 + B(11,5) * ak6 + B(11,6) * ak7 + B(11,7) * ak8 + B(11,8) * ak9 
00255          + B(11,9) * ak10 + B(11,10) * ak11) ;
00256       Vector<double> ak12 = peom->getDerivatives(x + A(11) * h, ytemp);
00257       
00258       // ak13
00259       ytemp = y + h * (B(12,0) * dydx + B(12,1) * ak2 + B(12,2) * ak3 + B(12,3) * ak4 
00260          + B(12,4) * ak5 + B(12,5) * ak6 + B(12,6) * ak7 + B(12,7) * ak8 + B(12,8) * ak9
00261          + B(12,9) * ak10 + B(12,10) * ak11 + B(12,11) * ak12) ;
00262       Vector<double> ak13 = peom->getDerivatives(x + A(12) * h, ytemp);
00263       
00264       yout.resize(n,0.0);
00265       yerr.resize(n,0.0);
00266       for (int i = 0; i < n; i++ ) 
00267       {
00268          /*
00269          // y7th
00270          yout[i] = y[i] + h * (C(0) * dydx[i] + C(1) * ak2[i] + C(2) * ak3[i] + C(3) * ak4[i] 
00271             + C(4) * ak5[i] + C(5) * ak6[i] + C(6) * ak7[i] + C(7) * ak8[i] + C(8) * ak9[i] 
00272             + C(9) * ak10[i] + C(10) * ak11[i] + C(11) * ak12[i] + C(12) * ak13[i]) ;*/
00273 
00274          // y8th
00275          yout[i] = y[i] + h * (C2(0) * dydx[i] + C2(1) * ak2[i] + C2(2) * ak3[i] + C2(3) * ak4[i] 
00276             + C2(4) * ak5[i] + C2(5) * ak6[i] + C2(6) * ak7[i] + C2(7) * ak8[i] + C2(8) * ak9[i] 
00277             + C2(9) * ak10[i] + C2(10) * ak11[i] + C2(11) * ak12[i] + C2(12) * ak13[i]) ;
00278          
00279          /*
00280          yerr[i] = h * (DC(0) * dydx[i] + DC(1) * ak2[i] + DC(2) * ak3[i] + DC(3) * ak4[i] 
00281             + DC(4) * ak5[i] + DC(5) * ak6[i] + DC(6) * ak7[i] + DC(7) * ak8[i] + DC(8) * ak9[i] 
00282             + DC(9) * ak10[i] + DC(10) * ak11[i] + DC(11) * ak12[i] + DC(12) * ak13[i]) ;
00283             */
00284          
00285          //dydx ak2 ak3 4 5 6 7 8 9 10 11 12 13
00286          //0     1   2  3 4 5 6 7 8 9  10 11 12 
00287          yerr[i] = h*C(0)*(ak12[i] + ak13[i] - dydx[i] - ak11[i]);
00288 
00289       }
00290 
00291       return 0;
00292 
00293    }  // End of 'RungeKuttaFehlberg::rkfs78()'
00294    
00295 
00296    // takes one "quality-controlled" Runge-Kutta-Fehlberg step 
00297    // 0 = Success
00298    // 1 = Unable to allocate workspace memory
00299    // 2 = Stepsize underflow
00300    int RungeKuttaFehlberg::rkfqcs(double&           x,
00301                                   Vector<double>&   y,
00302                                   const double&     htry,
00303                                   const double&     accuracy,
00304                                   EquationOfMotion* peom,
00305                                   Vector<double>&   yscal,
00306                                   double&           hdid,
00307                                   double&           hnext)
00308    {
00309       const double SAFETY = 0.9;
00310       const double PGROW  = (-1.0 / 8.0); 
00311       const double PSHRINK = (-1.0 / 7.0); 
00312       const double ERRCON = 2.56578451395034701e-8 ;  // ERRCON equals (5/SAFETY) raised to the power (1/PGROW) 
00313       
00314       const int n = y.size();
00315 
00316       Vector<double> yerr(n,0.0);
00317       Vector<double> ytemp(n,0.0);
00318 
00319       double h = htry ;
00320       
00321       double errmax(0.0);
00322 
00323       while(true)
00324       {
00325          int jstat = rkfs78(x,y,h,peom,ytemp,yerr);
00326          if ( jstat != 0 ) 
00327          {
00328             return jstat ;
00329          } 
00330 
00331          errmax = 0.0 ;
00332          for (int i = 0; i < n; i++ ) 
00333          {  
00334             double temp = fabs ( yerr[i] / yscal[i] );
00335             errmax = (errmax >= temp) ? errmax : temp;
00336          }
00337          errmax /= accuracy;
00338 
00339          if ( errmax <= 1.0 ) 
00340          {
00341             break ;
00342          }
00343 
00344          double htemp = SAFETY * h * std::pow ( errmax, PSHRINK ) ;
00345          
00346          h = (h >=0 ) ? (htemp > 0.1*h ? htemp : 0.1*h) : (htemp < 0.1*h ? htemp : 0.1*h);
00347          
00348          double xnew = x + h ;
00349 
00350          // Test for Underflow
00351 
00352          if ( xnew == x ) 
00353          {
00354             return 2 ;
00355          }
00356 
00357       }
00358 
00359       if ( errmax > ERRCON ) 
00360       {
00361          hnext = SAFETY * h * std::pow ( errmax, PGROW ) ;
00362       }
00363       else 
00364       {
00365          hnext = 5.0 * h ;
00366       }
00367       
00368       hdid = h;
00369       
00370       // update x and y
00371       x += hdid ;
00372       y = ytemp;
00373 
00374       return 0;
00375 
00376    }  // End of method 'RungeKuttaFehlberg::rkfqcs()'
00377    
00378 
00379    Vector<double> RungeKuttaFehlberg::integrateFixedStep(const double&           t, 
00380                                                          const Vector<double>&   y, 
00381                                                          EquationOfMotion*       peom,
00382                                                          const double&           tf )
00383    {
00384       Vector<double> yout,yerr;
00385 
00386       Vector<double> oldState = y;
00387 
00388       double dt = stepSize;
00389 
00390       double tt = t;
00391       while(t <= tf)
00392       {
00393          if((tt + dt) >= tf)
00394          {
00395             dt = tf - tt;
00396             break;
00397          }
00398             
00399          rkfs78(tt,oldState,dt,peom,yout,yerr);
00400          
00401          oldState = yout;
00402 
00403          tt += dt;
00404       }
00405 
00406       dt=tf-tt;
00407 
00408       rkfs78(tt,oldState,dt,peom,yout,yerr);
00409 
00410       return yout;
00411 
00412    }  // End of method 'RungeKuttaFehlberg::integrateFixedStep'
00413 
00414    Vector<double> RungeKuttaFehlberg::integrateAdaptive(const double&           t, 
00415                                     const Vector<double>&   y, 
00416                                     EquationOfMotion*       peom,
00417                                     const double&           tf )
00418    {
00419       double eps = accuracyEps;
00420       double x1 = t;
00421       double x2 = tf;
00422       double h1 = stepSize;
00423       double hmin = minStepSize;
00424 
00425       // number of variables
00426       const int nvar = y.size();
00427 
00428 
00429       double x = x1 ;
00430       double h = std::fabs(h1) * ( ( x2 < x1 ) ? -1.0 : 1.0);
00431 
00432       // make a copy of the data
00433       Vector<double> yend = y;
00434 
00435       for (int nstp = 0; nstp < RKF_MAXSTEP; nstp++ ) 
00436       {
00437 
00438          Vector<double> dydx = peom->getDerivatives(x, yend);
00439       
00440          Vector<double> yscal(nvar,0.0);
00441          for(int i=0;i<nvar;i++)
00442          {
00443             yscal(i) = std::fabs(yend(i)) + std::fabs(dydx(i)*h) + RKF_EPS;
00444          }
00445          
00446 
00447          if ( ( x + h - x2 ) * ( x + h - x1 ) > 0.0)
00448          {
00449             h = x2 - x ;
00450          }
00451 
00452          double hdid(0.0),hnext(0.0);
00453 
00454          int jstat = rkfqcs(x, yend, h, eps, peom, yscal, hdid, hnext);
00455          if ( jstat != 0 ) 
00456          {
00457             // 1  Failed to allocate
00458             // 2  Stepsize underflow
00459 
00460             Exception e2("Stepsize underflow!");
00461             GPSTK_THROW(e2);
00462          } ;
00463 
00464          if ( ( x - x2 ) * ( x2 - x1 ) >= 0.0 )
00465          {           
00466             return yend ;
00467          }
00468 
00469          if ( fabs ( hnext ) <= hmin ) 
00470          {
00471             // Stepsize too small
00472 
00473             Exception e4("Stepsize too small!");
00474             GPSTK_THROW(e4);
00475          }
00476 
00477          h = hnext ;
00478       }
00479 
00480       // Maximum steps exceeded
00481 
00482       Exception e3("Maximum steps exceeded!");
00483       GPSTK_THROW(e3);
00484 
00485    }  // End of method 'RungeKuttaFehlberg::integrateAdaptive'
00486 
00487 
00488 
00490    // class to test integrator
00491    
00492    class TestEOM : public EquationOfMotion
00493    {
00494    public:
00495       virtual Vector<double> getDerivatives(const double& t,
00496          const Vector<double>& y);
00497    };
00498 
00499    Vector<double>  TestEOM::getDerivatives(const double& t,
00500       const Vector<double>& y)
00501    {
00502       gpstk::Vector<double> dydx(y.size(),0.0);   
00503       dydx[0] = std::cos(t); //0.25 * y(0) * ( 1.0 - y(0) / 20.0 ) ;
00504       
00505      
00506       return dydx;
00507    }
00508    
00509 
00510 
00511    void RungeKuttaFehlberg::test()
00512    {
00513       TestEOM eom;
00514       
00515       double t0   = 0.0;
00516       double h   = 1.0;
00517       gpstk::Vector<double> y0(1,0.0); 
00518       int dim      = 1;
00519       gpstk::Vector<double> y(1,0.0);   // = {0.0};
00520       
00521       this->setStepSize(0.01);
00522       //this->setAdaptive(true);
00523 
00524       int i=0;
00525       for(i=0;i<1000000;i++)
00526       {
00527          y = integrateTo(t0, y0, &eom, t0 + h);
00528          double t = t0 + h;
00529          double err = std::sin(t)-y[0];
00530 
00531          //cout<<fixed<<setprecision(8)<<setw(18);
00532          cout<<fixed;
00533          cout<<setw(18)<<setprecision(8)<< t << " "
00534             <<setw(18)<<setprecision(8)<<y[0] << " "
00535             <<setw(18)<<setprecision(12)<<err<<endl;
00536 
00537          t0 += h;
00538          y0[0] = y[0];
00539          y[0] = 0.0;
00540       }
00541       
00542       int a =0;
00543 
00544    }  // End of method 'RungeKuttaFehlberg::test()'
00545 
00546 
00547 }  // End of 'namespace gpstk'

Generated on Tue May 22 03:31:01 2012 for GPS ToolKit Software Library by  doxygen 1.3.9.1