00001 ////////////////////////////////////////////////////////////////////////////////////////////////// 00002 /*! \file RungeKuttaIntegrator.cpp 00003 * \brief Implementation of the Runge-Kutta Fourth Order integrator. 00004 * \author $Author: cakinli $ 00005 * \version $Revision: 1.1.1.1 $ 00006 * \date $Date: 2005/04/26 17:41:00 $ 00007 ////////////////////////////////////////////////////////////////////////////////////////////////// 00008 * \todo Add test cases 00009 */ 00010 ////////////////////////////////////////////////////////////////////////////////////////////////// 00011 00012 00013 #include "RungeKuttaIntegrator.h" 00014 namespace O_SESSAME { 00015 00016 /*! \brief Creates a default, unitialized RK-integrator. 00017 */ 00018 RungeKuttaIntegrator::RungeKuttaIntegrator() 00019 { 00020 m_NumSteps = 1; 00021 } 00022 00023 /** \todo pull out RungeKuttaIntegrator::Step function */ 00024 /* 00025 Matrix RungeKuttaIntegrator::Integrate(const Vector &_propTime, odeFunc _FuncPtr, const Vector &_initialConditions, const Matrix &_constants, vectorFuncPtr _vectorFuncPtr) 00026 { 00027 double timeInitial = _propTime(VectorIndexBase); 00028 double t = timeInitial; 00029 double h = (_propTime(VectorIndexBase + 1) - t) / m_NumSteps; 00030 00031 int numEqs = _initialConditions.getIndexCount(); 00032 Vector inputs = _initialConditions; 00033 Vector K1(numEqs); 00034 Vector K2(numEqs); 00035 Vector K3(numEqs); 00036 Vector K4(numEqs); 00037 00038 Matrix output(m_NumSteps + 1, numEqs + 1); 00039 00040 output(MatrixIndexBase,MatrixIndexBase) = timeInitial; 00041 output(MatrixIndexBase,_(MatrixIndexBase+1,MatrixIndexBase+numEqs)) = ~_initialConditions; 00042 00043 Vector temp(numEqs); 00044 for (int ii = 1; ii <= m_NumSteps; ++ii) 00045 { 00046 K1 = h * _FuncPtr(t, inputs, _constants, _vectorFuncPtr); 00047 temp = inputs + K1 / 2.0; 00048 K2 = h * _FuncPtr(t + h/2, temp, _constants, _vectorFuncPtr); 00049 temp = inputs + K2 / 2.0; 00050 K3 = h * _FuncPtr(t + h/2, temp, _constants, _vectorFuncPtr); 00051 temp = inputs + K3; 00052 K4 = h * _FuncPtr(t + h, temp, _constants, _vectorFuncPtr); 00053 for (int jj = MatrixIndexBase; jj < MatrixIndexBase + numEqs; ++jj) 00054 { 00055 inputs(jj) += (K1(jj) 00056 + 2.0 * K2(jj) 00057 + 2.0 * K3(jj) 00058 + K4(jj)) / 6.0; 00059 } 00060 t = timeInitial + ii * h; 00061 output(MatrixIndexBase + ii,MatrixIndexBase) = t; 00062 output(MatrixIndexBase + ii,_(MatrixIndexBase+1,MatrixIndexBase+numEqs)) = ~inputs; 00063 } 00064 return output; 00065 } 00066 */ 00067 00068 /*! \brief Integrates the Right-Hand Side (RHS) equation using a Runge-Kutta 4th Order %integrator. 00069 * 00070 * This function will integrate an equation of the form \f$\dot{\bf x} = f(t,{\bf x})\f$ from \f$t_0\f$ to \f$t_f\f$ given 00071 * initial conditions, an orbit and attitude object (or empty references if not required), a matrix of constants, and an 00072 * external call-back function. 00073 * 00074 * @param _propTime This input variable specifies the list of integration times, from the starting value (first time) to the ending integration (last time) with the specified intervals. 00075 * If no specific intervals are required (and can be interpolated later), the user needs to just specify the beginning and end times of integration. 00076 * This vector is built by creating ssfTime object, and "push_back" them onto the vector list: 00077 * \code 00078 * vector<ssfTime> integrationTimes; 00079 * ssfTime begin(0); 00080 * ssfTime end(begin + 20); 00081 * integrationTimes.push_back(begin); 00082 * integrationTimes.push_back(end); 00083 * \endcode 00084 * @param _FunctorPtr This is the reference (odeFunctor) to the Right-Hand side (RHS) of the integration equation. It should be a single function that computes the time derivative 00085 * of the state given the time, current state, and other parameters. 00086 * @param _initialConditions The vector of initial conditions of the state being integrated. It can be any sized. 00087 * @param _pOrbit This is a pointer to an Orbit object. It will be passed directly to the RHS and may be used for evaluating the dynamics or disturbance torque/forces. 00088 * However, if no orbit is required, or used, the user should only pass a NULL pointer and the orbit object shouldn't be used in the user's RHS function. 00089 * @param _pAttitude This is a pointer to an Attitude object. It behaves much the same way as _Orbit above. It will be passed directly to the RHS function for use in 00090 * evaluation, but if not used, the user should only pass a NULL pointer, and the attitude object not used in the RHS function. 00091 * @param _constants This is a matrix of constants that is required by the RHS function. The constants are passed to each evaluation of the RHS, and may be any size, and 00092 * store any values the user requires. Examples include Moments of Inertia, ballistic coefficients, mass, etc. 00093 * @param _functorPtr The Functor is a call-back function that the RHS can use to evaluate an external function call. The prototype of the _functorPtr must correspond to the Functor 00094 * definition, but other than that, may perform any calculations required by the user in the RHS function. 00095 * @return The output of the integration function is a matrix of calculated integration times (meshpoints), and integrated state values at each of the meshpoints. 00096 * \f[ 00097 * \begin{bmatrix} 00098 * t_0 & x_{1,0} & x_{2,0} & ...\\ 00099 * t_1 & x_{1,1} & x_{2,1} & ...\\ 00100 * t_2 & x_{1,2} & x_{2,2} & ...\\ 00101 * . & . & . & . \\ 00102 * t_{final} & x_{1,f} & x_{2,f} & ... 00103 * \end{bmatrix} 00104 * \f] 00105 * where /f$t_T/f$ is the time at step T, and /f$x_{i,T}/f$ is the state value of element i, at time step T. 00106 */ 00107 Matrix RungeKuttaIntegrator::Integrate(const vector<ssfTime>& _propTime, odeFunctor _odeFunctorPtr, const Vector& _initialConditions, Orbit* _pOrbit, Attitude* _pAttitude, const Matrix& _constants, const Functor& _functorPtr) 00108 { 00109 vector<ssfTime> propTime = _propTime; // need to create copy to prevent the stl .begin() and .end() from discarding the const-ness 00110 vector<ssfTime>::iterator timeIterator = propTime.begin(); 00111 00112 ssfTime timeInitial = (*timeIterator); 00113 ssfTime t = timeInitial; 00114 timeIterator = propTime.end() - 1; 00115 double h = ((*timeIterator).GetSeconds() - timeInitial.GetSeconds()) / m_NumSteps; // Calculation step size (seconds) 00116 int numEqs = _initialConditions.getIndexCount(); 00117 Vector inputs = _initialConditions; 00118 Vector K1(numEqs); 00119 Vector K2(numEqs); 00120 Vector K3(numEqs); 00121 Vector K4(numEqs); 00122 00123 Matrix output(m_NumSteps + 1, numEqs + 1); 00124 00125 output(MatrixIndexBase,MatrixIndexBase) = timeInitial.GetSeconds(); 00126 output(MatrixIndexBase,_(MatrixIndexBase+1,MatrixIndexBase+numEqs)) = ~_initialConditions; 00127 ssfTime tTemp; 00128 Vector temp(numEqs); 00129 for (int ii = 1; ii <= m_NumSteps; ++ii) 00130 { 00131 K1 = h * _odeFunctorPtr(t, inputs, _pOrbit, _pAttitude, _constants, _functorPtr); 00132 temp = inputs + K1 / 2.0; tTemp = t + h/2; 00133 K2 = h * _odeFunctorPtr(tTemp, temp, _pOrbit, _pAttitude, _constants, _functorPtr); 00134 temp = inputs + K2 / 2.0; 00135 K3 = h * _odeFunctorPtr(tTemp, temp, _pOrbit, _pAttitude, _constants, _functorPtr); 00136 temp = inputs + K3; tTemp = t + h; 00137 K4 = h * _odeFunctorPtr(tTemp, temp, _pOrbit, _pAttitude, _constants, _functorPtr); 00138 for (int jj = MatrixIndexBase; jj < MatrixIndexBase + numEqs; ++jj) 00139 { 00140 inputs(jj) += (K1(jj) 00141 + 2.0 * K2(jj) 00142 + 2.0 * K3(jj) 00143 + K4(jj)) / 6.0; 00144 } 00145 t = timeInitial + ii * h; 00146 output(MatrixIndexBase + ii,MatrixIndexBase) = t.GetSeconds(); 00147 output(MatrixIndexBase + ii,_(MatrixIndexBase+1,MatrixIndexBase+numEqs)) = ~inputs; 00148 } 00149 return output; 00150 } 00151 } // close namespace O_SESSAME 00152 00153 // Do not change the comments below - they will be added automatically by CVS 00154 /***************************************************************************** 00155 * $Log: RungeKuttaIntegrator.cpp,v $ 00156 * Revision 1.1.1.1 2005/04/26 17:41:00 cakinli 00157 * Adding OpenSESSAME to DSACSS distrib to capture fixed version. 00158 * 00159 * Revision 1.7 2003/05/22 02:59:15 nilspace 00160 * Updated comments. Changed to pass in pointers to Orbit & Attitude objects. 00161 * 00162 * Revision 1.6 2003/05/13 18:58:27 nilspace 00163 * Cleaned up comments. 00164 * 00165 * Revision 1.5 2003/04/27 22:04:34 nilspace 00166 * Created the namespace O_SESSAME. 00167 * 00168 * Revision 1.4 2003/04/25 14:15:06 nilspace 00169 * Created a temporary vectro<ssfTime> to prevent the STL .begin() and .end() functions from discarding the const-ness of _propTime in Integrate(). 00170 * 00171 * Revision 1.3 2003/04/25 13:45:55 nilspace 00172 * const'd Get() functions. 00173 * 00174 * Revision 1.2 2003/04/23 16:30:59 nilspace 00175 * Various bugfixes & uploading of all changed code for new programmers. 00176 * 00177 * Revision 1.1 2003/04/08 22:29:55 nilspace 00178 * Initial submission. Made a subclass of Integrator. 00179 * 00180 * 00181 * 00182 ******************************************************************************/