Files
KSP-MGA-Planner/dist/dedicated-workers/trajectory-optimizer.js
2022-07-16 21:35:31 +02:00

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);