Files
KSP-MGA-Planner/dist/dedicated-workers/trajectory-optimizer.js
2021-12-24 17:35:12 +01:00

105 lines
4.0 KiB
JavaScript

"use strict";
importScripts("libs/common.js", "libs/evolution.js", "libs/math.js", "libs/physics-3d.js", "libs/lambert.js", "libs/trajectory-calculator.js");
class TrajectoryOptimizer extends WorkerEnvironment {
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._sequence = data.sequence;
this._startDateMin = data.startDateMin;
this._startDateMax = data.startDateMax;
}
onWorkerRun(input) {
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;
}
return trajectory.totalDeltaV;
};
const trajConfig = this._config.trajectorySearch;
const { crossoverProba, diffWeight } = trajConfig;
const { chunkStart, chunkEnd } = input;
this._evolver = new ChunkedEvolver(chunkStart, chunkEnd, agentDim, fitness, crossoverProba, diffWeight);
this._bestDeltaV = Infinity;
const popChunk = this._evolver.createRandomPopulationChunk();
const dvChunk = this._evolver.evaluateChunkFitness(popChunk);
sendResult({
bestSteps: this._bestTrajectory.steps,
bestDeltaV: this._bestDeltaV,
fitChunk: dvChunk,
popChunk: popChunk,
});
}
else {
const { population, deltaVs } = input;
const { popChunk, fitChunk } = this._evolver.evolvePopulationChunk(population, deltaVs);
sendResult({
popChunk, fitChunk,
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._startDateMin, this._startDateMax, agent);
let failed = false;
try {
trajectory.compute();
trajectory.recomputeLegsSecondArcs();
}
catch {
failed = true;
}
if (failed || this._hasNaNValuesInSteps(trajectory)) {
this._evolver.randomizeAgent(agent);
trajectory.reset();
}
else {
return trajectory;
}
attempts++;
}
throw new Error("Impossible to compute the trajectory.");
}
_hasNaNValuesInSteps(trajectory) {
const hasNaN = obj => {
for (const value of Object.values(obj)) {
if (typeof value == "object") {
if (hasNaN(value))
return true;
}
else if (typeof value == "number") {
if (isNaN(value))
return true;
}
}
return false;
};
const { steps } = trajectory;
for (let i = steps.length - 1; i >= 0; i--) {
if (hasNaN(steps[i]))
return true;
}
return false;
}
}
WorkerEnvironment.init(TrajectoryOptimizer);