public static ManeuverParameters OptimizeEjection(ManeuverParameters original_maneuver, Orbit initial_orbit, Orbit target, double UT_arrival) { alglib.minlmstate state; alglib.minlmreport rep; double[] x = new double[4]; double[] scale = new double[4]; x[0] = original_maneuver.dV.x; x[1] = original_maneuver.dV.y; x[2] = original_maneuver.dV.z; x[3] = 0; scale[0] = scale[1] = scale[2] = original_maneuver.dV.magnitude; scale[3] = initial_orbit.period; OptimizerData data = new OptimizerData(); data.initial_orbit = initial_orbit; data.original_UT = original_maneuver.UT; data.UT_arrival = UT_arrival; data.pos_arrival = target.getTruePositionAtUT(UT_arrival); alglib.minlmcreatev(3, x, 0.01, out state); alglib.minlmsetcond(state, 0, 0, 0, 50); alglib.minlmsetscale(state, scale); alglib.minlmoptimize(state, DistanceToTarget, null, data); alglib.minlmresults(state, out x, out rep); return(new ManeuverParameters(new Vector3d(x[0], x[1], x[2]), original_maneuver.UT + x[3])); }
public static ManeuverParameters OptimizeEjection(ManeuverParameters original_maneuver, Orbit initial_orbit, Orbit target, double UT_arrival, double earliest_UT) { int N = 0; while (true) { alglib.minlmstate state; alglib.minlmreport rep; double[] x = new double[5]; double[] scale = new double[5]; x[0] = original_maneuver.dV.x; x[1] = original_maneuver.dV.y; x[2] = original_maneuver.dV.z; x[3] = original_maneuver.UT + N * initial_orbit.period; x[4] = UT_arrival; scale[0] = scale[1] = scale[2] = original_maneuver.dV.magnitude; scale[3] = initial_orbit.period; scale[4] = target.period / 4.0; OptimizerData data = new OptimizerData(); data.initial_orbit = initial_orbit; data.target_orbit = target; alglib.minlmcreatev(6, x, 0.001, out state); double epsx = 1e-16; // stop if |(x(k+1)-x(k)) ./ scale| <= EpsX double epsf = 1e-16; // stop if |F(k+1)-F(k)| <= EpsF*max{|F(k)|,|F(k+1)|,1} alglib.minlmsetcond(state, 0, epsf, epsx, 50); alglib.minlmsetscale(state, scale); alglib.minlmoptimize(state, DistanceToTarget, null, data); alglib.minlmresults(state, out x, out rep); Debug.Log("Transfer calculator: termination type=" + rep.terminationtype); Debug.Log("Transfer calculator: iteration count=" + rep.iterationscount); // try again in one orbit if the maneuver node is in the past if (x[3] < earliest_UT) { Debug.Log("Transfer calculator: maneuver is " + (earliest_UT - x[3]) + " s too early, trying again in " + initial_orbit.period + " s"); N++; } else { Debug.Log("from optimizer DV = " + Math.Sqrt(Math.Pow(x[0], 2.0) + Math.Pow(x[1], 2.0) + Math.Pow(x[2], 2.0))); return(new ManeuverParameters(new Vector3d(x[0], x[1], x[2]), x[3])); } } }
public static ManeuverParameters OptimizeEjection(ManeuverParameters original_maneuver, Orbit initial_orbit, Orbit target, double UT_arrival, double earliest_UT) { while (true) { alglib.minlmstate state; alglib.minlmreport rep; double[] x = new double[4]; double[] scale = new double[4]; x[0] = original_maneuver.dV.x; x[1] = original_maneuver.dV.y; x[2] = original_maneuver.dV.z; x[3] = 0; scale[0] = scale[1] = scale[2] = original_maneuver.dV.magnitude; scale[3] = initial_orbit.period; OptimizerData data = new OptimizerData(); data.initial_orbit = initial_orbit; data.original_UT = original_maneuver.UT; data.UT_arrival = UT_arrival; data.pos_arrival = target.getTruePositionAtUT(UT_arrival); alglib.minlmcreatev(4, x, 0.01, out state); double epsx = 1e-4; // stop if |(x(k+1)-x(k)) ./ scale| <= EpsX double epsf = 0.01; // stop if |F(k+1)-F(k)| <= EpsF*max{|F(k)|,|F(k+1)|,1} alglib.minlmsetcond(state, 0, epsf, epsx, 50); alglib.minlmsetscale(state, scale); alglib.minlmoptimize(state, DistanceToTarget, null, data); alglib.minlmresults(state, out x, out rep); Debug.Log("Transfer calculator: termination type=" + rep.terminationtype); Debug.Log("Transfer calculator: iteration count=" + rep.iterationscount); // try again in one orbit if the maneuver node is in the past if (original_maneuver.UT + x[3] < earliest_UT) { Debug.Log("Transfer calculator: maneuver is " + (earliest_UT - original_maneuver.UT - x[3]) + " s too early, trying again in " + initial_orbit.period + " s"); original_maneuver.UT += initial_orbit.period; } else { return(new ManeuverParameters(new Vector3d(x[0], x[1], x[2]), original_maneuver.UT + x[3])); } } }
private void JobFinished() { int remaining = Interlocked.Decrement(ref pendingJobs); if (remaining == 0) { for (int date_index = 0; date_index < dateSamples; date_index++) { int n = DurationSamplesForDate(date_index); for (int duration_index = 0; duration_index < n; duration_index++) { if (computed[bestDate, bestDuration] == null || (computed[date_index, duration_index] != null && IsBetter(bestDate, bestDuration, date_index, duration_index))) { bestDate = date_index; bestDuration = duration_index; } } } arrivalDate = DateFromIndex(bestDate) + DurationFromIndex(bestDuration); result = computed[bestDate, bestDuration]; pendingJobs = -1; #if DEBUG string dir = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); var f = System.IO.File.CreateText(dir + "/DeltaVWorking.csv"); f.WriteLine(originOrbit.referenceBody.referenceBody.gravParameter); for (int date_index = 0; date_index < dateSamples; date_index++) { int n = DurationSamplesForDate(date_index); for (int duration_index = 0; duration_index < n; duration_index++) { f.WriteLine(log[date_index, duration_index]); } } #endif } }
public List <ManeuverParameters> OptimizeEjection(double UT_transfer, Orbit initial_orbit, Orbit target, CelestialBody target_body, double UT_arrival, double earliest_UT, double target_PeR, bool includeCaptureBurn) { int N = 0; List <ManeuverParameters> NodeList = new List <ManeuverParameters>(); while (true) { const double DIFFSTEP = 1e-6; const double EPSX = 1e-9; const int MAXITS = 100; alglib.minlmstate state; alglib.minlmreport rep; double[] x = new double[3]; double[] scale = new double[3]; Vector3d exitDV, captureDV; CalcLambertDVs(UT_transfer, UT_arrival - UT_transfer, out exitDV, out captureDV); Orbit source = initial_orbit.referenceBody.orbit; // helicentric orbit of the source planet // helicentric transfer orbit Orbit transfer_orbit = new Orbit(); transfer_orbit.UpdateFromStateVectors(source.getRelativePositionAtUT(UT_transfer), source.getOrbitalVelocityAtUT(UT_transfer) + exitDV, source.referenceBody, UT_transfer); double UT_SOI_exit; OrbitalManeuverCalculator.SOI_intercept(transfer_orbit, initial_orbit.referenceBody, UT_transfer, UT_arrival, out UT_SOI_exit); // convert from heliocentric to body centered velocity Vector3d Vsoi = transfer_orbit.getOrbitalVelocityAtUT(UT_SOI_exit) - initial_orbit.referenceBody.orbit.getOrbitalVelocityAtUT(UT_SOI_exit); // find the magnitude of Vinf from energy double Vsoi_mag = Vsoi.magnitude; double E_h = Vsoi_mag * Vsoi_mag / 2 - initial_orbit.referenceBody.gravParameter / initial_orbit.referenceBody.sphereOfInfluence; double Vinf_mag = Math.Sqrt(2 * E_h); // scale Vsoi by the Vinf magnitude (this is now the Vinf target that will yield Vsoi at the SOI interface, but in the Vsoi direction) Vector3d Vinf = Vsoi / Vsoi.magnitude * Vinf_mag; // using Vsoi seems to work slightly better here than the Vinf from the heliocentric computation at UT_Transfer //ManeuverParameters maneuver = ComputeEjectionManeuver(Vsoi, initial_orbit, UT_transfer, true); ManeuverParameters maneuver = ComputeEjectionManeuver(Vinf, initial_orbit, UT_transfer, true); // // common setup for the optimization problems // x[0] = maneuver.dV.x; x[1] = maneuver.dV.y; x[2] = maneuver.dV.z; UT_transfer = maneuver.UT; scale[0] = scale[1] = scale[2] = 1000.0f; // // initial patched conic shooting to precisely hit the target // const int ZEROMISSCONS = 3; double[] fi = new double[ZEROMISSCONS]; zeroMissObjectiveFunction(x, fi, null, initial_orbit, target_body, UT_transfer, UT_arrival); Debug.Log("zero miss phase before optimization = " + new Vector3d(fi[0], fi[1], fi[2]).magnitude + " m (" + new Vector3d(x[0], x[1], x[2]).magnitude + " m/s)"); alglib.minlmcreatev(3, ZEROMISSCONS, x, DIFFSTEP, out state); alglib.minlmsetcond(state, EPSX, MAXITS); alglib.minlmsetscale(state, scale); alglib.minlmoptimize(state, (x, fi, obj) => zeroMissObjectiveFunction(x, fi, obj, initial_orbit, target_body, UT_transfer, UT_arrival), null, null); alglib.minlmresults(state, out x, out rep); zeroMissObjectiveFunction(x, fi, null, initial_orbit, target_body, UT_transfer, UT_arrival); Debug.Log("zero miss phase after optimization = " + new Vector3d(fi[0], fi[1], fi[2]).magnitude + " m (" + new Vector3d(x[0], x[1], x[2]).magnitude + " m/s)"); Debug.Log("Transfer calculator: termination type=" + rep.terminationtype); Debug.Log("Transfer calculator: iteration count=" + rep.iterationscount); // // Fine tuning of the periapsis // bool failed = false; if (target_PeR > 0) { const int PERIAPSISCONS = 1; double[] fi2 = new double[PERIAPSISCONS]; periapsisObjectiveFunction(x, fi2, null, initial_orbit, target_body, UT_transfer, UT_arrival, target_PeR, ref failed); Debug.Log("periapsis phase before optimization = " + fi2[0] + " m (" + new Vector3d(x[0], x[1], x[2]).magnitude + " m/s)"); alglib.minlmcreatev(3, PERIAPSISCONS, x, DIFFSTEP, out state); alglib.minlmsetcond(state, EPSX, MAXITS); alglib.minlmsetscale(state, scale); alglib.minlmoptimize(state, (x, fi, obj) => periapsisObjectiveFunction(x, fi, obj, initial_orbit, target_body, UT_transfer, UT_arrival, target_PeR, ref failed), null, null); alglib.minlmresults(state, out x, out rep); periapsisObjectiveFunction(x, fi2, null, initial_orbit, target_body, UT_transfer, UT_arrival, target_PeR, ref failed); Debug.Log("periapsis phase after optimization = " + fi2[0] + " m (" + new Vector3d(x[0], x[1], x[2]).magnitude + " m/s)"); Debug.Log("Transfer calculator: termination type=" + rep.terminationtype); Debug.Log("Transfer calculator: iteration count=" + rep.iterationscount); } maneuver.dV.x = x[0]; maneuver.dV.y = x[1]; maneuver.dV.z = x[2]; // // exit conditions and error handling // // try again if we failed to intersect the target orbit if (failed) { Debug.Log("Failed to intersect target orbit"); } // try again in one orbit if the maneuver node is in the past else if (maneuver.UT < earliest_UT || failed) { Debug.Log("Transfer calculator: maneuver is " + (earliest_UT - maneuver.UT) + " s too early, trying again in " + initial_orbit.period + " s"); UT_transfer += initial_orbit.period; } else { Debug.Log("from optimizer DV = " + maneuver.dV + " t = " + maneuver.UT + " original arrival = " + UT_arrival); NodeList.Add(maneuver); break; } if (N++ > 10) { throw new OperationException("Ejection Optimization failed; try manual selection"); } } if (NodeList.Count > 0 && target_PeR > 0 && includeCaptureBurn) { // calculate the incoming orbit Orbit incoming_orbit; OrbitalManeuverCalculator.PatchedConicInterceptBody(initial_orbit, target_body, NodeList[0].dV, NodeList[0].UT, UT_arrival, out incoming_orbit); double burnUT = incoming_orbit.NextPeriapsisTime(incoming_orbit.StartUT); NodeList.Add(new ManeuverParameters(OrbitalManeuverCalculator.DeltaVToCircularize(incoming_orbit, burnUT), burnUT)); } return(NodeList); }
public static ManeuverParameters OptimizeEjection(ManeuverParameters original_maneuver, Orbit initial_orbit, Orbit target, double UT_arrival, double earliest_UT) { while(true) { alglib.minlmstate state; alglib.minlmreport rep; double[] x = new double[4]; double[] scale = new double[4]; x[0] = original_maneuver.dV.x; x[1] = original_maneuver.dV.y; x[2] = original_maneuver.dV.z; x[3] = 0; scale[0] = scale[1] = scale[2] = original_maneuver.dV.magnitude; scale[3] = initial_orbit.period; OptimizerData data = new OptimizerData(); data.initial_orbit = initial_orbit; data.original_UT = original_maneuver.UT; data.UT_arrival = UT_arrival; data.pos_arrival = target.getTruePositionAtUT(UT_arrival); alglib.minlmcreatev(4, x, 0.01, out state); double epsx = 1e-4; // stop if |(x(k+1)-x(k)) ./ scale| <= EpsX double epsf = 0.01; // stop if |F(k+1)-F(k)| <= EpsF*max{|F(k)|,|F(k+1)|,1} alglib.minlmsetcond(state, 0, epsf, epsx, 50); alglib.minlmsetscale(state, scale); alglib.minlmoptimize(state, DistanceToTarget, null, data); alglib.minlmresults(state, out x, out rep); Debug.Log("Transfer calculator: termination type=" + rep.terminationtype); Debug.Log("Transfer calculator: iteration count=" + rep.iterationscount); // try again in one orbit if the maneuver node is in the past if (original_maneuver.UT + x[3] < earliest_UT) { Debug.Log("Transfer calculator: maneuver is " + (earliest_UT - original_maneuver.UT - x[3]) + " s too early, trying again in " + initial_orbit.period + " s"); original_maneuver.UT += initial_orbit.period; } else return new ManeuverParameters(new Vector3d(x[0], x[1], x[2]), original_maneuver.UT + x[3]); } }
public Porkchop(ManeuverParameters[,] nodes) { Gradient colours = new Gradient(); var colourKeys = new GradientColorKey[6]; colourKeys[0].color = new Color(0.25f, 0.25f, 1.0f); colourKeys[0].time = 0.0f; colourKeys[1].color = new Color(0.5f, 0.5f, 1.0f); colourKeys[1].time = 0.01f; colourKeys[2].color = new Color(0.5f, 1.0f, 1.0f); colourKeys[2].time = 0.25f; colourKeys[3].color = new Color(0.5f, 1.0f, 0.5f); colourKeys[3].time = 0.5f; colourKeys[4].color = new Color(1.0f, 1.0f, 0.5f); colourKeys[4].time = 0.75f; colourKeys[5].color = new Color(1.0f, 0.5f, 0.5f); colourKeys[5].time = 1.0f; var alphaKeys = new GradientAlphaKey[2]; alphaKeys[0].alpha = 1.0f; alphaKeys[0].time = 0.0f; alphaKeys[1].alpha = 1.0f; alphaKeys[1].time = 1.0f; colours.SetKeys(colourKeys, alphaKeys); double DVminsqr = double.MaxValue; double DVmaxsqr = double.MinValue; for (int i = 0; i < nodes.GetLength(0); i++) { for (int j = 0; j < nodes.GetLength(1); j++) { if (nodes[i, j] != null) { double DVsqr = nodes[i, j].dV.sqrMagnitude; if (DVsqr < DVminsqr) { DVminsqr = DVsqr; } DVmaxsqr = Math.Max(DVmaxsqr, nodes[i, j].dV.sqrMagnitude); } } } texture = new Texture2D(nodes.GetLength(0), nodes.GetLength(1), TextureFormat.RGB24, false); double logDVminsqr = Math.Log(DVminsqr); double logDVmaxsqr = Math.Min(Math.Log(DVmaxsqr), logDVminsqr + 4); for (int i = 0; i < nodes.GetLength(0); i++) { for (int j = 0; j < nodes.GetLength(1); j++) { if (nodes[i, j] == null) { texture.SetPixel(i, j, colours.Evaluate(1)); } else { double lambda = (Math.Log(nodes[i, j].dV.sqrMagnitude) - logDVminsqr) / (logDVmaxsqr - logDVminsqr); texture.SetPixel(i, j, colours.Evaluate((float)lambda)); } } } texture.Apply(); #if DEBUG string dir = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); System.IO.File.WriteAllBytes(dir + "/Porkchop.png", texture.EncodeToPNG()); #endif }