keplerian-core
Version:
High-performance TypeScript library for orbital mechanics calculations, providing numerical integration, state propagation, and perturbation modeling for Keplerian orbits.
63 lines (62 loc) • 3.01 kB
JavaScript
export const dormandPrince = {
name: 'dormand-prince',
displayName: 'Dormand-Prince 5(4)',
description: 'Adaptive step-size Runge-Kutta method for high accuracy.',
order: 5,
recommended: true,
function: (initialState, params, accelerationFn, time, dt) => {
// Dormand-Prince 5(4) method coefficients
const a = [
[0],
[1 / 5],
[3 / 40, 9 / 40],
[44 / 45, -56 / 15, 32 / 9],
[19372 / 6561, -25360 / 2187, 64448 / 6561, -212 / 729],
[9017 / 3168, -355 / 33, 46732 / 5247, 49 / 176, -5103 / 18656],
[35 / 384, 0, 500 / 1113, 125 / 192, -2187 / 6784, 11 / 84]
];
const b = [
35 / 384, 0, 500 / 1113, 125 / 192, -2187 / 6784, 11 / 84, 0
];
const b_star = [
5179 / 57600, 0, 7571 / 16695, 393 / 640, -92097 / 339200, 187 / 2100, 1 / 40
];
const c = [0, 1 / 5, 3 / 10, 4 / 5, 8 / 9, 1, 1];
const k = Array(7).fill(null).map(() => [{ x: 0, y: 0 }, { x: 0, y: 0 }]);
const { position, velocity } = initialState;
// k1
k[0][0] = velocity;
k[0][1] = accelerationFn(position, velocity, params);
for (let i = 1; i < 7; i++) {
let pos_i = { x: position.x, y: position.y };
let vel_i = { x: velocity.x, y: velocity.y };
for (let j = 0; j < i; j++) {
pos_i.x += dt * a[i][j] * k[j][0].x;
pos_i.y += dt * a[i][j] * k[j][0].y;
vel_i.x += dt * a[i][j] * k[j][1].x;
vel_i.y += dt * a[i][j] * k[j][1].y;
}
k[i][0] = vel_i;
k[i][1] = accelerationFn(pos_i, vel_i, params);
}
let newPosition = { x: position.x, y: position.y };
let newVelocity = { x: velocity.x, y: velocity.y };
let newPosition_star = { x: position.x, y: position.y };
let newVelocity_star = { x: velocity.x, y: velocity.y };
for (let i = 0; i < 7; i++) {
newPosition.x += dt * b[i] * k[i][0].x;
newPosition.y += dt * b[i] * k[i][0].y;
newVelocity.x += dt * b[i] * k[i][1].x;
newVelocity.y += dt * b[i] * k[i][1].y;
newPosition_star.x += dt * b_star[i] * k[i][0].x;
newPosition_star.y += dt * b_star[i] * k[i][0].y;
newVelocity_star.x += dt * b_star[i] * k[i][1].x;
newVelocity_star.y += dt * b_star[i] * k[i][1].y;
}
// Error estimation (for adaptive step-size, not fully implemented here yet)
// const errorPos = { x: newPosition.x - newPosition_star.x, y: newPosition.y - newPosition_star.y };
// const errorVel = { x: newVelocity.x - newVelocity_star.x, y: newVelocity.y - newVelocity_star.y };
// const error = Math.sqrt(errorPos.x * errorPos.x + errorPos.y * errorPos.y + errorVel.x * errorVel.x + errorVel.y * errorVel.y);
return { position: newPosition, velocity: newVelocity };
}
};