Files
KSP-MGA-Planner/dist/dedicated-workers/trajectory-optimizer.js
Krafpy 8da935b047 2D physics fix and error handling consistency
- Reimplemented 2D orbital mechanics functions in physics-2d.ts
and encaspulated inside a `Physics2D` namespace.
- Deleted physics.ts and moved the required functions into physics-3d.ts
Further cleaning and reimplemntation will be done on the physics-3d.ts
content.
- Forced consistency on error handling : every raised error throws
an `Error` object.
- Commented sections relative to 2D physics and sequence generation.
2021-12-19 17:19:30 +01:00

113 lines
4.6 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;
}
onWorkerDataPass(data) {
this._depAltitude = data.depAltitude;
this._sequence = data.sequence;
this._startDateMin = data.startDateMin;
this._startDateMax = data.startDateMax;
}
onWorkerRun(input) {
const evaluate = (params) => this._evaluate(params);
if (input.start) {
this._bestDeltaV = Infinity;
const chunkSize = input.chunkEnd - input.chunkStart + 1;
const popChunk = this._createRandomMGAPopulationChunk(chunkSize);
const dvChunk = populationChunkFitness(popChunk, evaluate);
sendResult({
bestSteps: this._bestSteps,
bestDeltaV: this._bestDeltaV,
fitChunk: dvChunk,
popChunk: popChunk,
});
}
else {
const { crossoverProba, diffWeight } = this._config.trajectorySearch;
const results = evolvePopulationChunk(input.population, input.deltaVs, input.chunkStart, input.chunkEnd, crossoverProba, diffWeight, evaluate);
sendResult({
...results,
bestSteps: this._bestSteps,
bestDeltaV: this._bestDeltaV
});
}
}
_evaluate(params) {
const trajectory = this._computeTrajectory(params);
if (trajectory.totalDeltaV < this._bestDeltaV) {
this._bestDeltaV = trajectory.totalDeltaV;
this._bestSteps = trajectory.steps;
}
return trajectory.totalDeltaV;
}
;
_computeTrajectory(params) {
const calculate = () => {
const trajectory = new TrajectoryCalculator(this._system, this._config.trajectorySearch, this._sequence);
trajectory.setParameters(this._depAltitude, this._startDateMin, this._startDateMax, params);
trajectory.compute();
return trajectory;
};
let trajectory = calculate();
while (!trajectory.noError) {
this._randomizeExistingAgent(params);
trajectory = calculate();
}
return trajectory;
}
_createRandomMGAPopulationChunk(chunkSize) {
const popChunk = [];
for (let i = 0; i < chunkSize; i++) {
popChunk.push(this._createRandomMGAAgent());
}
return popChunk;
}
_createRandomMGAAgent() {
const dim = 4 * (this._sequence.length - 1) + 2;
const solution = Array(dim).fill(0);
solution[0] = randomInInterval(this._startDateMin, this._startDateMax);
solution[1] = randomInInterval(1, 3);
for (let i = 1; i < this._sequence.length; i++) {
const j = 2 + (i - 1) * 4;
const { legDuration, dsmOffset } = this._legDurationAndDSM(i);
solution[j] = legDuration;
solution[j + 1] = dsmOffset;
const { theta, phi } = randomPointOnSphereRing(0, Math.PI / 2);
solution[j + 2] = theta;
solution[j + 3] = phi;
}
return solution;
}
_randomizeExistingAgent(agent) {
const newAgent = this._createRandomMGAAgent();
for (let i = 0; i < agent.length; i++) {
agent[i] = newAgent[i];
}
}
_legDurationAndDSM(index) {
const isResonant = this._sequence[index - 1] == this._sequence[index];
const { dsmOffsetMin, dsmOffsetMax } = this._config.trajectorySearch;
if (isResonant) {
const sideralPeriod = this._system[this._sequence[index]].orbit.sideralPeriod;
const revs = randomInInterval(1, 4);
const legDuration = revs * sideralPeriod;
const minOffset = clamp((revs - 1) / revs, dsmOffsetMin, dsmOffsetMax);
const dsmOffset = randomInInterval(minOffset, dsmOffsetMax);
return { legDuration, dsmOffset };
}
else {
const body1 = this._system[this._sequence[index - 1]];
const body2 = this._system[this._sequence[index]];
const attractor = this._system[body1.orbiting];
const period = getHohmannPeriod(body1, body2, attractor);
const legDuration = randomInInterval(0.1, 1) * period;
const dsmOffset = randomInInterval(dsmOffsetMin, dsmOffsetMax);
return { legDuration, dsmOffset };
}
}
}
initWorker(TrajectoryOptimizer);