package com.dwave.math; /** * Runge-Kutta methods propagate a solution over an interval by combining the * information from several Euler-sytle steps(each involving one evaluation of * the right-hand f's), and then using the information obtained to match * a Taylor series expansion up to some higher order. *
* Translated to Java directly from Numerical Recipes in C.
*/
public final class RungeKutta {
private final static float
a2 = 0.2f,
a3 = 0.3f,
a4 = 0.6f,
a5 = 1.0f,
a6 = 0.875f,
b21 = 0.2f,
b31 = 0.075f,
b32 = 0.225f,
b41 = 0.3f,
b42 = -0.9f,
b43 = 1.2f,
b51 = -11.0f / 54.0f,
b52 = 2.5f,
b53 = -70.0f / 27.0f,
b54 = 35.0f / 27.0f,
b61 = 1631.0f / 55296.0f,
b62 = 175.0f / 512.0f,
b63 = 575.0f / 13824.0f,
b64 = 44275.0f / 110592.0f,
b65 = 253.0f / 4096.0f,
c1 = 37.0f / 378.0f,
c3 = 250.0f / 621.0f,
c4 = 125.0f / 594.0f,
c6 = 512.0f / 1771.0f,
dc5 = -277.0f / 14336.0f;
static long totalTime = 0L;
/**
* Private constructor to guard against instantiation
*/
private RungeKutta() {}
//////////////////////////////
///// ALGORITHM ROUTINES /////
//////////////////////////////
/**
* Given values for the variables y[1...n] and their derivatives dydk[1..n] known at x, use
* the fourth-order Runge-Kutta method to advance the solution over an interval h and
* return the incremented variables as yout[1..n], which need not be a distinct array from y.
* The user supplies the routine dervis(x,y,dydx), which returns derivatives dydx at x.
*
* @param y psi
* @param dydx derivative first order terms
* @param x time
* @param h stepsize
* @param yout output
* @param derivs method for calculating the derivative
*/
public static boolean rk4(float y[],float dydx[],float x,
float h,float yout[],ODEInterface derivs) {
if(y.length != dydx.length || y.length != yout.length) {
System.out.println("RK.rk4: error");
System.out.println("RK.rk4: y.length " + y.length);
System.out.println("RK.rk4: dydx.length " + dydx.length);
System.out.println("RK.rk4: yout.length " + yout.length);
return false;
}
int i;
float xh, hh, h6, dym[], dyt[], yt[];
dym = new float[y.length];
dyt = new float[y.length];
yt = new float[y.length];
hh = 0.5f * h;
h6 = h / 6.0f;
xh = x + hh;
for (i=0;i
* [NOTE] User storage for intermediate results: preset kmax (can be 0) and dxsav in the calling
* program. if kmax != 0 results are stored at approximate intervals dxsav in the array xp[1..kount],
* yp[1..ystart.length][1..kount], where kount is output by odeint. Defining declarations for
* these variables should be in the calling program.
*
* @param ystart psi
* @param x1 initial time
* @param x2 finishing time
* @param eps accuracy
* @param h1 guessed first step size
* @param hmin minimum stepsize allowed
* @param nok number of good steps
* @param nbad number of bad steps
* @param kmax number of step to be stored
* @param dxsav approximate storage interval
* @param derivs mehtod for calculating the derivative
*/
public static boolean odeint(float[] ystart,float x1,float x2,float eps,
float h1,float hmin,int[] nok,int[] nbad,
int kmax, float dxsav, ODEInterface derivs) {
float xsav, h;
float[] yscal, y, dydx, xp, x, hnext, hdid;
int MAXSTEP = 10000,
KMAXX = 200,
kount = 0;
float TINY = 1.0e-30f;
if(kmax == 0)
kmax = KMAXX;
x = new float[1];
hnext = new float[1];
hdid = new float[1];
yscal = new float[ystart.length];
y = new float[ystart.length];
dydx = new float[ystart.length];
xp = new float[kmax];
x[0] = x1;
h = (x2 > x1) ? Math.abs(h1) : -Math.abs(h1);
nok[0] = nbad[0] = 0;
for(int i = 0; i < ystart.length; i++)
y[i] = ystart[i];
// if(kmax > 0)
xsav = x[0] - dxsav * 2.0f;
// else
// xsav = 0;
for(int nstep = 0; nstep < MAXSTEP; nstep++) {
derivs.deriv(x[0], y, dydx);
for(int i = 0; i < ystart.length; i++)
yscal[i] = Math.abs(y[i]) + Math.abs(dydx[i] * h) + TINY;
if(kmax > 0 && kount < kmax - 1 && Math.abs(x[0] - xsav) > Math.abs(dxsav)) {
xp[kount++] = x[0];
xsav = x[0];
}
if((x[0] + h - x2) * (x[0] + h - x1) > 0.0f)
h = x2 - x[0];
rkqs(y, dydx, x, h, eps, yscal, hdid, hnext, derivs);
if(hdid[0] == h)
nok[0]++;
else
nbad[0]++;
if((x[0] - x2) * (x2 - x1) >= 0.0f) {
for(int i = 0; i < ystart.length; i++)
ystart[i] = y[i];
if(kmax > 0) {
xp[kount++] = x[0];
}
return true;
}
if(Math.abs(hnext[0]) <= hmin) {
System.out.println("Step size too small in odeint");
return false;
}
h = hnext[0];
}
System.out.println("Too many steps in routine odeint");
return false;
}
}