//============================================================================ // // Ordinary differential equation solver using the Runge-Kutta method. // $Id$ // Copyright (C) 2004 Georg Drenkhahn // // This file is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License version 2 as published by the // Free Software Foundation. // //============================================================================ #ifndef RKODESOLVER_H #define RKODESOLVER_H // STL headers #include /** @brief Solver class to integrate a first-order ordinary differential * equation (ODE) by means of a 6. order Runge-Kutta method. * * The ODE system must be given as the derivative * dy/dx = f(x,y) * with x in R and y in R^n. * * Within this class the function f() is a pure virtual function, which must be * reimplemented in a derived class. * * No other special data type for vectors or matrices are needed besides the STL * class std::valarray. */ template class RkOdeSolver { public: /** @brief Constructor * @param x Initial integration parameter * @param y Initial function values of function to integrate * @param dx Initial guess for step size. Will be automatically adjusted to * guarantee required precision. * @param eps Relative precision * * Initialises the solver with start conditions. */ RkOdeSolver(const T& x=0.0, const std::valarray& y=std::valarray(0), const T& dx=0, const T& eps=1e-6); /** @brief Destructor */ virtual ~RkOdeSolver(void); /** @brief Integrates the ordinary differential equation from the current x * value to x+@a dx. * @param dx x-interval size to integrate over starting from x. dx may be * negative. * * The integration is performed by calling rkStepCheck() repeatedly until the * desired x value is reached. */ void integrate(const T& dx); // Accessors // get/set x value /** @brief Get current x value. * @return Reference of x value. */ const T& X(void) const; /** @brief Set current x value. * @param a The value to be set. */ void X(const T& a); // get/set y value /** @brief Get current y value. * @return Reference of y vector. */ const std::valarray& Y(void) const; /** @brief Set current y values. * @param a The vector to be set. */ void Y(const std::valarray& a); /** @brief Get current dy/dx value. * @return Reference of dy/dx vector. */ const std::valarray& dYdX(void) const; // get/set dx value /** @brief Get current estimated step size dX. * @return Reference of dX value. */ const T& dX(void) const; /** @brief Set estimated step size dX. * @param a The value to be set. */ void dX(const T& a); // get/set eps value /** @brief Get current presision. * @return Reference of precision value. */ const T& Eps(void) const; /** @brief Set estimated presision. * @param a The value to be set. */ void Eps(const T& a); protected: // purely virtual function which is integrated /** @brief ODE function * @param x Integration value * @param y Function value * @return Derivation * * This purely virtual function returns the value of dy/dx for the given * parameter values of x and y. */ virtual std::valarray f(const T& x, const std::valarray& y) const = 0; private: /** @brief Perform one integration step with a tolerable relative error given * by ::mErr. * @param dx Maximal step size, may be positive or negative depending on * integration direction. * @return Flag indicating if made absolute integration step was equal |@a dx * | (true) less than |@a dx | (false). * * A new estimate for the maximum next step size is saved to ::mStep. The * new values for x, y and f are saved in ::mX, ::mY and ::mDydx. */ bool rkStepCheck(const T& dx); /** @brief Perform one Runge-Kutta integration step forward with step size * ::mStep * @param dx Step size relative to current x value. * @param yerr Reference to vector in which the estimated error made in y is * returned. * @return The y value after the step at x+@a dx. * * Stored current x,y values are not adjusted. */ std::valarray rkStep(const T& dx, std::valarray& yerr) const; /** current x value */ T mX; /** current y value */ std::valarray mY; /** current value of dy/dx */ std::valarray mDydx; /** allowed relative error */ T mEps; /** estimated step size for next Runge-Kutta step */ T mStep; }; // inline accessors template inline const T& RkOdeSolver::X(void) const { return mX; } template inline void RkOdeSolver::X(const T &a) { mX = a; } template inline const std::valarray& RkOdeSolver::Y(void) const { return mY; } template inline const std::valarray& RkOdeSolver::dYdX(void) const { return mDydx; } template inline const T& RkOdeSolver::dX(void) const { return mStep; } template inline const T& RkOdeSolver::Eps(void) const { return mEps; } #endif