00001 #pragma ident "$Id: RungeKuttaFehlberg.cpp 2457 2010-08-18 14:20:12Z coandrei $"
00002
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
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
00042 const struct RungeKuttaFehlberg::RKF78Param RungeKuttaFehlberg::rkf78_param =
00043 {
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
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
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
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
00150 RungeKuttaFehlberg::RungeKuttaFehlberg()
00151 :accuracyEps(1.0e-12),
00152 minStepSize(1.2e-10),
00153 isAdaptive(false)
00154 {
00155 }
00156
00157
00158
00159
00160
00161
00162
00163
00164
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
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 }
00185
00186
00187
00188
00189
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
00198 const int n = y.size();
00199
00200 Vector<double> dydx = peom->getDerivatives(x, y);
00201
00202 Vector<double> ytemp(n,0.0) ;
00203
00204
00205 ytemp = y + B(1,0) * h * dydx ;
00206 Vector<double> ak2 = peom->getDerivatives(x + A(1) * h, ytemp);
00207
00208
00209
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
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
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
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
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
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
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
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
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
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
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
00270
00271
00272
00273
00274
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
00281
00282
00283
00284
00285
00286
00287 yerr[i] = h*C(0)*(ak12[i] + ak13[i] - dydx[i] - ak11[i]);
00288
00289 }
00290
00291 return 0;
00292
00293 }
00294
00295
00296
00297
00298
00299
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 ;
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
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
00371 x += hdid ;
00372 y = ytemp;
00373
00374 return 0;
00375
00376 }
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 }
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
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
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
00458
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
00472
00473 Exception e4("Stepsize too small!");
00474 GPSTK_THROW(e4);
00475 }
00476
00477 h = hnext ;
00478 }
00479
00480
00481
00482 Exception e3("Maximum steps exceeded!");
00483 GPSTK_THROW(e3);
00484
00485 }
00486
00487
00488
00490
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);
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);
00520
00521 this->setStepSize(0.01);
00522
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
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 }
00545
00546
00547 }