Runge-Kutta in C++

 

In my previous post, I went through the benefits of using Runge-Kutta for numerical solving of differential equations. Now, a sample implementation.

Here, F is some type that supports addition and scalar multiplication. In mathematics terms, F is a vector space. The simplest form could be a float or a double. For more complicated differential equations, F could be a three-dimensional point, for example.

D is some function or functor that can be called, returning the derivative of the system. Rather than using a second template parameter, this could be replaced by either std::function<F(const F&,double)> derivative or F (*derivative)(const F&,double). However, the first introduces some overhead, and the second is less general. Since I am already templating on F, I might as well template on D as well.

template<typename F, typename D>
class RungeKutta{
public:
	RungeKutta(F initial, D derivative,
	           double deltaT, double start_time=0){
		m_current = initial;
		m_der = derivative;
		m_deltaT = deltaT;
		m_time = start_time;
	}

	void Step(double dT){
		F k1 = m_der(m_current, m_time)*dT;
		F k2 = m_der(m_current + 0.5*k1, m_time + 0.5*dT)*dT;
		F k3 = m_der(m_current + 0.5*k2, m_time + 0.5*dT)*dT;
		F k4 = m_der(m_current + k3, m_time + dT)*dT;
		m_current = m_current + (k1 + k2*2 + k3*2 + k4) * (1.0/6.0);
		m_time += dT;
	}

	void Step(){ Step(m_deltaT); }
	F GetCurrent(){ return m_current; }
	double GetTime(){ return m_time; }

private:
	F m_current;
	D m_der;
	double m_deltaT;
	double m_time;
};

This assumes that the following functions are available for F and D.

F operator+ (const F&, const F&);
F operator* (const F&, double);
class D{
	F operator() (const F&, double);
};