RKF45method.cpp

00001 //
00002 //#####################################################################
00003 //                          RKF45method.cpp 
00004 //#####################################################################
00005 //
00006 // Class RKF45method implementation 
00007 //
00008 // For Math 157
00009 //
00010 //#####################################################################
00011 // Chris Anderson (C) UCLA                             Jan. 22, 2009
00012 //#####################################################################
00013 //
00014 #include "RKF45method.h"
00015 #include "fortranODEfunction.h"
00016 
00017 RKF45method::RKF45method() 
00018 {
00019     errorTolerance = 1.0e-02;
00020     errorCode      = 0;
00021 }
00022 
00023 void RKF45method::setErrorTolerance(double tolerance)
00024 {
00025     errorTolerance  = tolerance ;
00026 }
00027 
00028 double RKF45method::getErrorTolerance() const
00029 {
00030     return errorTolerance;
00031 }
00032 
00033 int RKF45method::getErrorCode() const
00034 {
00035     return errorCode;
00036 }
00037 
00038 //
00039 // Prototype for the external ftc translation of rk45. 
00040 //
00041 extern "C" int rkf45_(int (*f)(double*, double*, double*), long *neqn, 
00042 double *y, double*t, double *tout, double *relerr, 
00043 double *abserr, long *iflag, double *work, long *iwork);
00044 
00045 /**
00046 @arg yk     : DoubleVector containing solution at time t = tk
00047 @arg dt     : Timestep
00048 @arg Fptr   : Pointer to to a class that extends the VectorFuntion class
00049 \returns     
00050 yk is updated with the solution value at t = tk + dt. The return value is 0 if advance is successful; 
00051 otherwise the return value is the error code iflag from the rkf45 method. The value of 
00052 iflag can also be obtained using the getErrorCode() member function. 
00053 The following description is taken from the rkf45.f source code file. <p>
00054 
00055 <pre>
00056        iflag = 3 -- integration was not completed because relative error
00057                     tolerance was too small. relerr has been increased
00058                     appropriately for continuing.
00059              = 4 -- integration was not completed because more than
00060                     3000 derivative evaluations were needed. this
00061                     is approximately 500 steps.
00062              = 5 -- integration was not completed because solution
00063                     vanished making a pure relative error test
00064                     impossible. must use non-zero abserr to continue.
00065                     using the one-step integration mode for one step
00066                     is a good way to proceed.
00067              = 6 -- integration was not completed because requested
00068                     accuracy could not be achieved using smallest
00069                     allowable stepsize. user must increase the error
00070                     tolerance before continued integration can be
00071                    attempted.
00072              = 7 -- it is likely that rkf45 is inefficient for solving
00073                     this problem. too much output is restricting the
00074                     natural stepsize choice. use the one-step integrator
00075                     mode.
00076              = 8 -- invalid input parameters
00077                     this indicator occurs if any of the following is
00078                     satisfied -   neqn .le. 0
00079                                   t=tout  and  iflag .ne. +1 or -1
00080                                   relerr or abserr .lt. 0.
00081                                   iflag .eq. 0  or  .lt. -2  or  .gt. 8
00082 </pre>
00083 
00084 The errorTolerance specified is used to set both the absolute and 
00085 relative error tolerence values. As dicussed in the comments in
00086 original rkf45.f, <a href="..\rkf45Comments.f">rkf45Comments.f</a>,
00087 the advance() routine should not be used with relative error control 
00088 smaller than about 1.e-8.
00089 */
00090 
00091 int RKF45method::advance(DoubleVector& yk, double dt, VectorFunction* Fptr)
00092 {
00093     long i;
00094 
00095     long dim = yk.getSize();
00096 //
00097 //  Use the fortranODEfunction class to provide 
00098 //  a function pointer interface to the ODE specified by Fptr. 
00099 //
00100     fortranODEfunction::setDimension(dim);
00101     fortranODEfunction::setFunction(Fptr);
00102     int (*f)(double*, double*, double*) = fortranODEfunction::f;
00103 //
00104 //  Allocate local temporary arrays
00105 //
00106     double* y    = new double[dim];
00107     double* work = new double[4 + 6*dim];
00108     long*  iwork = new long[10];
00109 //
00110 //  Specify parameters and initial condition
00111 //
00112     long neqn     = dim;
00113     double t      = 0.0;        // We assume an autonomous system; so always
00114     double tout   = dt;         // start at t = 0 and go to t = dt.
00115     double relerr = errorTolerance;
00116     double abserr = errorTolerance;
00117     long   iflag  = 1;
00118 
00119     for(i = 0; i < dim; i++)
00120     {
00121       y[i] =  yk(i);
00122     }
00123 //
00124 //  Call rkf45 method
00125 //
00126     rkf45_(f,&neqn,y,&t,&tout,&relerr,&abserr,&iflag,work,iwork);
00127 // 
00128 //  Check for error in integration 
00129 //
00130     if(iflag != 2)
00131     {
00132     // clean up 
00133     delete [] work;  delete [] iwork;  delete [] y;
00134 
00135     // Set error code to iflag and return iflag value 
00136     
00137     errorCode = iflag;
00138     return iflag;
00139     }
00140 //
00141 //  Call initialize so that ykp1 is guaranteed non-null.
00142 // 
00143     
00144     for(i = 0; i < dim; i++)
00145     {
00146     yk(i) = y[i];
00147     }
00148     
00149     // clean up 
00150 
00151     delete [] work;  delete [] iwork; delete [] y;
00152     //
00153     // Set error code to 0 and return 0 for success 
00154     // Note: this code value is not the iflag value.
00155     //
00156     errorCode = 0;
00157     return 0;
00158 }

Generated on Fri Jan 23 08:16:07 2009 for RKF45 by  doxygen 1.5.1-p1