def plot(self, x): import matplotlib as mpl from mpl_toolkits.mplot3d import Axes3D import matplotlib.pyplot as plt from pykep import epoch, AU, DAY2SEC from pykep.sims_flanagan import sc_state from pykep.orbit_plots import plot_planet, plot_sf_leg start = epoch(x[0]) end = epoch(x[0] + x[1]) r, v = self.__earth.eph(start) v = [a + b for a, b in zip(v, x[4:7])] x0 = sc_state(r, v, self.__sc.mass) r, v = self.__mars.eph(end) xe = sc_state(r, v, x[3]) self.__leg.set( start, x0, x[-3 * self.__nseg:], end, xe, x[2] * DAY2SEC) fig = plt.figure() axis = fig.gca(projection='3d') # The Sun axis.scatter([0], [0], [0], color='y') # The leg plot_sf_leg(self.__leg, units=AU, N=10, ax=axis) # The planets plot_planet( self.__earth, start, units=AU, legend=True, color=(0.8, 0.8, 1), ax=axis) plot_planet( self.__mars, end, units=AU, legend=True, color=(0.8, 0.8, 1), ax=axis) plt.show()
def run_example5(): import pygmo as pg from pykep import epoch from pykep.planet import jpl_lp from pykep.trajopt import mga_1dsm # We define an Earth-Venus-Earth problem (single-objective) seq = [jpl_lp('earth'), jpl_lp('venus'), jpl_lp('earth')] udp = mga_1dsm( seq=seq, t0=[epoch(5844), epoch(6209)], tof=[0.7 * 365.25, 3 * 365.25], vinf=[0.5, 2.5], add_vinf_dep=False, add_vinf_arr=True, multi_objective=False ) pg.problem(udp) # We solve it!! uda = pg.sade(gen=100) archi = pg.archipelago(algo=uda, prob=udp, n=8, pop_size=20) print( "Running a Self-Adaptive Differential Evolution Algorithm .... on 8 parallel islands") archi.evolve(10) archi.wait() sols = archi.get_champions_f() idx = sols.index(min(sols)) print("Done!! Solutions found are: ", archi.get_champions_f()) udp.pretty(archi.get_champions_x()[idx]) udp.plot(archi.get_champions_x()[idx])
def _plot_traj(self, z, axes, units): """Plots spacecraft trajectory. Args: - z (``tuple``, ``list``, ``numpy.ndarray``): Decision chromosome. - axes (``matplotlib.axes._subplots.Axes3DSubplot``): 3D axes to use for the plot - units (``float``, ``int``): Length unit by which to normalise data. Examples: >>> prob.extract(pykep.trajopt.indirect_or2or).plot_traj(pop.champion_x) """ # times t0 = pk.epoch(0) tf = pk.epoch(z[0]) # Mean Anomalies M0 = z[1] - self.elem0[1] * np.sin(z[1]) Mf = z[2] - self.elemf[1] * np.sin(z[2]) elem0 = np.hstack([self.elem0[:5], [M0]]) elemf = np.hstack([self.elemf[:5], [Mf]]) # Keplerian points kep0 = pk.planet.keplerian(t0, elem0) kepf = pk.planet.keplerian(tf, elemf) # planets pk.orbit_plots.plot_planet( kep0, t0=t0, units=units, ax=axes, color=(0.8, 0.8, 0.8)) pk.orbit_plots.plot_planet( kepf, t0=tf, units=units, ax=axes, color=(0.8, 0.8, 0.8))
def _plot_traj(self, z, axes, units=pk.AU): """Plots spacecraft trajectory. Args: - z (``tuple``, ``list``, ``numpy.ndarray``): Decision chromosome. - axes (``matplotlib.axes._subplots.Axes3DSubplot``): 3D axes to use for the plot - units (``float``, ``int``): Length unit by which to normalise data. Examples: >>> prob.extract(pykep.trajopt.indirect_pt2or).plot_traj(pop.champion_x) """ # times t0 = pk.epoch(0) tf = pk.epoch(z[1]) # Keplerian elements of the osculating orbit at start elem0 = list(pk.ic2par(self.x0[0:3], self.x0[3:6], self.leg.mu)) # Eccentric to Mean Anomaly elem0[5] = elem0[5] - elem0[1] * np.sin(elem0[5]) # Mean Anomaly at the target orbit Mf = z[1] - self.elemf[1] * np.sin(z[1]) elemf = np.hstack([self.elemf[:5], [Mf]]) # Keplerian elements kep0 = pk.planet.keplerian(t0, elem0) kepf = pk.planet.keplerian(tf, self.elemf) # plot departure and arrival pk.orbit_plots.plot_planet( kep0, t0, units=units, color=(0.8, 0.8, 0.8), ax=axes) pk.orbit_plots.plot_planet( kepf, tf, units=units, color=(0.8, 0.8, 0.8), ax=axes)
def _plot_traj(self, z, axes, units): # states x0 = self.leg.x0 xf = self.leg.xf # times t0 = pk.epoch(self.leg.t0) tf = pk.epoch(self.leg.tf) # Computes the osculating Keplerian elements at start and arrival elem0 = list(pk.ic2par(x0[0:3], x0[3:6], self.leg.mu)) elemf = list(pk.ic2par(xf[0:3], xf[3:6], self.leg.mu)) # Converts the eccentric anomaly into eccentric anomaly elem0[5] = elem0[5] - elem0[1] * np.sin(elem0[5]) elemf[5] = elemf[5] - elemf[1] * np.sin(elemf[5]) # Creates two virtual keplerian planets with the said elements kep0 = pk.planet.keplerian(t0, elem0) kepf = pk.planet.keplerian(tf, elemf) # Plots the departure and arrival osculating orbits pk.orbit_plots.plot_planet( kep0, t0, units=units, color=(0.8, 0.8, 0.8), ax=axes) pk.orbit_plots.plot_planet( kepf, tf, units=units, color=(0.8, 0.8, 0.8), ax=axes)
def pretty(self, x): """ prob.pretty(x) Args: - x (``list``, ``tuple``, ``numpy.ndarray``): Decision chromosome, e.g. (``pygmo.population.champion_x``). Prints human readable information on the trajectory represented by the decision vector x """ if not len(x) == len(self.get_bounds()[0]): raise ValueError("Invalid length of the decision vector x") n_seg = self.__n_seg m_i = self.__sc.mass t0 = x[0] T = x[1] m_f = x[2] thrusts = [np.linalg.norm(x[3 + 3 * i: 6 + 3 * i]) for i in range(n_seg)] tf = t0 + T mP = m_i - m_f deltaV = self.__sc.isp * pk.G0 * np.log(m_i / m_f) dt = np.append(self.__fwd_dt, self.__bwd_dt) * T / pk.DAY2SEC time_thrusts_on = sum(dt[i] for i in range( len(thrusts)) if thrusts[i] > 0.1) print("Departure:", pk.epoch(t0), "(", t0, "mjd2000 )") print("Time of flight:", T, "days") print("Arrival:", pk.epoch(tf), "(", tf, "mjd2000 )") print("Delta-v:", deltaV, "m/s") print("Propellant consumption:", mP, "kg") print("Thrust-on time:", time_thrusts_on, "days")
def run_example11(n_seg=30): """ This example demonstrates the use of the class lt_margo developed for the internal ESA CDF study on the interplanetary mission named MARGO. The class was used to produce the preliminary traget selection for the mission resulting in 88 selected possible targets (http://www.esa.int/spaceinimages/Images/2017/11/Deep-space_CubeSat) (http://www.esa.int/gsp/ACT/mad/projects/lt_to_NEA.html) """ import pykep as pk import pygmo as pg import numpy as np from matplotlib import pyplot as plt from pykep.examples import add_gradient, algo_factory # 0 - Target asteroid from MPCORB mpcorbline = "K14Y00D 24.3 0.15 K1794 105.44160 34.12337 117.64264 1.73560 0.0865962 0.88781021 1.0721510 2 MPO369254 104 1 194 days 0.24 M-v 3Eh MPCALB 2803 2014 YD 20150618" # 1 - Algorithm algo = algo_factory("snopt7") # 2 - Problem udp = add_gradient(pk.trajopt.lt_margo( target=pk.planet.mpcorb(mpcorbline), n_seg=n_seg, grid_type="uniform", t0=[pk.epoch(8000), pk.epoch(9000)], tof=[200, 365.25 * 3], m0=20.0, Tmax=0.0017, Isp=3000.0, earth_gravity=False, sep=True, start="earth"), with_grad=False ) prob = pg.problem(udp) prob.c_tol = [1e-5] * prob.get_nc() # 3 - Population pop = pg.population(prob, 1) # 4 - Solve the problem (evolve) pop = algo.evolve(pop) # 5 - Inspect the solution print("Feasible?:", prob.feasibility_x(pop.champion_x)) # 6 - plot trajectory axis = udp.udp_inner.plot_traj(pop.champion_x, plot_segments=True) plt.title("The trajectory in the heliocentric frame") # 7 - plot control udp.udp_inner.plot_dists_thrust(pop.champion_x) # 8 - pretty udp.udp_inner.pretty(pop.champion_x) plt.ion() plt.show()
def fitness(self, x_full): retval = [] # 1 - obj fun if self.__objective == 'mass': retval.append(x_full[-1 - self.__dim_leg + 3]) elif self.__objective == 'time': retval.append(x_full[-1 - self.__dim_leg] - x_full[0]) sc_mass = self.__start_mass eqs = [] ineqs = [] # 2 - constraints for i in range(self.__num_legs): x = x_full[i * self.__dim_leg:(i + 1) * self.__dim_leg] start = pk.epoch(x[0]) end = pk.epoch(x[0] + x[1]) # Computing starting spaceraft state r, v = self.__seq[i].eph(start) x0 = pk.sims_flanagan.sc_state(r, v, sc_mass) # Computing ending spaceraft state r, v = self.__seq[i + 1].eph(end) xe = pk.sims_flanagan.sc_state(r, v, x[3]) # Building the SF leg self.__legs[i].set_spacecraft( pk.sims_flanagan.spacecraft(sc_mass, .3, 3000.)) self.__legs[i].set(start, x0, x[-3 * self.__nseg:], end, xe) # Setting all constraints eqs.extend(self.__legs[i].mismatch_constraints()) ineqs.extend(self.__legs[i].throttles_constraints()) eqs[-7] /= pk.AU eqs[-6] /= pk.AU eqs[-5] /= pk.AU eqs[-4] /= pk.EARTH_VELOCITY eqs[-3] /= pk.EARTH_VELOCITY eqs[-2] /= pk.EARTH_VELOCITY eqs[-1] /= self.__start_mass sc_mass = x[3] # update mass to final mass of leg if i < self.__num_legs - 1: x_next = x_full[ (i + 1) * self.__dim_leg:(i + 2) * self.__dim_leg] time_ineq = x[0] + x[1] + x[2] - x_next[0] ineqs.append(time_ineq / 365.25) else: final_time_ineq = x[0] + x[1] + x[2] - \ x_full[0] - x_full[-1] # <- total time ineqs.append(final_time_ineq / 365.25) retval = retval + eqs + ineqs return retval
def fitness(self, z): # departure and arrival times t0 = pk.epoch(0) tf = pk.epoch(z[0]) # departure and arrival eccentric anomolies M0 = z[1] Mf = z[2] # departure costates l0 = np.asarray(z[3:]) # set Keplerian elements elem0 = np.hstack([self.elem0[:5], [M0]]) elemf = np.hstack([self.elemf[:5], [Mf]]) # compute Cartesian states r0, v0 = pk.par2ic(elem0, self.leg.mu) rf, vf = pk.par2ic(elemf, self.leg.mu) # departure and arrival states (xf[6] is unused) x0 = pk.sims_flanagan.sc_state(r0, v0, self.sc.mass) xf = pk.sims_flanagan.sc_state(rf, vf, self.sc.mass / 10) # set leg self.leg.set(t0, x0, l0, tf, xf) # equality constraints ceq = self.leg.mismatch_constraints(atol=self.atol, rtol=self.rtol) # final mass obj = self.leg.trajectory[-1, -1] # Transversality conditions # At start lambdas0 = np.array(self.leg.trajectory[0, 7:13]) r0norm = np.sqrt(r0[0] * r0[0] + r0[1] * r0[1] + r0[2] * r0[2]) tmp = - pk.MU_SUN / r0norm**3 tangent = np.array([v0[0], v0[1], v0[2], tmp * r0[0], tmp * r0[1], tmp * r0[2]]) tangent_norm = np.linalg.norm(tangent) tangent = tangent / tangent_norm T0 = np.dot(lambdas0, tangent) # At end lambdasf = np.array(self.leg.trajectory[-1, 7:13]) rfnorm = np.sqrt(rf[0] * rf[0] + rf[1] * rf[1] + rf[2] * rf[2]) tmp = - pk.MU_SUN / rfnorm**3 tangent = np.array([vf[0], vf[1], vf[2], tmp * rf[0], tmp * rf[1], tmp * rf[2]]) tangent_norm = np.linalg.norm(tangent) tangent = tangent / tangent_norm Tf = np.dot(lambdasf, tangent) return np.hstack(([1], ceq, [T0, Tf]))
def _plot_traj(self, z, axis, units): # times t0 = pk.epoch(z[0]) tf = pk.epoch(z[0] + z[1]) # plot Keplerian pk.orbit_plots.plot_planet( self.p0, t0, units=units, color=(0.8, 0.8, 0.8), ax=axis) pk.orbit_plots.plot_planet( self.pf, tf, units=units, color=(0.8, 0.8, 0.8), ax=axis)
def _pretty(self, z): print("\nLow-thrust NEP transfer from " + self.p0.name + " to " + self.pf.name) print("\nLaunch epoch: {!r} MJD2000, a.k.a. {!r}".format( z[0], pk.epoch(z[0]))) print("Arrival epoch: {!r} MJD2000, a.k.a. {!r}".format( z[0] + z[1], pk.epoch(z[0] + z[1]))) print("Time of flight (days): {!r} ".format(z[1])) print("\nLaunch DV (km/s) {!r} - [{!r},{!r},{!r}]".format(np.sqrt( z[3]**2 + z[4]**2 + z[5]**2) / 1000, z[3] / 1000, z[4] / 1000, z[5] / 1000)) print("Arrival DV (km/s) {!r} - [{!r},{!r},{!r}]".format(np.sqrt( z[6]**2 + z[7]**2 + z[8]**2) / 1000, z[6] / 1000, z[7] / 1000, z[8] / 1000))
def _plot_traj(self, z, axis, units): # times t0 = pk.epoch(0) tf = pk.epoch(z[0]) # Keplerian kep0 = pk.planet.keplerian(t0, self.elem0) kepf = pk.planet.keplerian(tf, self.elemf) # plot Keplerian pk.orbit_plots.plot_planet( kep0, t0, units=units, color=(0.8, 0.8, 0.8), ax=axis) pk.orbit_plots.plot_planet( kepf, tf, units=units, color=(0.8, 0.8, 0.8), ax=axis)
def plot(self, x, ax=None): """ ax = prob.plot(x, ax=None) - x: encoded trajectory - ax: matplotlib axis where to plot. If None figure and axis will be created - [out] ax: matplotlib axis where to plot Plots the trajectory represented by a decision vector x on the 3d axis ax Example:: ax = prob.plot(x) """ import matplotlib as mpl from mpl_toolkits.mplot3d import Axes3D import matplotlib.pyplot as plt from pykep import epoch, AU from pykep.sims_flanagan import sc_state from pykep.orbit_plots import plot_planet, plot_sf_leg # Creating the axis if necessary if ax is None: mpl.rcParams['legend.fontsize'] = 10 fig = plt.figure() axis = fig.gca(projection='3d') else: axis = ax # Plotting the Sun ........ axis.scatter([0], [0], [0], color='y') # Plotting the pykep.planet both at departure and arrival dates for i in range(self.__num_legs): idx = i * self.__dim_leg plot_planet(self.__seq[i], epoch(x[idx]), units=AU, legend=True, color=( 0.7, 0.7, 0.7), s=30, ax=axis) plot_planet(self.__seq[i + 1], epoch(x[idx] + x[idx + 1]), units=AU, legend=False, color=(0.7, 0.7, 0.7), s=30, ax=axis) # Computing the legs self.fitness(x) # Plotting the legs for leg in self.__legs: plot_sf_leg(leg, units=AU, N=10, ax=axis, legend=False) return axis
def fitness(self, z): # times t0 = self.t0 tf = pk.epoch(t0.mjd2000 + z[0]) # intial costates l0 = np.asarray(z[1:]) # arrival conditions rf, vf = self.pf.eph(tf) # departure state x0 = pk.sims_flanagan.sc_state(self.x0[0:3], self.x0[3:6], self.x0[6]) # arrival state (mass will be ignored) xf = pk.sims_flanagan.sc_state(rf, vf, self.sc.mass / 10) # set leg self.leg.set(t0, x0, l0, tf, xf) # equality constraints ceq = self.leg.mismatch_constraints(atol=self.atol, rtol=self.rtol) obj = self.leg.trajectory[-1, -1] * self.leg._dynamics.c2 * 1000 return np.hstack(([obj], ceq))
def _plot_traj(self, z, axes, units=pk.AU): """Plots spacecraft trajectory. Args: - z (``tuple``, ``list``, ``numpy.ndarray``): Decision chromosome. - axes (``matplotlib.axes._subplots.Axes3DSubplot``): 3D axes to use for the plot - units (``float``, ``int``): Length unit by which to normalise data. Examples: >>> prob.extract(pykep.trajopt.indirect_pt2or).plot_traj(pop.champion_x) """ # states x0 = self.x0 # times t0 = self.t0 tf = pk.epoch(t0.mjd2000 + z[0]) # Computes the osculating Keplerian elements at start elem0 = list(pk.ic2par(x0[0:3], x0[3:6], self.leg.mu)) # Converts the eccentric anomaly into eccentric anomaly elem0[5] = elem0[5] - elem0[1] * np.sin(elem0[5]) # Creates a virtual keplerian planet with the said elements kep0 = pk.planet.keplerian(t0, elem0) # Plots the departure and arrival osculating orbits pk.orbit_plots.plot_planet( kep0, t0, units=units, color=(0.8, 0.8, 0.8), ax=axes) pk.orbit_plots.plot_planet( self.pf, tf, units=units, color=(0.8, 0.8, 0.8), ax=axes)
def plot(self, x, axes=None, units=pk.AU, N=60): """plot(self, x, axes=None, units=pk.AU, N=60) Plots the spacecraft trajectory. Args: - x (``tuple``, ``list``, ``numpy.ndarray``): Decision chromosome. - axes (``matplotlib.axes._subplots.Axes3DSubplot``): 3D axes to use for the plot - units (``float``, ``int``): Length unit by which to normalise data. - N (``float``): Number of points to plot per leg """ import matplotlib as mpl import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D # Creating the axes if necessary if axes is None: mpl.rcParams['legend.fontsize'] = 10 fig = plt.figure() axes = fig.gca(projection='3d') T = self._decode_tofs(x) ep = np.insert(T, 0, x[0]) # [t0, T1, T2 ...] ep = np.cumsum(ep) # [t0, t1, t2, ...] DVlaunch, DVfb, DVarrival, l, _ = self._compute_dvs(x) for pl, e in zip(self.seq, ep): pk.orbit_plots.plot_planet(pl, pk.epoch( e), units=units, legend=True, color=(0.7, 0.7, 1), ax=axes) for lamb in l: pk.orbit_plots.plot_lambert( lamb, N=N, sol=0, units=units, color='k', legend=False, ax=axes, alpha=0.8) return axes
def fitness(self, z): # times t0 = pk.epoch(0) tf = pk.epoch(z[0]) # costates l0 = np.asarray(z[1:]) # set leg self.leg.set(t0, self.x0, l0, tf, self.xf) # equality constraints ceq = self.leg.mismatch_constraints(atol=self.atol, rtol=self.rtol) return np.hstack(([1, ceq]))
def fitness(self, z): # epochs (mjd2000) t0 = pk.epoch(z[0]) tf = pk.epoch(z[0] + z[1]) # final mass mf = z[2] # controls u = z[9:] # compute Cartesian states of planets r0, v0 = self.p0.eph(t0) rf, vf = self.pf.eph(tf) # add the vinfs from the chromosome v0 = [a + b for a, b in zip(v0, z[3:6])] vf = [a + b for a, b in zip(vf, z[6:9])] # spacecraft states x0 = pk.sims_flanagan.sc_state(r0, v0, self.sc.mass) xf = pk.sims_flanagan.sc_state(rf, vf, mf) # set leg self.leg.set(t0, x0, u, tf, xf) # compute equality constraints ceq = np.asarray(self.leg.mismatch_constraints(), np.float64) # nondimensionalise equality constraints ceq[0:3] /= pk.AU ceq[3:6] /= pk.EARTH_VELOCITY ceq[6] /= self.sc.mass # compute inequality constraints cineq = np.asarray(self.leg.throttles_constraints(), np.float64) # compute inequality constraints on departure and arrival velocities v_dep_con = (z[3] ** 2 + z[4] ** 2 + z[5] ** 2 - self.vinf_dep ** 2) v_arr_con = (z[6] ** 2 + z[7] ** 2 + z[8] ** 2 - self.vinf_arr ** 2) # nondimensionalize inequality constraints v_dep_con /= pk.EARTH_VELOCITY ** 2 v_arr_con /= pk.EARTH_VELOCITY ** 2 return np.hstack(([-mf], ceq, cineq, [v_dep_con, v_arr_con]))
def plot(self, x): import matplotlib as mpl from mpl_toolkits.mplot3d import Axes3D import matplotlib.pyplot as plt from pykep import epoch, AU from pykep.sims_flanagan import sc_state from pykep.orbit_plots import plot_planet, plot_sf_leg t_E = epoch(x[0]) t_V = epoch(x[0] + x[1]) t_M = epoch(x[0] + x[1] + x[9]) rE, vE = self.__earth.eph(t_E) rV, vV = self.__venus.eph(t_V) rM, vM = self.__mercury.eph(t_M) # First Leg v = [a + b for a, b in zip(vE, x[3:6])] x0 = sc_state(rE, v, self.__sc.mass) v = [a + b for a, b in zip(vV, x[6:9])] xe = sc_state(rV, v, x[2]) self.__leg1.set( t_E, x0, x[-3 * (self.__nseg1 + self.__nseg2):-self.__nseg2 * 3], t_V, xe) # Second leg v = [a + b for a, b in zip(vV, x[11:14])] x0 = sc_state(rV, v, x[2]) v = [a + b for a, b in zip(vM, x[14:17])] xe = sc_state(rM, v, x[10]) self.__leg2.set(t_E, x0, x[(-3 * self.__nseg2):], t_V, xe) fig = plt.figure() axis = fig.gca(projection='3d') # The Sun axis.scatter([0], [0], [0], color='y') # The legs plot_sf_leg(self.__leg1, units=AU, N=10, ax=axis) plot_sf_leg(self.__leg2, units=AU, N=10, ax=axis) # The planets plot_planet( self.__earth, t_E, units=AU, legend=True, color=(0.7, 0.7, 1), ax=axis) plot_planet( self.__venus, t_V, units=AU, legend=True, color=(0.7, 0.7, 1), ax=axis) plot_planet( self.__mercury, t_M, units=AU, legend=True, color=(0.7, 0.7, 1), ax=axis) plt.show()
def fitness(self, z): # epochs (mjd2000) t0 = pk.epoch(0) tf = pk.epoch(z[0]) # final mass mf = z[1] # eccentric anomolies E0 = z[2] Ef = z[3] # controls u = z[4:] # set Keplerian elements self.elem0[5] = E0 self.elemf[5] = Ef # compute Cartesian states r0, v0 = pk.par2ic(self.elem0, self.mu) rf, vf = pk.par2ic(self.elemf, self.mu) # spacecraft states x0 = pk.sims_flanagan.sc_state(r0, v0, self.sc.mass) xf = pk.sims_flanagan.sc_state(rf, vf, mf) # set leg self.leg.set(t0, x0, u, tf, xf) # compute equality constraints ceq = np.asarray(self.leg.mismatch_constraints(), np.float64) # nondimensionalise equality constraints ceq[0:3] /= pk.AU ceq[3:6] /= pk.EARTH_VELOCITY ceq[6] /= self.sc.mass # compute inequality constraints cineq = np.asarray(self.leg.throttles_constraints(), np.float64) return np.hstack(([-mf], ceq, cineq))
def fitness(self, z): # times t0 = pk.epoch(0) tf = pk.epoch(z[0]) # final eccentric anomaly Mf = z[1] # intial costates l0 = np.asarray(z[2:]) # set arrival Keplerian elements self.elemf[5] = Mf # departure state x0 = pk.sims_flanagan.sc_state(self.x0[0:3], self.x0[3:6], self.x0[6]) # compute Cartesian arrival state rf, vf = pk.par2ic(self.elemf, self.leg.mu) xf = pk.sims_flanagan.sc_state(rf, vf, self.sc.mass / 10) # set leg self.leg.set(t0, x0, l0, tf, xf) # equality constraints ceq = self.leg.mismatch_constraints(atol=self.atol, rtol=self.rtol) # final mass # mf = self.leg.trajectory[-1, 6] # Transversality condition at the end lambdasf = np.array(self.leg.trajectory[-1, 7:13]) rfnorm = np.sqrt(rf[0] * rf[0] + rf[1] * rf[1] + rf[2] * rf[2]) tmp = - pk.MU_SUN / rfnorm**3 tangent = np.array([vf[0], vf[1], vf[2], tmp * rf[0], tmp * rf[1], tmp * rf[2]]) tangent_norm = np.linalg.norm(tangent) tangent = tangent / tangent_norm Tf = np.dot(lambdasf, tangent) return np.hstack(([1], ceq, [Tf]))
def plotContours(start_planet, end_planet, eph1, eph2, flt1, flt2, sampling_size): start_epochs = np.arange(eph1, eph2, sampling_size) duration = np.arange(flt1, flt2, sampling_size) data = list() for start in start_epochs: row = list() for T in duration: r1, v1 = start_planet.eph(pk.epoch(start)) r2, v2 = end_planet.eph(pk.epoch(start + T)) l = pk.lambert_problem(r1, r2, T * 60 * 60 * 24, start_planet.mu_central_body) DV1 = np.linalg.norm(array(v1) - array(l.get_v1()[0])) DV2 = np.linalg.norm(array(v2) - array(l.get_v2()[0])) DV1 = max([0, DV1 - eph1]) DV = DV1 + DV2 row.append(DV) data.append(row) minrows = [min(l) for l in data] i_idx = np.argmin(minrows) j_idx = np.argmin(data[i_idx]) best = data[i_idx][j_idx] print('\nBest DV: ', best) print('Launch epoch (MJD2000): ', start_epochs[i_idx]) print('Duration (days): ', duration[j_idx]) duration_pl2, start_epochs_pl2 = np.meshgrid(duration, start_epochs) CP2 = plt.contourf(start_epochs_pl2, duration_pl2, array(data), levels=list(np.linspace(best, 5000, 10))) plt.colorbar(CP2).set_label('△V km/s') plt.title(f'{start_planet.name} - {end_planet.name} Total △V Requirements'. title()) plt.xlabel('Launch Date (MJD2000)') plt.ylabel('Mission Duration (days)') plt.show()
def double_segments(self, x): """ new_prob, new_x = prob.double_segments(self,x) Args: - x (``list``, ``tuple``, ``numpy.ndarray``): Decision chromosome, e.g. (``pygmo.population.champion_x``). Returns: - the new udp having twice the segments - list: the new chromosome to be used as initial guess Returns the decision vector encoding a low trust trajectory having double the number of segments with respect to x and a 'similar' throttle history. In case high fidelity is True, and x is a feasible trajectory, the returned decision vector also encodes a feasible trajectory that can be further optimized Returns the problem and the decision vector encoding a low-thrust trajectory having double the number of segments with respect to x and the same throttle history. If x is a feasible trajectory, the new chromosome is "slightly unfeasible", due to the new refined Earth's gravity and/or SEP thrust that are now computed in the 2 halves of each segment. """ if not len(x) == len(self.get_bounds()[0]): raise ValueError("Invalid length of the decision vector x") new_x = np.append(x[:3], np.repeat(x[3:].reshape((-1, 3)), 2, axis=0)) new_prob = lt_margo( target=self.target, n_seg=2 * self.__n_seg, grid_type=self.__grid_type, t0=[pk.epoch(self.__lb[0]), pk.epoch(self.__ub[0])], tof=[self.__lb[1], self.__ub[1]], m0=self.__sc.mass, Tmax=self.__sc.thrust, Isp=self.__sc.isp, earth_gravity=self.__earth_gravity, sep=self.__sep, start=self.__start ) return new_prob, new_x
def __init__( self, t0_limits=[7000, 8000], tof_limits=[[50, 420], [50, 400], [50, 400]], max_revs: int = 2, resonances=[[[1, 1], [5, 4], [4, 3]], [[1, 1], [5, 4], [4, 3]], [[1, 1], [5, 4], [4, 3]], [[4, 3], [3, 2], [5, 3]], [[4, 3], [3, 2], [5, 3]], [[4, 3], [3, 2], [5, 3]]], safe_distance=350000, max_mission_time=11.0 * 365.25, max_dv0=5600, ): """ Args: - t0_limits (``list`` of ``float``): start time bounds. - tof_limits (``list`` of ``list`` of ``float``): time of flight bounds. - max_revs (``int``): maximal number of revolutions for Lambert transfer. - resonances (``list`` of ``list`` of ``int``): resonance options. - safe_distance: (``float``): safe distance from planet at GA maneuver in m. - max_mission_time: (``float``): max mission time in days. - max_dv0: (``float``): max delta velocity at start. """ self._safe_distance = safe_distance self._max_mission_time = max_mission_time self._max_dv0 = max_dv0 self._min_beta = -math.pi self._max_beta = math.pi self._earth = jpl_lp("earth") self._venus = jpl_lp("venus") self._seq = [ self._earth, self._venus, self._venus, self._earth, self._venus, self._venus, self._venus, self._venus, self._venus, self._venus ] assert len(self._seq) - 4 == len( resonances) # one resonance option selection for each VV sequence self._resonances = resonances self._t0 = t0_limits self._tof = tof_limits self._max_revs = max_revs self._n_legs = len(self._seq) - 1 # initialize data to compute heliolatitude t_plane_crossing = epoch(7645) rotation_axis = self._seq[0].eph(t_plane_crossing)[0] self._rotation_axis = rotation_axis / np.linalg.norm(rotation_axis) self._theta = -7.25 * DEG2RAD # fixed direction of the rotation
def _plot_traj(self, z, axes, units): """Plots spacecraft trajectory. Args: - z (``tuple``, ``list``, ``numpy.ndarray``): Decision chromosome. - axes (``matplotlib.axes._subplots.Axes3DSubplot``): 3D axes to use for the plot - units (``float``, ``int``): Length unit by which to normalise data. Examples: >>> prob.extract(pykep.trajopt.indirect_or2or).plot_traj(pop.champion_x) """ # times t0 = pk.epoch(0) tf = pk.epoch(z[0]) # Mean Anomalies M0 = z[1] - self.elem0[1] * np.sin(z[1]) Mf = z[2] - self.elemf[1] * np.sin(z[2]) elem0 = np.hstack([self.elem0[:5], [M0]]) elemf = np.hstack([self.elemf[:5], [Mf]]) # Keplerian points kep0 = pk.planet.keplerian(t0, elem0) kepf = pk.planet.keplerian(tf, elemf) # planets pk.orbit_plots.plot_planet(kep0, t0=t0, units=units, axes=axes, color=(0.8, 0.8, 0.8)) pk.orbit_plots.plot_planet(kepf, t0=tf, units=units, axes=axes, color=(0.8, 0.8, 0.8))
def fitness(self, x): from pykep import epoch, AU, EARTH_VELOCITY, DAY2SEC from pykep.sims_flanagan import sc_state # This is the objective function objfun = [-x[3]] # And these are the constraints start = epoch(x[0]) end = epoch(x[0] + x[1]) r, v = self.__earth.eph(start) v = [a + b for a, b in zip(v, x[4:7])] x0 = sc_state(r, v, self.__sc.mass) r, v = self.__mars.eph(end) xe = sc_state(r, v, x[3]) self.__leg.set(start, x0, x[-3 * self.__nseg:], end, xe, x[2] * DAY2SEC) v_inf_con = (x[4] * x[4] + x[5] * x[5] + x[6] * x[6] - self.__Vinf * self.__Vinf) / (EARTH_VELOCITY * EARTH_VELOCITY) try: constraints = list(self.__leg.mismatch_constraints( ) + self.__leg.throttles_constraints()) + [v_inf_con] except: print( "warning: CANNOT EVALUATE constraints .... possible problem in the Taylor integration in the Sundmann variable") constraints = (1e14,) * (8 + 1 + self.__nseg + 2) # We then scale all constraints to non-dimensional values constraints[0] /= AU constraints[1] /= AU constraints[2] /= AU constraints[3] /= EARTH_VELOCITY constraints[4] /= EARTH_VELOCITY constraints[5] /= EARTH_VELOCITY constraints[6] /= self.__sc.mass constraints[7] /= 365.25 * DAY2SEC return objfun + constraints
def run_example1(impulses=4): import pykep as pk import pygmo as pg import numpy as np from matplotlib import pyplot as plt from pykep.examples import add_gradient, algo_factory # problem udp = add_gradient(pk.trajopt.pl2pl_N_impulses( start=pk.planet.jpl_lp('earth'), target=pk.planet.jpl_lp('venus'), N_max=impulses, tof=[100., 1000.], vinf=[0., 4], phase_free=False, multi_objective=False, t0=[pk.epoch(0), pk.epoch(1000)]), with_grad=False) prob = pg.problem(udp) # algorithm uda = pg.cmaes(gen=1000, force_bounds=True) algo = pg.algorithm(uda) algo.set_verbosity(10) # population pop = pg.population(prob, 20) # solve the problem pop = algo.evolve(pop) # inspect the solution udp.udp_inner.plot(pop.champion_x) plt.ion() plt.show() udp.udp_inner.pretty(pop.champion_x)
def __init__(self, x0=[ -24482087316.947845, -150000284705.77328, -196089391.29376224, 31677.87649549203, -5859.747563624047, -351.75278222719828, 1000 ], pf="mars", mass=1000, thrust=0.3, isp=3000, tof=[230, 280], t0=1251.0286746844447, mu=pk.MU_SUN, alpha=0, bound=False, atol=1e-12, rtol=1e-12): """Initialises ``pykep.trajopt.indirect_pt2or`` problem. Args: - x0 (``list``, ``tuple``, ``numpy.ndarray``): Departure state [m, m, m, m/s, m/s, m/s, kg]. - pf (``str``): Arrival planet name. (will be used to construct a planet.jpl_lp object) - mass (``float``, ``int``): Spacecraft wet mass [kg]. - thrust (``float``, ``int``): Spacecraft maximum thrust [N]. - isp (``float``, ``int``): Spacecraft specific impulse [s]. - atol (``float``, ``int``): Absolute integration solution tolerance. - rtol (``float``, ``int``): Relative integration solution tolerance. - tof (``list``): Transfer time bounds [days]. - t0 (``float``): launch epoch [MJD2000]. - freetime (``bool``): Activates final time transversality condition. Allows final time to vary. - alpha (``float``, ``int``): Homotopy parameter, governing the degree to which the theoretical control law is intended to reduce propellant expenditure or energy. - bound (``bool``): Activates bounded control, in which the control throttle is bounded between 0 and 1, otherwise the control throttle is allowed to unbounded. - mu (``float``): Gravitational parameter of primary body [m^3/s^2]. """ # initialise base _indirect_base.__init__(self, mass, thrust, isp, mu, True, False, alpha, bound, atol, rtol) # departure epoch self.t0 = pk.epoch(t0) # departure state self.x0 = np.asarray(x0, np.float64) # arrival planet self.pf = pk.planet.jpl_lp(pf) # bounds on the time of flight self.tof = tof # store the alfa value (immutable) self._alpha = alpha
def __init__(self, x0=[-24482087316.947845, -150000284705.77328, -196089391.29376224, 31677.87649549203, -5859.747563624047, -351.75278222719828, 1000], pf="mars", mass=1000, thrust=0.3, isp=3000, tof=[230, 280], t0=1251.0286746844447, mu=pk.MU_SUN, alpha=0, bound=False, atol=1e-12, rtol=1e-12 ): """Initialises ``pykep.trajopt.indirect_pt2or`` problem. Args: - x0 (``list``, ``tuple``, ``numpy.ndarray``): Departure state [m, m, m, m/s, m/s, m/s, kg]. - pf (``str``): Arrival planet name. (will be used to construct a planet.jpl_lp object) - mass (``float``, ``int``): Spacecraft wet mass [kg]. - thrust (``float``, ``int``): Spacecraft maximum thrust [N]. - isp (``float``, ``int``): Spacecraft specific impulse [s]. - atol (``float``, ``int``): Absolute integration solution tolerance. - rtol (``float``, ``int``): Relative integration solution tolerance. - tof (``list``): Transfer time bounds [days]. - t0 (``float``): launch epoch [MJD2000]. - freetime (``bool``): Activates final time transversality condition. Allows final time to vary. - alpha (``float``, ``int``): Homotopy parametre, governing the degree to which the theoretical control law is intended to reduce propellant expenditure or energy. - bound (``bool``): Activates bounded control, in which the control throttle is bounded between 0 and 1, otherwise the control throttle is allowed to unbounded. - mu (``float``): Gravitational parametre of primary body [m^3/s^2]. """ # initialise base _indirect_base.__init__( self, mass, thrust, isp, mu, True, False, alpha, bound, atol, rtol ) # departure epoch self.t0 = pk.epoch(t0) # departure state self.x0 = np.asarray(x0, np.float64) # arrival planet self.pf = pk.planet.jpl_lp(pf) # bounds on the time of flight self.tof = tof # store the alfa value (immutable) self._alpha = alpha
def planet(self): """PyKep object (pykep.planet.keplerian) representation of Planet.""" if self.pykep_planet is None: if self.planet_radius is None: planet_radius_constant = Constant("Rpln") self.planet_radius = planet_radius_constant.value self.pykep_planet = keplerian( epoch(0), (self.semimajor_axis * AU, self.eccentricity, self.inclination, self.longitude_of_ascending_node, self.argument_of_periapsis, self.true_anomaly_at_epoch), self._star.gm, self.gm, self.radius * self.planet_radius, self.radius * self.planet_radius, self.name) return self.pykep_planet
def rate__orbital(dep_ast, dep_t, leg_dT, **kwargs): """ Orbital Phasing Indicator. See: http://arxiv.org/pdf/1511.00821.pdf#page=12 Estimates the cost of a `leg_dT` days transfer from departure asteroid `dep_ast` at epoch `dep_t`, towards each of the available asteroids. """ dep_t = pk.epoch(dep_t, "mjd") leg_dT *= DAY2SEC orbi = [ orbital_indicator(ast, dep_t, leg_dT, **kwargs) for ast in asteroids ] ast_orbi = np.array(orbi[dep_ast]) return np.linalg.norm(ast_orbi - orbi, axis=1)
def pretty(self, x): """ prob.pretty(x) Args: - x (``list``, ``tuple``, ``numpy.ndarray``): Decision chromosome, e.g. (``pygmo.population.champion_x``). Prints human readable information on the trajectory represented by the decision vector x """ if not len(x) == len(self.get_bounds()[0]): raise ValueError("Invalid length of the decision vector x") n_seg = self.__n_seg m_i = self.__sc.mass t0 = x[0] T = x[1] m_f = x[2] thrusts = [ np.linalg.norm(x[3 + 3 * i:6 + 3 * i]) for i in range(n_seg) ] tf = t0 + T mP = m_i - m_f deltaV = self.__sc.isp * pk.G0 * np.log(m_i / m_f) dt = np.append(self.__fwd_dt, self.__bwd_dt) * T / pk.DAY2SEC time_thrusts_on = sum(dt[i] for i in range(len(thrusts)) if thrusts[i] > 0.1) print("Departure:", pk.epoch(t0), "(", t0, "mjd2000 )") print("Time of flight:", T, "days") print("Arrival:", pk.epoch(tf), "(", tf, "mjd2000 )") print("Delta-v:", deltaV, "m/s") print("Propellant consumption:", mP, "kg") print("Thrust-on time:", time_thrusts_on, "days")
def plot_planet_2d(planet, t0): T = planet.compute_period(t0) * SEC2DAY when = np.linspace(0, T, 60) x = np.array([0.0] * 60) y = np.array([0.0] * 60) z = np.array([0.0] * 60) for i, day in enumerate(when): r, _ = planet.eph(epoch(t0.mjd2000 + day)) x[i] = r[0] / AU y[i] = r[1] / AU z[i] = r[2] / AU return x, y, z
def plot(self, x, axes=None, units=AU, N=60): import matplotlib as mpl import matplotlib.pyplot as plt from pykep.orbit_plots import plot_planet rvt_outs, rvt_ins, rvt_pls, _, _ = self._compute_dvs(x) rvt_outs = [ rvt.rotate(self._rotation_axis, self._theta) for rvt in rvt_outs ] rvt_ins[1:] = [ rvt.rotate(self._rotation_axis, self._theta) for rvt in rvt_ins[1:] ] rvt_pls = [ rvt.rotate(self._rotation_axis, self._theta) for rvt in rvt_pls ] ep = [epoch(rvt_pl._t * SEC2DAY) for rvt_pl in rvt_pls] # Creating the axes if necessary if axes is None: mpl.rcParams["legend.fontsize"] = 10 fig = plt.figure() axes = fig.gca(projection="3d") plt.xlim([-1, 1]) # planets for pl, e in zip(self._seq, ep): plot_planet(pl, e, units=units, legend=True, color=(0.7, 0.7, 1), axes=axes) # lamberts and resonances for i in range(0, len(self._seq) - 1): pl = self._seq[i] # stay at planet: it is a resonance colored black is_reso = pl == self._seq[i + 1] rvt_out = rvt_outs[i] tof = rvt_ins[i + 1]._t - rvt_out._t rvt_out.plot(tof, units=units, N=4 * N, color="k" if is_reso else "r", axes=axes) return axes
def eph_reference(ref_ast, t): """ Calculate reference r and v magnitudes for use in the normalization of asteroid ephemeris. Returns: (|r|, |v|) where (r,v) is the ephemeris of the given asteroid `ref_ast` (id, or object) at epoch `t` (int/float, or epoch object). """ if type(ref_ast) is int: ref_ast = asteroids[ref_ast] if type(t) in [float, int]: t = pk.epoch(t, "mjd") r, v = ref_ast.eph(t) return np.linalg.norm(r), np.linalg.norm(v)
def epoch_offset(): planet = Planet(1817514095, 1905216634, -455609026) winter = np.arctan2(-1, 0) a = -75.0 b = 75.0 for _ in range(1000): c = (a + b) / 2 r_c, _ = planet.planet.eph(epoch(c)) angle = np.arctan2(r_c[1], r_c[0]) if angle - winter < 0: a = c else: b = c return jsonify(c) if has_app_context() else c
def _plot_traj(self, z, axes, units=pk.AU): """Plots spacecraft trajectory. Args: - z (``tuple``, ``list``, ``numpy.ndarray``): Decision chromosome. - atol (``float``, ``int``): Absolute integration solution tolerance. - rtol (``float``, ``int``): Relative integration solution tolerance. - units (``float``, ``int``): Length unit by which to normalise data. Examples: >>> prob.extract(pykep.trajopt.indirect_pt2or).plot_traj(pop.champion_x) """ # states x0 = self.x0 # times t0 = self.t0 tf = pk.epoch(t0.mjd2000 + z[0]) # Computes the osculating Keplerian elements at start elem0 = list(pk.ic2par(x0[0:3], x0[3:6], self.leg.mu)) # Converts the eccentric anomaly into eccentric anomaly elem0[5] = elem0[5] - elem0[1] * np.sin(elem0[5]) # Creates a virtual keplerian planet with the said elements kep0 = pk.planet.keplerian(t0, elem0) # Plots the departure and arrival osculating orbits pk.orbit_plots.plot_planet(kep0, t0, units=units, color=(0.8, 0.8, 0.8), ax=axes) pk.orbit_plots.plot_planet(self.pf, tf, units=units, color=(0.8, 0.8, 0.8), ax=axes)
def ephemeris(planet, modifiedJulianDay, mode='jpl', ref='sun'): ''' Query the ephemeris for the specified planet and epoch Based on the Pykep package by ESA/ACT, developed with version 2.3 Returns the state vector (pos, vel) in Cartesian and Cylindrical coordinates mode='jpl' uses low precision ephemerides of the planets ('earth', etc) mode='spice' uses high precision spice kernel. These need to be loaded into memory using loadSpiceKernels(). The kernel (430.bsp) includes ephemerides for Earth, Moon and the planet system barycenters ('399', 301', '4', etc) mode='gtoc2' uses the asteroids from the GTOC2 competition (Keplerian) ''' epoch = pk.epoch(modifiedJulianDay, 'mjd2000') if mode == 'jpl': planet = pk.planet.jpl_lp(planet) elif mode == 'spice': planet = pk.planet.spice(planet, ref, 'eclipj2000') elif mode == 'gtoc2': planet = pk.planet.gtoc2(planet) else: print('ERROR: This is not a valid source of ephemerides.') # retrieve Cartesian state vectors in SI units rCart, vCart = planet.eph(epoch) # conversion to cylindrical values to get boundary conditions rCyl = Pcart2cyl(rCart) vCyl = Vcart2cyl(vCart, rCart) # combine into (6,) vectors (3xposition, 3xvelocity) stateVectorCartesian = np.array((rCart, vCart)).reshape(6, ) stateVectorCylindrical = np.array((rCyl, vCyl)).reshape(6, ) return stateVectorCylindrical, stateVectorCartesian, planet
def plot_dists_thrust(self, x, axes=None): """ axes = prob.plot_dists_thrust(self, x, axes=None) Args: - x (``list``, ``tuple``, ``numpy.ndarray``): Decision chromosome, e.g. (``pygmo.population.champion_x``). Returns: matplotlib.axes: axes where to plot Plots the distance of the spacecraft from the Earth/Sun and the thrust profile """ if not len(x) == len(self.get_bounds()[0]): raise ValueError("Invalid length of the decision vector x") import matplotlib as mpl import matplotlib.pyplot as plt # Creating the axes if necessary if axes is None: mpl.rcParams['legend.fontsize'] = 10 fig = plt.figure() axes = fig.add_subplot(111) n_seg = self.__n_seg fwd_seg = self.__fwd_seg bwd_seg = self.__bwd_seg t0 = x[0] T = x[1] fwd_grid = t0 + T * self.__fwd_grid # days bwd_grid = t0 + T * self.__bwd_grid # days throttles = [np.linalg.norm(x[3 + 3 * i: 6 + 3 * i]) for i in range(n_seg)] dist_earth = [0.0] * (n_seg + 2) # distances spacecraft - Earth dist_sun = [0.0] * (n_seg + 2) # distances spacecraft - Sun times = np.concatenate((fwd_grid, bwd_grid)) rfwd, rbwd, vfwd, vbwd, mfwd, mbwd, ufwd, ubwd, fwd_dt, bwd_dt, _, _ = self._propagate( x) # Forward propagation xfwd = [0.0] * (fwd_seg + 1) yfwd = [0.0] * (fwd_seg + 1) zfwd = [0.0] * (fwd_seg + 1) xfwd[0] = rfwd[0][0] / pk.AU yfwd[0] = rfwd[0][1] / pk.AU zfwd[0] = rfwd[0][2] / pk.AU r_E = [ri / pk.AU for ri in self.__earth.eph(pk.epoch(fwd_grid[0]))[0]] dist_earth[0] = np.linalg.norm( [r_E[0] - xfwd[0], r_E[1] - yfwd[0], r_E[2] - zfwd[0]]) dist_sun[0] = np.linalg.norm([xfwd[0], yfwd[0], zfwd[0]]) for i in range(fwd_seg): xfwd[i + 1] = rfwd[i + 1][0] / pk.AU yfwd[i + 1] = rfwd[i + 1][1] / pk.AU zfwd[i + 1] = rfwd[i + 1][2] / pk.AU r_E = [ ri / pk.AU for ri in self.__earth.eph(pk.epoch(fwd_grid[i + 1]))[0]] dist_earth[ i + 1] = np.linalg.norm([r_E[0] - xfwd[i + 1], r_E[1] - yfwd[i + 1], r_E[2] - zfwd[i + 1]]) dist_sun[ i + 1] = np.linalg.norm([xfwd[i + 1], yfwd[i + 1], zfwd[i + 1]]) # Backward propagation xbwd = [0.0] * (bwd_seg + 1) ybwd = [0.0] * (bwd_seg + 1) zbwd = [0.0] * (bwd_seg + 1) xbwd[-1] = rbwd[-1][0] / pk.AU ybwd[-1] = rbwd[-1][1] / pk.AU zbwd[-1] = rbwd[-1][2] / pk.AU r_E = [ ri / pk.AU for ri in self.__earth.eph(pk.epoch(bwd_grid[-1]))[0]] dist_earth[-1] = np.linalg.norm([r_E[0] - xbwd[-1], r_E[1] - ybwd[-1], r_E[2] - zbwd[-1]]) dist_sun[-1] = np.linalg.norm([xbwd[-1], ybwd[-1], zbwd[-1]]) for i in range(bwd_seg): xbwd[-i - 2] = rbwd[-i - 2][0] / pk.AU ybwd[-i - 2] = rbwd[-i - 2][1] / pk.AU zbwd[-i - 2] = rbwd[-i - 2][2] / pk.AU r_E = [ ri / pk.AU for ri in self.__earth.eph(pk.epoch(bwd_grid[-i - 2]))[0]] dist_earth[-i - 2] = np.linalg.norm( [r_E[0] - xbwd[-i - 2], r_E[1] - ybwd[-i - 2], r_E[2] - zbwd[-i - 2]]) dist_sun[-i - 2] = np.linalg.norm([xbwd[-i - 2], ybwd[-i - 2], zbwd[-i - 2]]) axes.set_xlabel("t [mjd2000]") # Plot Earth distance axes.plot(times, dist_earth, c='b', label="sc-Earth") # Plot Sun distance axes.plot(times, dist_sun, c='y', label="sc-Sun") axes.set_ylabel("distance [AU]", color='k') axes.set_ylim(bottom=0.) axes.tick_params('y', colors='k') axes.legend(loc=2) # draw threshold where Earth gravity equals 0.1*Tmax if self.__earth_gravity: axes.axhline(y=np.sqrt(pk.MU_EARTH * self.__sc.mass / (self.__sc.thrust * 0.1) ) / pk.AU, c='g', ls=":", lw=1, label="earth_g = 0.1*Tmax") # Plot thrust profile axes = axes.twinx() if self.__sep: max_thrust = self.__sc.thrust thrusts = np.linalg.norm( np.array(ufwd + ubwd), axis=1) / max_thrust # plot maximum thrust achievable at that distance from the Sun distsSun = dist_sun[:fwd_seg] + \ dist_sun[-bwd_seg:] + [dist_sun[-1]] Tmaxs = [self._sep_model(d)[0] / max_thrust for d in distsSun] axes.step(np.concatenate( (fwd_grid, bwd_grid[1:])), Tmaxs, where="post", c='lightgray', linestyle=':') else: thrusts = throttles.copy() # duplicate the last for plotting thrusts = np.append(thrusts, thrusts[-1]) axes.step(np.concatenate( (fwd_grid, bwd_grid[1:])), thrusts, where="post", c='r', linestyle='--') axes.set_ylabel("T/Tmax$_{1AU}$", color='r') axes.tick_params('y', colors='r') axes.set_xlim([times[0], times[-1]]) axes.set_ylim([0, max(thrusts) + 0.2]) return axes
def rate__edelbaum(dep_ast, dep_t, **kwargs): dep_ast = asteroids[dep_ast] dep_t = pk.epoch(dep_t, "mjd") return [edelbaum_dv(dep_ast, arr_ast, dep_t) for arr_ast in asteroids]
intervals = 1.0 start_epochs = np.arange(start_date, end_date, intervals) max_tof = 400.0 duration = np.arange(120.0, max_tof, 1.0) origin = 'earth' destination = 'mars' earth = pk.planet.jpl_lp(origin) mars = pk.planet.jpl_lp(destination) data = list() for start in start_epochs: row = list() for tof in duration: pos_1, v1 = earth.eph(pk.epoch(start, 'mjd2000')) pos_2, v2 = mars.eph(pk.epoch(start + tof, 'mjd2000')) seconds_elapsed = tof * 60 * 60 * 24 if tof > 0 else 1 * 60 * 60 * 24 l = pk.lambert_problem(pos_1, pos_2, seconds_elapsed, pk.MU_SUN) DV1 = np.linalg.norm(np.array(v1) - np.array(l.get_v1()[0])) DV2 = np.linalg.norm(np.array(v2) - np.array(l.get_v2()[0])) DV1 = max([0, DV1 - 4000]) DV = DV1 + DV2 row.append(DV) data.append(row)
from pykep.trajopt import mga_1dsm from pykep.planet import jpl_lp, keplerian from pykep import AU, DEG2RAD, MU_SUN, epoch # ROSETTA (we need to modify the safe radius of the planets to match the wanted problem) _churyumov = keplerian(epoch(52504.23754000012, "mjd"), [ 3.50294972836275 * AU, 0.6319356, 7.12723 * DEG2RAD, 50.92302 * DEG2RAD, 11.36788 * DEG2RAD, 0. * DEG2RAD ], MU_SUN, 0., 0., 0., "Churyumov-Gerasimenko") _mars_rosetta = jpl_lp('mars') _mars_rosetta.safe_radius = 1.05 _seq_rosetta = [ jpl_lp('earth'), jpl_lp('earth'), _mars_rosetta, jpl_lp('earth'), jpl_lp('earth'), _churyumov ] class _rosetta_udp(mga_1dsm): """ This class represents a rendezvous mission to the comet 67P/Churyumov-Gerasimenko modelled as an MGA-1DSM transfer. The fly-by sequence selected (i.e. E-EMEE-C) is similar to the one planned for the spacecraft Rosetta. The objective function considered is the total mission delta V. No launcher model is employed and a final randezvous with the comet is included in the delta V computations. .. note:: A significantly similar version of this problem was part of the no longer maintained GTOP database, https://www.esa.int/gsp/ACT/projects/gtop/gtop.html. The exact definition is, though, different and results
def plot_planet(plnt, t0=0, tf=None, N=60, units=1.0, color='k', alpha=1.0, s=40, legend=(False, False), axes=None): """ ax = plot_planet(plnt, t0=0, tf=None, N=60, units=1.0, color='k', alpha=1.0, s=40, legend=(False, False), axes=None): - axes: 3D axis object created using fig.gca(projection='3d') - plnt: pykep.planet object we want to plot - t0: a pykep.epoch or float (mjd2000) indicating the first date we want to plot the planet position - tf: a pykep.epoch or float (mjd2000) indicating the final date we want to plot the planet position. if None this is computed automatically from the orbital period (prone to error for non periodic orbits) - units: the length unit to be used in the plot - color: color to use to plot the orbit (passed to matplotlib) - s: planet size (passed to matplotlib) - legend 2-D tuple of bool or string: The first element activates the planet scatter plot, the second to the actual orbit. If a bool value is used, then an automated legend label is generated (if True), if a string is used, the string is the legend. Its also possible but deprecated to use a single bool value. In which case that value is used for both the tuple components. Plots the planet position and its orbit. Example:: import pykep as pk import matplotlib.pyplot as plt fig = plt.figure() ax = fig.gca(projection = '3d') pl = pk.planet.jpl_lp('earth') t_plot = pk.epoch(219) ax = pk.orbit_plots.plot_planet(pl, ax = ax, color='b') """ from pykep import MU_SUN, SEC2DAY, epoch, AU, RAD2DEG from pykep.planet import keplerian from math import pi, sqrt import numpy as np import matplotlib.pylab as plt from mpl_toolkits.mplot3d import Axes3D if axes is None: fig = plt.figure() ax = fig.gca(projection='3d') else: ax = axes if type(t0) is not epoch: t0 = epoch(t0) # This is to make the tuple API compatible with the old API if type(legend) is bool: legend = (legend, legend) if tf is None: # orbit period at epoch T = plnt.compute_period(t0) * SEC2DAY else: if type(tf) is not epoch: tf = epoch(tf) T = (tf.mjd2000 - t0.mjd2000) if T < 0: raise ValueError("tf should be after t0 when plotting an orbit") # points where the orbit will be plotted when = np.linspace(0, T, N) # Ephemerides Calculation for the given planet x = np.array([0.0] * N) y = np.array([0.0] * N) z = np.array([0.0] * N) for i, day in enumerate(when): r, v = plnt.eph(epoch(t0.mjd2000 + day)) x[i] = r[0] / units y[i] = r[1] / units z[i] = r[2] / units # Actual plot commands if (legend[0] is True): label1 = plnt.name + " " + t0.__repr__()[0:11] elif (legend[0] is False): label1 = None elif (legend[0] is None): label1 = None else: label1 = legend[0] if (legend[1] is True): label2 = plnt.name + " orbit" elif (legend[1] is False): label2 = None elif (legend[1] is None): label2 = None else: label2 = legend[1] ax.plot(x, y, z, label=label2, c=color, alpha=alpha) ax.scatter([x[0]], [y[0]], [z[0]], s=s, marker='o', alpha=0.8, c=[color], label=label1) if legend[0] or legend[1]: ax.legend() return ax
def fineCorrectionBurn(self): #Propagate orbit to correction burn 1, then apply it to orbit, then propagage further and check. #If okay, then add in the manual inclination correction, and then do a final Lambert. self.AddOrbitPoint("1:319:0:0:0", 14646793325, 9353.0) rMan1, vMan1 = propagate_lagrangian(self.OrbitPoints[-2].r, self.OrbitPoints[-2].v, self.OrbitPoints[-1].t, self.mu_c) print(str(vMan1)) vMan1 = np.asarray(vMan1) vMan1 += [-34.8, 35.9, 0] #?????? WTF norm ok but direction is wrong (apprently) #vMan1 += [-25.87664536,+42.44449723,0] print(str(vMan1)) self.OrbitPoints[-1].r = rMan1 self.OrbitPoints[-1].r_n = norm(rMan1) self.OrbitPoints[-1].v = vMan1 self.OrbitPoints[-1].v_n = norm(vMan1) #Propagate to a new point self.AddOrbitPoint("1:399:3:33:30", 17739170771, 7823.5) rCheck, vCheck = propagate_lagrangian( self.OrbitPoints[-2].r, self.OrbitPoints[-2].v, self.OrbitPoints[-1].t - self.OrbitPoints[-2].t, self.mu_c) self.printVect(rCheck, "r2 pred") self.printVect(vCheck, "v2 pred") self.deltasAtPoint(norm(rCheck), norm(vCheck), (self.OrbitPoints[-1].r_n), (self.OrbitPoints[-1].v_n), "r check fromZero", "v check fromZero") self.AddOrbitPoint("1:417:2:58:04", 18284938767, 7574.6) rCheck, vCheck = propagate_lagrangian( self.OrbitPoints[-3].r, self.OrbitPoints[-3].v, self.OrbitPoints[-1].t - self.OrbitPoints[-3].t, self.mu_c) self.printVect(rCheck, "r3 pred") self.printVect(vCheck, "v3 pred") self.deltasAtPoint(norm(rCheck), norm(vCheck), (self.OrbitPoints[-1].r_n), (self.OrbitPoints[-1].v_n), "r check2 fromZero", "v check2 fromZero") #self.OrbitPoints[-3].r, self.OrbitPoints[-3].v = propagate_lagrangian(self.OrbitPoints[-3].r,self.OrbitPoints[-3].v,0,self.mu_c) plt.rcParams['savefig.dpi'] = 100 ManT = 76 # manoevre time ManT_W = 5 # manoevre window Edy2s = 24 * 3600 dy2s = 6 * 3600 start_epochs = np.arange(ManT, (ManT + ManT_W), 0.25) ETA = 20 ETA_W = 200 duration = np.arange(ETA, (ETA + ETA_W), 0.25) data = list() v_data = list() r_data = list() v1_data = list() for start in start_epochs: row = list() v_row = list() r_row = list() v1_row = list() for T in duration: #Need to replace the kerbin start point by the ship at time t using r1, v1 = propagate_lagrangian( self.OrbitPoints[-3].r, self.OrbitPoints[-3].v, (start) * Edy2s - self.OrbitPoints[-3].t, self.mu_c) #r1,v1 = Kerbin.eph(epoch(start)) r2, v2 = Duna.eph(epoch(start + T)) l = lambert_problem(r1, r2, T * Edy2s, Kerbin.mu_central_body) #K day = 6h DV1 = np.linalg.norm(array(v1) - array(l.get_v1()[0])) v_DV1 = array(v1) - array(l.get_v1()[0]) #DV2 = np.linalg.norm( array(v2)-array(l.get_v2()[0]) ) #DV1 = max([0,DV1-4000]) #DV = DV1+DV2 DV = DV1 #DV = sqrt(dot(DV1, DV1) + 2 * Kerbin.mu_self / Kerbin.safe_radius) - sqrt(Kerbin.mu_self / Kerbin.safe_radius ) r_row.append(r1) v1_row.append(v1) v_row.append(v_DV1) row.append(DV) data.append(row) v_data.append(v_row) r_data.append(r_row) v1_data.append(v1_row) minrows = [min(l) for l in data] i_idx = np.argmin(minrows) j_idx = np.argmin(data[i_idx]) best = data[i_idx][j_idx] v_best = v_data[i_idx][j_idx] r1 = r_data[i_idx][j_idx] v1 = v1_data[i_idx][j_idx] progrd_uv = -array(v1) / linalg.norm(v1) plane_uv = cross(v1, r1) plane_uv = plane_uv / linalg.norm(plane_uv) radial_uv = cross(plane_uv, progrd_uv) EJBK = sqrt( dot(v_best, v_best) + 2 * Kerbin.mu_central_body / norm(r1)) - sqrt(Kerbin.mu_central_body / norm(r1)) progrd_v = dot(progrd_uv, v_best) radial_v = dot(radial_uv, v_best) #print(rad2deg(atan(radial_v/progrd_v))) print("TransX escape plan - Kerbin escape") print("--------------------------------------") print("Best DV: " + str(best)) print("Best DV heliocentric components:" + str(v_best)) print("Launch epoch (K-days): " + str((start_epochs[i_idx]) * 4)) print("Duration (K-days): " + str(duration[j_idx] * 4)) print("Prograde: %10.3f m/s" % np.round(dot(progrd_uv, v_best), 3)) print("Radial: %10.3f m/s" % np.round(dot(radial_uv, v_best), 3)) print("Planar: %10.3f m/s" % np.round(dot(plane_uv, v_best), 3)) print("Hyp. excess velocity:%10.3f m/s" % np.round(sqrt(dot(v_best, v_best)), 3)) #print("Earth escape burn: %10.3f m/s" % np.round(EJBK, 3)) duration_pl, start_epochs_pl = np.meshgrid(duration, start_epochs) plt.contour(start_epochs_pl * 4, duration_pl * 4, array(data), levels=list(np.linspace(best, 3000, 12))) #plt.imshow(array(data).T, cmap=plt.cm.rainbow, origin = "lower", vmin = best, vmax = 5000, extent=[0.0, 850, 10, 470.0], interpolation='bilinear') #plt.colorbar(im); plt.colorbar() plt.show()
def fitness(self, x): from pykep import epoch, AU, EARTH_VELOCITY, fb_con from pykep.sims_flanagan import leg, sc_state from numpy.linalg import norm from math import sqrt, asin, acos retval = [-x[10]] # Ephemerides t_E = epoch(x[0]) t_V = epoch(x[0] + x[1]) t_M = epoch(x[0] + x[1] + x[9]) rE, vE = self.__earth.eph(t_E) rV, vV = self.__venus.eph(t_V) rM, vM = self.__mercury.eph(t_M) # First Leg v = [a + b for a, b in zip(vE, x[3:6])] x0 = sc_state(rE, v, self.__sc.mass) v = [a + b for a, b in zip(vV, x[6:9])] xe = sc_state(rV, v, x[2]) self.__leg1.set( t_E, x0, x[-3 * (self.__nseg1 + self.__nseg2):-self.__nseg2 * 3], t_V, xe) # Second leg v = [a + b for a, b in zip(vV, x[11:14])] x0 = sc_state(rV, v, x[2]) v = [a + b for a, b in zip(vM, x[14:17])] xe = sc_state(rM, v, x[10]) self.__leg2.set(t_E, x0, x[(-3 * self.__nseg2):], t_V, xe) # Defining the constraints # departure v_dep_con = (x[3] * x[3] + x[4] * x[4] + x[5] * x[5] - self.__Vinf_dep * self.__Vinf_dep) / (EARTH_VELOCITY * EARTH_VELOCITY) # arrival v_arr_con = (x[14] * x[14] + x[15] * x[15] + x[16] * x[16] - self.__Vinf_arr * self.__Vinf_arr) / (EARTH_VELOCITY * EARTH_VELOCITY) # fly-by at Venus DV_eq, alpha_ineq = fb_con(x[6:9], x[11:14], self.__venus) # Assembling the constraints constraints = list(self.__leg1.mismatch_constraints() + self.__leg2.mismatch_constraints()) + [DV_eq] + list( self.__leg1.throttles_constraints() + self.__leg2.throttles_constraints()) + [v_dep_con] + [v_arr_con] + [alpha_ineq] # We then scale all constraints to non-dimensional values # leg 1 constraints[0] /= AU constraints[1] /= AU constraints[2] /= AU constraints[3] /= EARTH_VELOCITY constraints[4] /= EARTH_VELOCITY constraints[5] /= EARTH_VELOCITY constraints[6] /= self.__sc.mass # leg 2 constraints[7] /= AU constraints[8] /= AU constraints[9] /= AU constraints[10] /= EARTH_VELOCITY constraints[11] /= EARTH_VELOCITY constraints[12] /= EARTH_VELOCITY constraints[13] /= self.__sc.mass # fly-by at Venus constraints[14] /= (EARTH_VELOCITY * EARTH_VELOCITY) return retval + constraints
def correctionBurn(self): plt.rcParams['savefig.dpi'] = 100 ManT = 76 # manoevre time ManT_W = 200 # manoevre window Edy2s = 24 * 3600 dy2s = 6 * 3600 start_epochs = np.arange(ManT, (ManT + ManT_W), 0.25) ETA = 250 ETA_W = 250 duration = np.arange(ETA, (ETA + ETA_W), 0.25) ''' #these are Earth days, to *4 to Kdays (for eph function). #Sanity checks. r2,v2 = Duna.eph(epoch(312.8*0.25)) #check jool position print(norm(r2)-self.r_c) print(norm(v2)) r1,v1 = propagate_lagrangian(self.OrbitPoints[-1].r,self.OrbitPoints[-1].v,312.8*dy2s,self.mu_c) print(norm(r1)-self.r_c) print(norm(v1)) ''' ''' Solving the lambert problem. the function need times in Edays, so convert later to Kdays. Carefull with the Jool ephemeris, since kerbol year starts at y1 d1, substract 1Kday = 0.25Eday ''' data = list() v_data = list() r_data = list() v1_data = list() for start in start_epochs: row = list() v_row = list() r_row = list() v1_row = list() for T in duration: #Need to replace the kerbin start point by the ship at time t using r1, v1 = propagate_lagrangian(self.OrbitPoints[-1].r, self.OrbitPoints[-1].v, (start) * Edy2s, self.mu_c) #r1,v1 = Kerbin.eph(epoch(start)) r2, v2 = Jool.eph(epoch(start + T)) l = lambert_problem(r1, r2, T * Edy2s, Kerbin.mu_central_body) #K day = 6h DV1 = np.linalg.norm(array(v1) - array(l.get_v1()[0])) v_DV1 = array(v1) - array(l.get_v1()[0]) #DV2 = np.linalg.norm( array(v2)-array(l.get_v2()[0]) ) #DV1 = max([0,DV1-4000]) #DV = DV1+DV2 DV = DV1 #DV = sqrt(dot(DV1, DV1) + 2 * Kerbin.mu_self / Kerbin.safe_radius) - sqrt(Kerbin.mu_self / Kerbin.safe_radius ) r_row.append(r1) v1_row.append(v1) v_row.append(v_DV1) row.append(DV) data.append(row) v_data.append(v_row) r_data.append(r_row) v1_data.append(v1_row) minrows = [min(l) for l in data] i_idx = np.argmin(minrows) j_idx = np.argmin(data[i_idx]) best = data[i_idx][j_idx] v_best = v_data[i_idx][j_idx] r1 = r_data[i_idx][j_idx] v1 = v1_data[i_idx][j_idx] progrd_uv = -array(v1) / linalg.norm(v1) plane_uv = cross(v1, r1) plane_uv = plane_uv / linalg.norm(plane_uv) radial_uv = cross(plane_uv, progrd_uv) EJBK = sqrt( dot(v_best, v_best) + 2 * Kerbin.mu_central_body / norm(r1)) - sqrt(Kerbin.mu_central_body / norm(r1)) progrd_v = dot(progrd_uv, v_best) radial_v = dot(radial_uv, v_best) #print(rad2deg(atan(radial_v/progrd_v))) print("TransX escape plan - Kerbin escape") print("--------------------------------------") print("Best DV: " + str(best)) print("Best DV heliocentric components:" + str(v_best)) print("Launch epoch (K-days): " + str((start_epochs[i_idx]) * 4)) print("Duration (K-days): " + str(duration[j_idx] * 4)) print("Prograde: %10.3f m/s" % np.round(dot(progrd_uv, v_best), 3)) print("Radial: %10.3f m/s" % np.round(dot(radial_uv, v_best), 3)) print("Planar: %10.3f m/s" % np.round(dot(plane_uv, v_best), 3)) print("Hyp. excess velocity:%10.3f m/s" % np.round(sqrt(dot(v_best, v_best)), 3)) #print("Earth escape burn: %10.3f m/s" % np.round(EJBK, 3)) duration_pl, start_epochs_pl = np.meshgrid(duration, start_epochs) plt.contour(start_epochs_pl * 4, duration_pl * 4, array(data), levels=list(np.linspace(best, 3000, 12))) #plt.imshow(array(data).T, cmap=plt.cm.rainbow, origin = "lower", vmin = best, vmax = 5000, extent=[0.0, 850, 10, 470.0], interpolation='bilinear') #plt.colorbar(im); plt.colorbar() plt.show()
tof=tof, vinf=[0.5, 2.5], add_vinf_dep=False, add_vinf_arr=True, tof_encoding=tof_encoding, multi_objective=False) def get_name(self): return "Earth-Venus-Earth mga-1dsm (Trajectory Optimisation Gym P7-9)" def get_extra_info(self): retval = "\ttof_encoding: " + self._tof_encoding return retval def __repr__(self): return self.get_name() # Problem P7: Earth-Venus-Earth MGA1DSM, single objective , direct encoding eve_mga1dsm = _eve_mga1dsm_udp(tof_encoding='direct', t0=[epoch(0), epoch(3000)], tof=[[10, 500], [10, 500]]) # Problem P8: Earth-Venus-Earth MGA1DSM, single objective , alpha encoding eve_mga1dsm_a = _eve_mga1dsm_udp(tof_encoding='alpha', t0=[epoch(0), epoch(3000)], tof=[300, 700]) # Problem P9: Earth-Venus-Earth MGA1DSM, single objective , eta encoding eve_mga1dsm_n = _eve_mga1dsm_udp(tof_encoding='eta', t0=[epoch(0), epoch(3000)], tof=700)
def __init__(self, seq=[pk.planet.jpl_lp('earth'), pk.planet.jpl_lp( 'venus'), pk.planet.jpl_lp('earth')], t0=[0, 1000], tof=[100, 500], vinf=2.5, multi_objective=False, tof_encoding='direct', orbit_insertion=False, e_target=None, rp_target=None ): """mga(seq=[pk.planet.jpl_lp('earth'), pk.planet.jpl_lp('venus'), pk.planet.jpl_lp('earth')], t0=[0, 1000], tof=[100, 500], vinf=2.5, multi_objective=False, alpha_encoding=False, orbit_insertion=False, e_target=None, rp_target=None) Args: - seq (``list of pk.planet``): sequence of body encounters including the starting object - t0 (``list of pk.epoch``): the launch window - tof (``list`` or ``float``): bounds on the time of flight. If *tof_encoding* is 'direct', this contains a list of 2D lists defining the upper and lower bounds on each leg. If *tof_encoding* is 'alpha', this contains a 2D list with the lower and upper bounds on the time-of-flight. If *tof_encoding* is 'eta' tof is a float defining the upper bound on the time-of-flight - vinf (``float``): the vinf provided at launch for free - multi_objective (``bool``): when True constructs a multiobjective problem (dv, T). In this case, 'alpha' or `eta` encodings are reccomended - tof_encoding (``str``): one of 'direct', 'alpha' or 'eta'. Selects the encoding for the time of flights - orbit_insertion (``bool``): when True the arrival dv is computed as that required to acquire a target orbit defined by e_target and rp_target - e_target (``float``): if orbit_insertion is True this defines the target orbit eccentricity around the final planet - rp_target (``float``): if orbit_insertion is True this defines the target orbit pericenter around the final planet Raises: - ValueError: if *planets* do not share the same central body (checked on the mu_central_body attribute) - ValueError: if *t0* does not contain objects able to construct a pk.epoch (e.g. pk. epoch or floats) - ValueError: if *tof* is badly defined - ValueError: it the target orbit is not defined and *orbit_insertion* is True """ # Sanity checks # 1 - All planets need to have the same mu_central_body if ([r.mu_central_body for r in seq].count(seq[0].mu_central_body) != len(seq)): raise ValueError( 'All planets in the sequence need to have exactly the same mu_central_body') # 2 - We try to build epochs out of the t0 list (mjd2000 by default) for i in range(len(t0)): if (type(t0[i]) != type(pk.epoch(0))): t0[i] = pk.epoch(t0[i]) # 3 - Check the tof bounds if tof_encoding is 'alpha': if len(tof) != 2: raise ValueError( 'When tof_encoding is alpha, the tof must have a length of 2 (lower and upper bounds on the tof)') elif tof_encoding is 'direct': if len(tof) != (len(seq) - 1): raise ValueError( 'When tof_encoding is direct, the tof must be a float (upper bound on the time of flight)' + str(len(seq) - 1)) elif tof_encoding is 'eta': if type(tof) != type(0.1): raise ValueError( 'The tof needs to be have len equal to ' + str(len(seq) - 1)) if not tof_encoding in ['alpha', 'eta', 'direct']: raise ValueError( "tof_encoding must be one of 'alpha', 'eta', 'direct'") # 4 - Check that if orbit insertion is selected e_target and r_p are # defined if orbit_insertion: if rp_target is None: raise ValueError( 'The rp_target needs to be specified when orbit insertion is selected') if e_target is None: raise ValueError( 'The e_target needs to be specified when orbit insertion is selected') # Public data members self.seq = seq self.t0 = t0 self.tof = tof self.vinf = vinf * 1000 self.multi_objective = multi_objective self.tof_encoding = tof_encoding self.orbit_insertion = orbit_insertion self.e_target = e_target self.rp_target = rp_target # Private data members self._n_legs = len(seq) - 1 self._common_mu = seq[0].mu_central_body
def __init__(self, target=pk.planet.mpcorb(mpcorbline), n_seg=30, grid_type="uniform", t0=[pk.epoch(8000), pk.epoch(9000)], tof=[200, 365.25 * 3], m0=20.0, Tmax=0.0017, Isp=3000.0, earth_gravity=False, sep=False, start="earth"): """ prob = lt_margo(target = pk.planet.mpcorb(mpcorbline), n_seg = 30, grid_type = "uniform", t0 = [epoch(8000), epoch(9000)], tof = [200, 365.25*3], m0 = 20.0, Tmax = 0.0017, Isp = 3000.0, earth_gravity = False, sep = False, start = "earth") Args: - target (``pykep.planet``): target planet - n_seg (``int``): number of segments to use in the problem transcription (time grid) - grid_type (``string``): "uniform" for uniform segments, "nonuniform" toi use a denser grid in the first part of the trajectory - t0 (``list``): list of two pykep.epoch defining the bounds on the launch epoch - tof (``list``): list of two floats defining the bounds on the time of flight (days) - m0 (``float``): initial mass of the spacecraft (kg) - Tmax (``float``): maximum thrust at 1 AU (N) - Isp (``float``): engine specific impulse (s) - earth_gravity (``bool``): activates the Earth gravity effect in the dynamics - sep (``bool``): Activates a Solar Electric Propulsion model for the thrust - distance dependency. - start(``string``): Starting point ("earth", "l1", or "l2"). .. note:: L1 and L2 are approximated as the points on the line connecting the Sun and the Earth at a distance of, respectively, 0.99 and 1.01 AU from the Sun. .. note:: If the Earth's gravity is enabled, the starting point cannot be the Earth """ # 1) Various checks if start not in ["earth", "l1", "l2"]: raise ValueError("start must be either 'earth', 'l1' or 'l2'") if grid_type not in ["uniform", "nonuniform"]: raise ValueError( "grid_type must be either 'uniform' or 'nonuniform'") if earth_gravity and start == "earth": raise ValueError( "If Earth gravity is enabled the starting point cannot be the Earth") # 2) Class data members # public: self.target = target # private: self.__n_seg = n_seg self.__grid_type = grid_type self.__sc = pk.sims_flanagan._sims_flanagan.spacecraft(m0, Tmax, Isp) self.__earth = pk.planet.jpl_lp('earth') self.__earth_gravity = earth_gravity self.__sep = sep self.__start = start # grid construction if grid_type == "uniform": grid = np.array([i / n_seg for i in range(n_seg + 1)]) elif grid_type == "nonuniform": grid_f = lambda x: x**2 if x < 0.5 else 0.25 + 1.5 * \ (x - 0.5) # quadratic in [0,0.5], linear in [0.5,1] grid = np.array([grid_f(i / n_seg) for i in range(n_seg + 1)]) # index corresponding to the middle of the transfer fwd_seg = int(np.searchsorted(grid, 0.5, side='right')) bwd_seg = n_seg - fwd_seg fwd_grid = grid[:fwd_seg + 1] bwd_grid = grid[fwd_seg:] self.__fwd_seg = fwd_seg self.__fwd_grid = fwd_grid self.__fwd_dt = np.array([(fwd_grid[i + 1] - fwd_grid[i]) for i in range(fwd_seg)]) * pk.DAY2SEC self.__bwd_seg = bwd_seg self.__bwd_grid = bwd_grid self.__bwd_dt = np.array([(bwd_grid[i + 1] - bwd_grid[i]) for i in range(bwd_seg)]) * pk.DAY2SEC # 3) Bounds lb = [t0[0].mjd2000] + [tof[0]] + [0] + [-1, -1, -1] * n_seg ub = [t0[1].mjd2000] + [tof[1]] + [m0] + [1, 1, 1] * n_seg self.__lb = lb self.__ub = ub
def plot_traj(self, x, units=pk.AU, plot_segments=True, plot_thrusts=False, axes=None): """ ax = prob.plot_traj(self, x, units=AU, plot_segments=True, plot_thrusts=False, axes=None) Args: - x (``list``, ``tuple``, ``numpy.ndarray``): Decision chromosome, e.g. (``pygmo.population.champion_x``). - units (``float``): the length unit to be used in the plot - plot_segments (``bool``): when True plots also the segments boundaries - plot_thrusts (``bool``): when True plots also the thrust vectors Returns: matplotlib.axes: axes where to plot Visualizes the the trajectory in a 3D plot """ if not len(x) == len(self.get_bounds()[0]): raise ValueError("Invalid length of the decision vector x") import matplotlib as mpl import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D # Creating the axes if necessary if axes is None: mpl.rcParams['legend.fontsize'] = 10 fig = plt.figure() axes = fig.gca(projection='3d') n_seg = self.__n_seg fwd_seg = self.__fwd_seg bwd_seg = self.__bwd_seg t0 = x[0] T = x[1] isp = self.__sc.isp veff = isp * pk.G0 fwd_grid = t0 + T * self.__fwd_grid # days bwd_grid = t0 + T * self.__bwd_grid # days throttles = [x[3 + 3 * i: 6 + 3 * i] for i in range(n_seg)] alphas = [min(1., np.linalg.norm(t)) for t in throttles] times = np.concatenate((fwd_grid, bwd_grid)) rfwd, rbwd, vfwd, vbwd, mfwd, mbwd, ufwd, ubwd, fwd_dt, bwd_dt, dfwd, dbwd = self._propagate( x) # Plotting the Sun, the Earth and the target axes.scatter([0], [0], [0], color='y') pk.orbit_plots.plot_planet(self.__earth, pk.epoch( t0), units=units, legend=True, color=(0.7, 0.7, 1), ax=axes) pk.orbit_plots.plot_planet(self.target, pk.epoch( t0 + T), units=units, legend=True, color=(0.7, 0.7, 1), ax=axes) # Forward propagation xfwd = [0.0] * (fwd_seg + 1) yfwd = [0.0] * (fwd_seg + 1) zfwd = [0.0] * (fwd_seg + 1) xfwd[0] = rfwd[0][0] / units yfwd[0] = rfwd[0][1] / units zfwd[0] = rfwd[0][2] / units for i in range(fwd_seg): if self.__sep: r = math.sqrt(rfwd[i][0]**2 + rfwd[i][1] ** 2 + rfwd[i][2]**2) / pk.AU _, isp = self._sep_model(r) veff = isp * pk.G0 if self.__earth_gravity: r3 = sum([r**2 for r in dfwd[i]])**(3 / 2) disturbance = [mfwd[i] * pk.MU_EARTH / r3 * ri for ri in dfwd[i]] pk.orbit_plots.plot_taylor_disturbance(rfwd[i], vfwd[i], mfwd[i], ufwd[i], disturbance, fwd_dt[ i], pk.MU_SUN, veff, N=10, units=units, color=(alphas[i], 0, 1 - alphas[i]), ax=axes) else: pk.orbit_plots.plot_taylor(rfwd[i], vfwd[i], mfwd[i], ufwd[i], fwd_dt[ i], pk.MU_SUN, veff, N=10, units=units, color=(alphas[i], 0, 1 - alphas[i]), ax=axes) xfwd[i + 1] = rfwd[i + 1][0] / units yfwd[i + 1] = rfwd[i + 1][1] / units zfwd[i + 1] = rfwd[i + 1][2] / units if plot_segments: axes.scatter(xfwd[:-1], yfwd[:-1], zfwd[:-1], label='nodes', marker='o', s=5, c='k') # Backward propagation xbwd = [0.0] * (bwd_seg + 1) ybwd = [0.0] * (bwd_seg + 1) zbwd = [0.0] * (bwd_seg + 1) xbwd[-1] = rbwd[-1][0] / units ybwd[-1] = rbwd[-1][1] / units zbwd[-1] = rbwd[-1][2] / units for i in range(bwd_seg): if self.__sep: r = math.sqrt(rbwd[-i - 1][0]**2 + rbwd[-i - 1] [1]**2 + rbwd[-i - 1][2]**2) / pk.AU _, isp = self._sep_model(r) veff = isp * pk.G0 if self.__earth_gravity: r3 = sum([r**2 for r in dbwd[-i - 1]])**(3 / 2) disturbance = [mfwd[i] * pk.MU_EARTH / r3 * ri for ri in dbwd[-i - 1]] pk.orbit_plots.plot_taylor_disturbance(rbwd[-i - 1], vbwd[-i - 1], mbwd[-i - 1], ubwd[-i - 1], disturbance, -bwd_dt[ -i - 1], pk.MU_SUN, veff, N=10, units=units, color=(alphas[-i - 1], 0, 1 - alphas[-i - 1]), ax=axes) else: pk.orbit_plots.plot_taylor(rbwd[-i - 1], vbwd[-i - 1], mbwd[-i - 1], ubwd[-i - 1], -bwd_dt[-i - 1], pk.MU_SUN, veff, N=10, units=units, color=(alphas[-i - 1], 0, 1 - alphas[-i - 1]), ax=axes) xbwd[-i - 2] = rbwd[-i - 2][0] / units ybwd[-i - 2] = rbwd[-i - 2][1] / units zbwd[-i - 2] = rbwd[-i - 2][2] / units if plot_segments: axes.scatter(xbwd[1:], ybwd[1:], zbwd[1:], marker='o', s=5, c='k') # Plotting the thrust vectors if plot_thrusts: throttles = np.array(throttles) xlim = axes.get_xlim() xrange = xlim[1] - xlim[0] ylim = axes.get_ylim() yrange = ylim[1] - ylim[0] zlim = axes.get_zlim() zrange = zlim[1] - zlim[0] scale = 0.1 throttles[:, 0] *= xrange throttles[:, 1] *= yrange throttles[:, 2] *= zrange throttles *= scale for (x, y, z, t) in zip(xfwd[:-1] + xbwd[:-1], yfwd[:-1] + ybwd[:-1], zfwd[:-1] + zbwd[:-1], throttles): axes.plot([x, x + t[0]], [y, y + t[1]], [z, z + t[2]], c='g') return axes
# http://en.wikipedia.org/wiki/Orbital_period#Calculation # Instantiating PyKEP planet objects for each of the bodies (and making them indexable by body name) # http://keptoolbox.sourceforge.net/documentation.html#PyKEP.planet _planet = pk.planet.keplerian ### Problem is with the planet consutrctor or smth. body_obj = OrderedDict([ ( _b.body, _planet( # when # a PyKEP.epoch indicating the orbital elements epoch pk.epoch(_b.Epoch), #, pk.epoch.epoch_type.MJD ), # orbital_elements # a sequence of six containing a,e,i,W,w,M (SI units, i.e. meters and radiants) ( _b.a * 1000., _b.e, radians(_b.i), radians(_b.Node), radians(_b.w), _b.M, ), # mu_central_body # gravity parameter of the central body (SI units, i.e. m^2/s^3) _b.mu_c * 1000.**3,
# asteroid. The second asteroid encounter (fly-by) corresponds to the delivery # of a 1 kg penetrator." MASS_EQUIPMENT = 40.0 MASS_PENETRATOR = 1.0 # constraint for the flyby to deliver the penetrator: # "flyby asteroid with a velocity not less than dV_min = 0.4 km/s." dV_fb_min = 400.0 # m/s # "The flight time, measured from start to the end must not exceed 15 years" TIME_MAX = 15 * YEAR2DAY # 5478.75 days # "The year of launch must lie in the range 2015 to 2025, inclusive: # 57023 MJD <= t_s <= 61041 MJD." TRAJ_START_MIN = pk.epoch(57023, "mjd") TRAJ_START_MAX = pk.epoch(61041, "mjd") # >>> TRAJ_START_MIN, TRAJ_START_MAX # (2015-Jan-01 00:00:00, 2026-Jan-01 00:00:00) TRAJ_END_MIN = pk.epoch(TRAJ_START_MIN.mjd + TIME_MAX, "mjd") TRAJ_END_MAX = pk.epoch(TRAJ_START_MAX.mjd + TIME_MAX, "mjd") # >>> TRAJ_END_MIN, TRAJ_END_MAX # (2029-Dec-31 18:00:00, 2040-Dec-31 18:00:00) # ==================================== # GTOC5 asteroids (body objects) # Earth's Keplerian orbital parameters # Source: http://dx.doi.org/10.2420/AF08.2014.9 (Table 1) _earth_op = (
def lpop_single(target_mjd): return pykep_satellite.eph(pykep.epoch(target_mjd, 'mjd'))
for qq in range(1, numOfExperiments + 1): satcat = loadData_satcat() debris = loadData_tle() # list of all EU states and ESA and its bodies EU_list = [ "EU", "ASRA", "BEL", "CZCH", "DEN", "ESA", "ESRO", "EST", "EUME", "EUTE", "FGER", "FR", "FRIT", "GER", "GREC", "HUN", "IT", "LTU", "LUXE", "NETH", "NOR", "POL", "POR", "SPN", "SWED", "SWTZ", "UK" ] agentList = ['CIS', 'US', 'PRC', 'EU'] agentListWithEU = ['CIS', 'US', 'PRC', EU_list] # filtering only objects in LEO debris_LEO = [] ep = kep.epoch(16. * 365.25) for p in debris: try: oe = p.osculating_elements(ep) if oe[0] * (1 - oe[1]) < 6378000.0 + 2000000: debris_LEO.append(p) except: pass debris = debris_LEO logger.info(len(debris)) # osculating elements distributions oe_histograms = [] oe_histograms = findHistograms(agentListWithEU) yearLaunchesDistributions = oe_histograms[10]
def _propagate(self, x): # 1 - We decode the chromosome t0 = x[0] T = x[1] m_f = x[2] # We extract the number of segments for forward and backward # propagation n_seg = self.__n_seg fwd_seg = self.__fwd_seg bwd_seg = self.__bwd_seg # We extract information on the spacecraft m_i = self.__sc.mass max_thrust = self.__sc.thrust isp = self.__sc.isp veff = isp * pk.G0 # And on the leg throttles = [x[3 + 3 * i: 6 + 3 * i] for i in range(n_seg)] # Return lists n_points_fwd = fwd_seg + 1 n_points_bwd = bwd_seg + 1 rfwd = [[0.0] * 3] * (n_points_fwd) vfwd = [[0.0] * 3] * (n_points_fwd) mfwd = [0.0] * (n_points_fwd) ufwd = [[0.0] * 3] * (fwd_seg) dfwd = [[0.0] * 3] * (fwd_seg) # distances E/S rbwd = [[0.0] * 3] * (n_points_bwd) vbwd = [[0.0] * 3] * (n_points_bwd) mbwd = [0.0] * (n_points_bwd) ubwd = [[0.0] * 3] * (bwd_seg) dbwd = [[0.0] * 3] * (bwd_seg) # 2 - We compute the initial and final epochs and ephemerides t_i = pk.epoch(t0) r_i, v_i = self.__earth.eph(t_i) if self.__start == 'l1': r_i = [r * 0.99 for r in r_i] v_i = [v * 0.99 for v in v_i] elif self.__start == 'l2': r_i = [r * 1.01 for r in r_i] v_i = [v * 1.01 for v in v_i] t_f = pk.epoch(t0 + T) r_f, v_f = self.target.eph(t_f) # 3 - Forward propagation fwd_grid = t0 + T * self.__fwd_grid # days fwd_dt = T * self.__fwd_dt # seconds # Initial conditions rfwd[0] = r_i vfwd[0] = v_i mfwd[0] = m_i # Propagate for i, t in enumerate(throttles[:fwd_seg]): if self.__sep: r = math.sqrt(rfwd[i][0]**2 + rfwd[i][1] ** 2 + rfwd[i][2]**2) / pk.AU max_thrust, isp = self._sep_model(r) veff = isp * pk.G0 ufwd[i] = [max_thrust * thr for thr in t] if self.__earth_gravity: r_E, v_E = self.__earth.eph(pk.epoch(fwd_grid[i])) dfwd[i] = [a - b for a, b in zip(r_E, rfwd[i])] r3 = sum([r**2 for r in dfwd[i]])**(3 / 2) disturbance = [mfwd[i] * pk.MU_EARTH / r3 * ri for ri in dfwd[i]] rfwd[i + 1], vfwd[i + 1], mfwd[i + 1] = pk.propagate_taylor_disturbance( rfwd[i], vfwd[i], mfwd[i], ufwd[i], disturbance, fwd_dt[i], pk.MU_SUN, veff, -10, -10) else: rfwd[i + 1], vfwd[i + 1], mfwd[i + 1] = pk.propagate_taylor( rfwd[i], vfwd[i], mfwd[i], ufwd[i], fwd_dt[i], pk.MU_SUN, veff, -10, -10) # 4 - Backward propagation bwd_grid = t0 + T * self.__bwd_grid # days bwd_dt = T * self.__bwd_dt # seconds # Final conditions rbwd[-1] = r_f vbwd[-1] = v_f mbwd[-1] = m_f # Propagate for i, t in enumerate(throttles[-1:-bwd_seg - 1:-1]): if self.__sep: r = math.sqrt(rbwd[-i - 1][0]**2 + rbwd[-i - 1] [1]**2 + rbwd[-i - 1][2]**2) / pk.AU max_thrust, isp = self._sep_model(r) veff = isp * pk.G0 ubwd[-i - 1] = [max_thrust * thr for thr in t] if self.__earth_gravity: r_E, v_E = self.__earth.eph(pk.epoch(bwd_grid[-i - 1])) dbwd[-i - 1] = [a - b for a, b in zip(r_E, rbwd[-i - 1])] r3 = sum([r**2 for r in dbwd[-i - 1]])**(3 / 2) disturbance = [mfwd[i] * pk.MU_EARTH / r3 * ri for ri in dbwd[-i - 1]] rbwd[-i - 2], vbwd[-i - 2], mbwd[-i - 2] = pk.propagate_taylor_disturbance( rbwd[-i - 1], vbwd[-i - 1], mbwd[-i - 1], ubwd[-i - 1], disturbance, -bwd_dt[-i - 1], pk.MU_SUN, veff, -10, -10) else: rbwd[-i - 2], vbwd[-i - 2], mbwd[-i - 2] = pk.propagate_taylor( rbwd[-i - 1], vbwd[-i - 1], mbwd[-i - 1], ubwd[-i - 1], -bwd_dt[-i - 1], pk.MU_SUN, veff, -10, -10) return rfwd, rbwd, vfwd, vbwd, mfwd, mbwd, ufwd, ubwd, fwd_dt, bwd_dt, dfwd, dbwd
def from_mjd_to_datetime(mjd_date): e = pykep.epoch(mjd_date, 'mjd') return datetime.datetime.strptime(str(e), '%Y-%b-%d %H:%M:%S.%f')
self.SMA = (self.Pe + self.Ap) / 2 self.e = 1 - 2 * self.Pe / (self.Pe + self.Ap) self.t0 = 0 self.t1 = 0 self.r0 = 0 self.r1 = 0 self.v0 = 0 self.v1 = 0 self.N = sqrt(Kerbin.mu_c / (self.SMA ^ 3)) def setT0(self, year, day, hour, minute, second): h2s = 3600 d2s = 6 * h2s y2s = 2556.5 * h2s self.t0 = year * y2s + day * d2s + hour * h2s + minute * 60 + second def setT1(self, year, day, hour, minute, second): h2s = 3600 d2s = 6 * h2s y2s = 2556.5 * h2s self.t0 = year * y2s + day * d2s + hour * h2s + minute * 60 + second def EccAnom(self): K = PI / 180 max_i = 50 i = 0 delta = 0.0001 plot_innerKerbol(epoch(100))