mirror of
https://github.com/Krafpy/KSP-MGA-Planner.git
synced 2025-12-12 23:59:59 -08:00
107 lines
4.3 KiB
JavaScript
107 lines
4.3 KiB
JavaScript
"use strict";
|
|
importScripts("libs/common.js", "libs/trajectory-calculator.js", "libs/evolution.js", "libs/math.js", "libs/physics-3d.js", "libs/lambert.js", "libs/utils.js");
|
|
class TrajectoryOptimizer extends WorkerEnvironment {
|
|
constructor() {
|
|
super(...arguments);
|
|
this._newDeltaVs = [];
|
|
this._deltaVs = [];
|
|
}
|
|
onWorkerInitialize(data) {
|
|
this._config = data.config;
|
|
this._system = data.system;
|
|
this._bodiesOrbits = [null];
|
|
for (let i = 1; i < this._system.length; i++) {
|
|
const data = this._system[i].orbit;
|
|
const orbit = Physics3D.orbitElementsFromOrbitData(data);
|
|
this._bodiesOrbits.push(orbit);
|
|
}
|
|
}
|
|
onWorkerDataPass(data) {
|
|
this._depAltitude = data.depAltitude;
|
|
this._destAltitude = data.destAltitude;
|
|
this._sequence = data.sequence;
|
|
this._startDateMin = data.startDateMin;
|
|
this._startDateMax = data.startDateMax;
|
|
}
|
|
onWorkerRun(input) {
|
|
this._newDeltaVs = [];
|
|
if (input.start) {
|
|
const numLegs = this._sequence.length - 1;
|
|
const agentDim = 3 + numLegs * 4 - 2;
|
|
const fitness = (agent) => {
|
|
const trajectory = this._computeTrajectory(agent);
|
|
if (trajectory.totalDeltaV < this._bestDeltaV) {
|
|
this._bestDeltaV = trajectory.totalDeltaV;
|
|
this._bestTrajectory = trajectory;
|
|
}
|
|
const lastIdx = trajectory.steps.length - 1;
|
|
const finalOrbit = trajectory.steps[lastIdx].orbitElts;
|
|
const totDV = trajectory.totalDeltaV;
|
|
this._newDeltaVs.push(totDV);
|
|
const lastInc = Math.abs(finalOrbit.inclination);
|
|
return totDV + totDV * lastInc * 0.1;
|
|
};
|
|
const trajConfig = this._config.trajectorySearch;
|
|
const { diffWeight } = trajConfig;
|
|
const { minCrossProba, maxCrossProba } = trajConfig;
|
|
const { crossProbaIncr, maxGenerations } = trajConfig;
|
|
const { chunkStart, chunkEnd } = input;
|
|
const evolSettings = {
|
|
maxGens: maxGenerations,
|
|
agentDim, fitness,
|
|
crInc: crossProbaIncr,
|
|
crMin: minCrossProba,
|
|
crMax: maxCrossProba,
|
|
f: diffWeight,
|
|
};
|
|
this._evolver = new Evolution.ChunkedEvolver(chunkStart, chunkEnd, evolSettings);
|
|
this._bestDeltaV = Infinity;
|
|
this._evolver.createRandomPopulationChunk();
|
|
this._evolver.evaluateChunkFitness();
|
|
this._deltaVs = [...this._newDeltaVs];
|
|
}
|
|
else {
|
|
const { population, fitnesses } = input;
|
|
const updated = this._evolver.evolvePopulationChunk(population, fitnesses);
|
|
for (const i of updated) {
|
|
this._deltaVs[i] = this._newDeltaVs[i];
|
|
}
|
|
}
|
|
this._bestTrajectory.computeStartingMeanAnomalies();
|
|
sendResult({
|
|
popChunk: this._evolver.popChunk,
|
|
fitChunk: this._evolver.fitChunk,
|
|
dVsChunk: this._deltaVs,
|
|
bestSteps: this._bestTrajectory.steps,
|
|
bestDeltaV: this._bestDeltaV
|
|
});
|
|
}
|
|
_computeTrajectory(agent, maxAttempts = 1000) {
|
|
const trajConfig = this._config.trajectorySearch;
|
|
const trajectory = new TrajectoryCalculator(this._system, trajConfig, this._sequence);
|
|
trajectory.addPrecomputedOrbits(this._bodiesOrbits);
|
|
let attempts = 0;
|
|
while (attempts < maxAttempts) {
|
|
trajectory.setParameters(this._depAltitude, this._destAltitude, this._startDateMin, this._startDateMax, agent);
|
|
let failed = false;
|
|
try {
|
|
trajectory.compute();
|
|
trajectory.recomputeLegsSecondArcs();
|
|
}
|
|
catch {
|
|
failed = true;
|
|
}
|
|
if (failed || Utils.hasNaN(trajectory.steps)) {
|
|
Evolution.randomizeAgent(agent);
|
|
trajectory.reset();
|
|
}
|
|
else {
|
|
return trajectory;
|
|
}
|
|
attempts++;
|
|
}
|
|
throw new Error("Impossible to compute the trajectory.");
|
|
}
|
|
}
|
|
WorkerEnvironment.init(TrajectoryOptimizer);
|