keplerian-core
Version:
High-performance TypeScript library for orbital mechanics calculations, providing numerical integration, state propagation, and perturbation modeling for Keplerian orbits.
84 lines (60 loc) • 2.8 kB
text/typescript
import { OrbitalState, InitialConditions, SimulationParams } from './types/physics';
import { rk4Integrator } from './physics/integrators/rk4';
import { eulerIntegrator } from './physics/integrators/euler';
import { leapfrogIntegrator } from './physics/integrators/leapfrog';
import { rk2Integrator } from './physics/integrators/rk2';
import { velocityVerletIntegrator } from './physics/integrators/velocity-verlet';
import { exportToCSV } from './utils/export';
import { calculateNetForce } from './physics/forces';
import { Vector2D } from './types/physics';
import { calculateDerivedQuantities } from './utils/calculateDerivedQuantities';
export function simulate(initialConditions: InitialConditions, params: SimulationParams, format: 'json' | 'csv' = 'json'): OrbitalState[] | string {
const states: OrbitalState[] = [];
let currentState: OrbitalState = {
position: initialConditions.position,
velocity: initialConditions.velocity,
momentum: { x: 0, y: 0 }, // Will be calculated by integrator
angularMomentum: 0, // Will be calculated by integrator
rungeLenzVector: { x: 0, y: 0 }, // Will be calculated by integrator
energy: 0, // Will be calculated by integrator
eccentricity: 0 // Will be calculated by integrator
};
// Initialize derived quantities for the initial state
// This is important for the first state in the array to have correct values
const accelerationFunction = (position: Vector2D, velocity: Vector2D, params: SimulationParams): Vector2D => {
const force = calculateNetForce(position, velocity, params);
return { x: force.x / params.orbitingMass, y: force.y / params.orbitingMass };
};
const derivedQuantities = calculateDerivedQuantities(currentState.position, currentState.velocity, params);
currentState = { ...currentState, ...derivedQuantities };
states.push(currentState);
let integratorFunction;
switch (params.integrator) {
case 'rk4':
integratorFunction = rk4Integrator.function;
break;
case 'euler':
integratorFunction = eulerIntegrator.function;
break;
case 'leapfrog':
integratorFunction = leapfrogIntegrator.function;
break;
case 'rk2':
integratorFunction = rk2Integrator.function;
break;
case 'velocity-verlet':
integratorFunction = velocityVerletIntegrator.function;
break;
default:
throw new Error(`Unknown integrator: ${params.integrator}`);
}
const numSteps = Math.ceil(params.totalTime / params.timeStep);
for (let i = 0; i < numSteps; i++) {
currentState = integratorFunction(currentState, params, accelerationFunction, i * params.timeStep, params.timeStep);
states.push(currentState);
}
if (format === 'csv') {
return exportToCSV(states);
}
return states;
}