def __init__(self, multi_objective, tof_encoding, tof): """ Args: - multi_objective (``bool``): when True the problem fitness will return also the time of flight as an added objective - tof_encoding (``str``): one of 'direct', 'eta' or 'alpha'. Selects the encoding for the time of flights - tof (``list`` or ``list`` of ``list``): time of flight bounds. As documented in ``pykep.mga_1dsm`` """ # Redefining the planets as to change their safe radius earth = jpl_lp('earth') earth.safe_radius = 1.05 # We need the Earth eph in the fitnes venus = jpl_lp('venus') venus.safe_radius = 1.05 mars = jpl_lp('mars') mars.safe_radius = 1.05 jupiter = jpl_lp('jupiter') super().__init__( seq=[earth, earth, venus, earth, mars, earth, jupiter], t0=[8000, 8400], tof=tof, vinf=[1., 4.], add_vinf_dep=False, add_vinf_arr=True, tof_encoding=tof_encoding, multi_objective=multi_objective, orbit_insertion=True, e_target=0.98531407996358, rp_target=1070400000, eta_lb=0.01, eta_ub=0.99, rp_ub=10)
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 goto_mars(): # We define an Earth-Mars problem (single-objective) seq = [jpl_lp('earth'), jpl_lp('mars')] udp = mga_1dsm(seq=seq, t0=[epoch(18 * 365.25 + 1), epoch(25 * 365.25 + 1)], tof=[0.7 * 365.25, 7 * 365.25], vinf=[0.5, 5], add_vinf_dep=False, add_vinf_arr=True, multi_objective=False) pg.problem(udp) # We solve it!! uda = pg.sade(gen=200) archi = pg.archipelago(algo=uda, prob=udp, n=8, pop_size=30) 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()) print(f"\nThe best solution with Dv = {min(sols)[0]}:\n") udp.pretty(archi.get_champions_x()[idx]) udp.plot(archi.get_champions_x()[idx], savepath="plot.png")
def run_example2(): import matplotlib as mpl from mpl_toolkits.mplot3d import Axes3D import matplotlib.pyplot as plt from pykep import epoch, DAY2SEC, AU, MU_SUN, lambert_problem from pykep.planet import jpl_lp from pykep.orbit_plots import plot_planet, plot_lambert mpl.rcParams['legend.fontsize'] = 10 fig = plt.figure() axis = fig.gca(projection='3d') t1 = epoch(0) t2 = epoch(640) dt = (t2.mjd2000 - t1.mjd2000) * DAY2SEC axis.scatter([0], [0], [0], color='y') pl = jpl_lp('earth') plot_planet(pl, t0=t1, color=(0.8, 0.8, 1), legend=True, units=AU, ax=axis) rE, vE = pl.eph(t1) pl = jpl_lp('mars') plot_planet(pl, t0=t2, color=(0.8, 0.8, 1), legend=True, units=AU, ax=axis) rM, vM = pl.eph(t2) l = lambert_problem(rE, rM, dt, MU_SUN) plot_lambert(l, color='b', legend=True, units=AU, ax=axis) plot_lambert(l, sol=1, color='g', legend=True, units=AU, ax=axis) plot_lambert(l, sol=2, color='g', legend=True, units=AU, 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 __init__(self, N=3): super(_emNimp_udp, self).__init__(start=planet.jpl_lp('earth'), target=planet.jpl_lp('mars'), N_max=N, tof=[200., 700.], vinf=[0., 4.], phase_free=False, multi_objective=False, t0=[10000, 11000]) self.N = N
def __init__(self, N = 3): super(_emNimp_udp, self).__init__( start=planet.jpl_lp('earth'), target=planet.jpl_lp('mars'), N_max=N, tof=[200., 700.], vinf=[0., 4.], phase_free=False, multi_objective=False, t0=[10000, 11000] ) self.N = N
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 __init__(self, seq=[jpl_lp('earth'), jpl_lp('venus'), jpl_lp('mercury')], n_seg=[5, 20], t0=[3000, 4000], tof=[[100, 1000], [200, 2000]], vinf_dep=3, vinf_arr=2, mass=[1200., 2000.0], Tmax=0.5, Isp=3500.0, fb_rel_vel=6, multi_objective=False, high_fidelity=False): """ Args: - seq (```list of pykep.planet```): defines the encounter sequence for the trajectory (including the initial planet). - n_seg (```list``` of ```int```): the number of segments to be used for each leg. - t0 (```list``` of ```floats```): the launch window (in mjd2000). - tof (```list``` of ```2D-list```): minimum and maximum time of each leg (days). - vinf_dep (```float```): maximum launch hyperbolic velocity allowed (in km/sec). - vinf_arr (```float```): maximum arrival hyperbolic velocity allowed (in km/sec). - mass (```float```): spacecraft starting mass. (in kg). - Tmax (```float```): maximum thrust (in N). - Isp (```float```):: engine specific impulse (in s). . - fb_rel_vel (```float```): determines the bounds on the maximum allowed relative velocity at all fly-bys (in km/sec). - multi-objective (```bool```): when True defines the problem as a multi-objective problem, returning total DV and time of flight. - high_fidelity (```bool```):makes the trajectory computations slower, but actually dynamically feasible. """ # We define some data members (we use the double underscore to # indicate they are private) self._seq = seq self._n_seg = n_seg self._t0 = t0 self._tof = tof self._vinf_dep = vinf_dep * 1000 self._vinf_arr = vinf_arr * 1000 self._mass = mass self._Tmax = Tmax self._fb_rel_vel = fb_rel_vel self._multiobjective = multi_objective self._high_fidelity = high_fidelity self._n_legs = len(seq) - 1 self._sc = spacecraft(mass[1], Tmax, Isp) self._leg = leg() self._leg.set_mu(MU_SUN) self._leg.set_spacecraft(self._sc)
def __init__(self, N=3): """ Write Me """ super().__init__( start=jpl_lp('earth'), target=jpl_lp('mars'), N_max=N, tof=[200., 700.], vinf=[0., 4.], phase_free=False, multi_objective=False, t0=[10000, 11000] ) self.N = N
def __init__(self, tof_encoding='direct', t0=[epoch(0), epoch(3000)], tof=[[10, 500], [10, 500]]): """ Write Me """ super().__init__( seq=[jpl_lp('earth'), jpl_lp('venus'), jpl_lp('earth')], t0=t0, tof=tof, vinf=[0.5, 2.5], add_vinf_dep=False, add_vinf_arr=True, tof_encoding=tof_encoding, multi_objective=False)
def __init__(self, seq=[jpl_lp('earth'), jpl_lp('venus'), jpl_lp('earth')], t0=[epoch(0), epoch(1000)], tof=[1.0, 5.0], vinf=[0.5, 2.5], add_vinf_dep=False, add_vinf_arr=True, multi_objective=False): """ pykep.trajopt.mga_1dsm(seq = [jpl_lp('earth'), jpl_lp('venus'), jpl_lp('earth')], t0 = [epoch(0),epoch(1000)], tof = [1.0,5.0], vinf = [0.5, 2.5], multi_objective = False, add_vinf_dep = False, add_vinf_arr=True) - seq: list of pykep planets defining the encounter sequence (including the starting launch) - t0: list of two epochs defining the launch window - tof: list of two floats defining the minimum and maximum allowed mission lenght (days) - vinf: list of two floats defining the minimum and maximum allowed initial hyperbolic velocity (at launch), in km/sec - multi_objective: when True constructs a multiobjective problem (dv, T) - add_vinf_dep: when True the computed Dv includes the initial hyperbolic velocity (at launch) - add_vinf_arr: when True the computed Dv includes the final hyperbolic velocity (at the last planet) """ # Sanity checks ...... 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' ) self.__add_vinf_dep = add_vinf_dep self.__add_vinf_arr = add_vinf_arr self.__n_legs = len(seq) - 1 self._t0 = t0 self._tof = tof self._vinf = vinf self._obj_dim = multi_objective + 1 # We then define all planets in the sequence and the common central # body gravity as data members self.seq = seq self.common_mu = seq[0].mu_central_body
def __init__(self, seq=[jpl_lp('earth'), jpl_lp('venus'), jpl_lp('earth')], t0=[epoch(0), epoch(1000)], tof=[1.0, 5.0], vinf=[0.5, 2.5], add_vinf_dep=False, add_vinf_arr=True, multi_objective=False): """ pykep.trajopt.mga_1dsm(seq = [jpl_lp('earth'), jpl_lp('venus'), jpl_lp('earth')], t0 = [epoch(0),epoch(1000)], tof = [1.0,5.0], vinf = [0.5, 2.5], multi_objective = False, add_vinf_dep = False, add_vinf_arr=True) - seq: list of pykep planets defining the encounter sequence (including the starting launch) - t0: list of two epochs defining the launch window - tof: list of two floats defining the minimum and maximum allowed mission lenght (days) - vinf: list of two floats defining the minimum and maximum allowed initial hyperbolic velocity (at launch), in km/sec - multi_objective: when True constructs a multiobjective problem (dv, T) - add_vinf_dep: when True the computed Dv includes the initial hyperbolic velocity (at launch) - add_vinf_arr: when True the computed Dv includes the final hyperbolic velocity (at the last planet) """ # Sanity checks ...... 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') self.__add_vinf_dep = add_vinf_dep self.__add_vinf_arr = add_vinf_arr self.__n_legs = len(seq) - 1 self._t0 = t0 self._tof = tof self._vinf = vinf self._obj_dim = multi_objective + 1 # We then define all planets in the sequence and the common central # body gravity as data members self.seq = seq self.common_mu = seq[0].mu_central_body
from pykep.trajopt import mga from pykep.planet import jpl_lp from pykep import AU, DEG2RAD, MU_SUN, epoch # CASSINI1 _seq_cassini1 = [ jpl_lp('earth'), jpl_lp('venus'), jpl_lp('venus'), jpl_lp('earth'), jpl_lp('jupiter'), jpl_lp('saturn') ] class _cassini1_udp(mga): """ Write Me """ def __init__(self): """ Write Me """ super().__init__(seq=_seq_cassini1, t0=[-1000., 0.], tof=[[30, 400], [100, 470], [30, 400], [400, 2000], [1000, 6000]], vinf=3., tof_encoding='direct', orbit_insertion=True, e_target=0.98,
from pykep.trajopt import mga_1dsm from pykep.planet import jpl_lp, keplerian from pykep import AU, DEG2RAD, MU_SUN, epoch # MESSENGER (FULL) (we need to modify the safe radius of the planets to match the wanted problem) _earth = jpl_lp('earth') _venus = jpl_lp('venus') _venus.safe_radius = 1.1 _mercury = jpl_lp('mercury') _mercury.safe_radius = 1.05 _seq_messenger = [ _earth, _venus, _venus, _mercury, _mercury, _mercury, _mercury ] class _messenger_udp(mga_1dsm): """ This class represents a rendezvous mission to Mercury modelled as an MGA-1DSM transfer. The selected fly-by sequence, E-VVMeMeMe-Me, and other parameters are inspired to the Messenger mission. We have only omitted the first Earth fly-by that was used to correct for launcher performances, since we here do not make use of a luncher model. As far as chemical propelled interplanetary trajectories go, this particular one is particularly complex and difficult to design. The time of flights among successive Mercury fly-bys allow for multiple rvolutions and resonances, making optimization techniques struggle to find the correct combination. The amount of specialistic knowledge that needs to be used to obtain a successfull design is significant. Finding a global optimization approach able to find a good trajectory in complete autonomy without making use of additional problem knowledge is possible, but limiting the number of fitness call is difficult. .. 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
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 rendezvous with the comet is included in the delta V computations. .. note::
from pykep.trajopt import mga_1dsm from pykep.planet import jpl_lp, keplerian from pykep import AU, DEG2RAD, MU_SUN, epoch # CASSINI2 (we need to modify the safe radius of the planets to match the wanted problem) _earth_cassini2 = jpl_lp('earth') _earth_cassini2.safe_radius = 1.15 _venus_cassini2 = jpl_lp('venus') _venus_cassini2.safe_radius = 1.05 _jupiter_cassini2 = jpl_lp('jupiter') _jupiter_cassini2.safe_radius = 1.7 _seq_cassini2 = [ _earth_cassini2, _venus_cassini2, _venus_cassini2, _earth_cassini2, _jupiter_cassini2, jpl_lp('saturn') ] class _cassini2_udp(mga_1dsm): """ Write Me """ def __init__(self): """ Write Me """ super().__init__(seq=_seq_cassini2, t0=[-1000, 0], tof=[[100, 400], [100, 500], [30, 300], [400, 1600], [800, 2200]], vinf=[3., 5.],
def __init__(self, seq=[jpl_lp('earth'), jpl_lp('venus'), jpl_lp('earth')], t0=[epoch(0), epoch(1000)], tof=[[10, 300], [10, 300]], vinf=[0.5, 2.5], add_vinf_dep=False, add_vinf_arr=True, tof_encoding='direct', multi_objective=False, orbit_insertion=False, e_target=None, rp_target=None, eta_lb=0.1, eta_ub=0.9, rp_ub=30): """ pykep.trajopt.mga_1dsm(seq = [jpl_lp('earth'), jpl_lp('venus'), jpl_lp('earth')], t0 = [epoch(0),epoch(1000)], tof = [1.0,5.0], vinf = [0.5, 2.5], multi_objective = False, add_vinf_dep = False, add_vinf_arr=True) - seq (``list`` of ``pykep.planet``): the encounter sequence (including the starting launch) - t0 (``list`` of ``pykep.epoch`` or ``floats``): the launch window (in mjd2000 if floats) - tof (``list`` or ``float``): bounds on the time of flight (days). 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 list of two floats containing 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 (``list``): the minimum and maximum allowed initial hyperbolic velocity (at launch), in km/sec - add_vinf_dep (``bool``): when True the computed Dv includes the initial hyperbolic velocity (at launch) - add_vinf_arr (``bool``): when True the computed Dv includes the final hyperbolic velocity (at the last planet) - tof_encoding (``str``): one of 'direct', 'alpha' or 'eta'. Selects the encoding for the time of flights - multi_objective (``bool``): when True constructs a multiobjective problem (dv, T) - 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 (in m) """ # Sanity checks # 1 - 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 identical mu_central_body' ) # 2 - tof encoding needs to be one of 'alpha', 'eta', 'direct' if tof_encoding not in ['alpha', 'eta', 'direct']: raise TypeError( 'tof encoding must be one of \'alpha\', \'eta\', \'direct\'') # 3 - tof is expected to have different content depending on the tof_encoding if tof_encoding == 'direct': if np.shape(np.array(tof)) != (len(seq) - 1, 2): raise TypeError( 'tof_encoding is ' + tof_encoding + ' and tof must be a list of two dimensional lists and with length equal to the number of legs' ) if tof_encoding == 'alpha': if np.shape(np.array(tof)) != (2, ): raise TypeError('tof_encoding is ' + tof_encoding + ' and tof must be a list of two floats') if tof_encoding == 'eta': if np.shape(np.array(tof)) != (): raise TypeError('tof_encoding is ' + tof_encoding + ' and tof must be a float') # 4 - Check launch window t0. If defined in terms of floats transform into epochs if len(t0) != 2: raise TypeError('t0 is ' + t0 + ' while should be a list of two floats or epochs') if type(t0[0]) is not epoch: t0[0] = epoch(t0[0]) if type(t0[1]) is not epoch: t0[1] = epoch(t0[1]) # 5 - 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' ) if add_vinf_arr is False: raise ValueError( 'When orbit insertion is selected, the add_vinf_arr must be True' ) self._seq = seq self._t0 = t0 self._tof = tof self._vinf = vinf self._add_vinf_dep = add_vinf_dep self._add_vinf_arr = add_vinf_arr self._tof_encoding = tof_encoding self._multi_objective = multi_objective self._orbit_insertion = orbit_insertion self._e_target = e_target self._rp_target = rp_target self._eta_lb = eta_lb self._eta_ub = eta_ub self._rp_ub = rp_ub self.n_legs = len(seq) - 1 self.common_mu = seq[0].mu_central_body
def __init__(self, start=jpl_lp('earth'), target=jpl_lp('venus'), N_max=3, tof=[20., 400.], vinf=[0., 4.], phase_free=True, multi_objective=False, t0=None ): """ prob = pykep.trajopt.pl2pl_N_impulses(start=jpl_lp('earth'), target=jpl_lp('venus'), N_max=3, tof=[20., 400.], vinf=[0., 4.], phase_free=True, multi_objective=False, t0=None) Args: - start (``pykep.planet``): the starting planet - target (``pykep.planet``): the target planet - N_max (``int``): maximum number of impulses - tof (``list``): the box bounds [lower,upper] for the time of flight (days) - vinf (``list``): the box bounds [lower,upper] for each DV magnitude (km/sec) - phase_free (``bool``): when True, no randezvous condition are enforced and start and arrival anomalies will be free - multi_objective (``bool``): when True, a multi-objective problem is constructed with DV and time of flight as objectives - t0 (``list``): the box bounds on the launch window containing two pykep.epoch. This is not needed if phase_free is True. """ # Sanity checks # 1) all planets need to have the same mu_central_body if (start.mu_central_body != target.mu_central_body): raise ValueError( 'Starting and ending pykep.planet must have the same mu_central_body') # 2) Number of impulses must be at least 2 if N_max < 2: raise ValueError('Number of impulses N is less than 2') # 3) If phase_free is True, t0 does not make sense if (t0 is None and not phase_free): t0 = [epoch(0), epoch(1000)] if (t0 is not None and phase_free): raise ValueError('When phase_free is True no t0 can be specified') if (type(t0[0]) != type(epoch(0))): t0[0] = epoch(t0[0]) if (type(t0[1]) != type(epoch(0))): t0[1] = epoch(t0[1]) self.obj_dim = multi_objective + 1 # We then define all class data members self.start = start self.target = target self.N_max = N_max self.phase_free = phase_free self.multi_objective = multi_objective self.vinf = [s * 1000 for s in vinf] self.__common_mu = start.mu_central_body # And we compute the bounds if phase_free: self._lb = [0, tof[0]] + [1e-3, 0.0, 0.0, vinf[0] * 1000] * (N_max - 2) + [1e-3] + [0] self._ub = [2 * start.compute_period(epoch(0)) * SEC2DAY, tof[1]] + [1.0-1e-3, 1.0, 1.0, vinf[ 1] * 1000] * (N_max - 2) + [1.0-1e-3] + [2 * target.compute_period(epoch(0)) * SEC2DAY] else: self._lb = [t0[0].mjd2000, tof[0]] + \ [1e-3, 0.0, 0.0, vinf[0] * 1000] * (N_max - 2) + [1e-3] self._ub = [t0[1].mjd2000, tof[1]] + \ [1.0-1e-3, 1.0, 1.0, vinf[1] * 1000] * (N_max - 2) + [1.0-1e-3]
def main(): print('\nInteplanetary porkchop plot using PyKEP\n') #Pykep makes use of lambert transfers to study interplanetary trajectories by producing Pork-Chop plots # Define the start and end planets of the inteplanetary trajectory while True: start_planet_input = input('Enter initial planet: ').lower() end_planet_input = input('Enter destination planet: ').lower() if (start_planet_input == end_planet_input): print( 'Incorrect input. Initial and destination planets cannot be the same.\n' ) elif (start_planet_input or end_planet_input) not in ('mercury', 'venus', 'earth', 'mars', 'jupiter', 'saturn', 'uranus', 'neptune', 'pluto'): print('Unknown planet name.\n') else: break start_planet = jpl_lp(start_planet_input) end_planet = jpl_lp(end_planet_input) # Set departure epochs and transfer time while True: try: input_eph1 = float( input('\nEnter first departure epoch in MJD2000: ')) input_eph2 = float( input('Enter latest departure epoch in MJD2000: ')) except ValueError: print('Invalid input.\n') continue else: print( f'\nDepature window is from {input_eph1} to {input_eph2} (MJD2000)\n' ) break while True: try: input_flt1 = float(input('Enter minimum flight time in days: ')) input_flt2 = float(input('Enter maximum flight time in days: ')) except ValueError: print('Invalid input.\n') continue else: print( f'\nTotal mission duration is from {input_flt1} to {input_flt2} (days)' ) break # Sample departure epochs and transfer times every 15 days and solve the lambert problem in a large defined grid plotContours(start_planet, end_planet, input_eph1, input_eph2, input_flt1, input_flt2, 15.0) while True: zoom = input( '\nWould you like to sample with a finer resolution? (Y/N)\n') if zoom[0].upper() == 'Y': pass while True: try: input_new_eph1 = float( input( '\nEnter the updated first departure epoch in MJD2000: ' )) input_new_eph2 = float( input( 'Enter the updated latest departure epoch in MJD2000: ' )) except ValueError: print('Invalid input.\n') continue else: print( f'\nDepature window is from {input_new_eph1} to {input_new_eph2} (MJD2000)\n' ) break while True: try: input_new_flt1 = float( input( 'Enter the updated minimum flight time in days: ')) input_new_flt2 = float( input('Enter updated maximum flight time in days: ')) except ValueError: print('Invalid input.\n') continue else: print( f'\nTotal mission duration is from {input_new_flt1} to {input_new_flt2} (days)' ) break plotContours(start_planet, end_planet, input_new_eph1, input_new_eph2, input_new_flt1, input_new_flt2, 1.0) else: print('Program ended.\n') break
mpl.rcParams['legend.fontsize'] = 10 # asteroid @ Epoch 2014-Dec-09 (JD 2,457,000.5) ast_time = epoch_from_string('2014-12-09 00:00:00.000') #epoch(6800,"mjd2000") ast_orbel = (2.77 * AU, 0.075, 9.65 * DEG2RAD, 80.33 * DEG2RAD, 72.52 * DEG2RAD, 95.99 * DEG2RAD) # a,e,i,W,w,M (SI and RAD) ast_mu = 6e10 ast_radius = 1e5 ast_name = 'asteroid' asteroid = keplerian(ast_time, ast_orbel, MU_SUN, ast_mu, ast_radius, ast_radius * 1.1, ast_name) rA, vA = asteroid.eph(ast_time) #earth pl = jpl_lp('earth') rE, vE = pl.eph(ast_time) # plot fig = plt.figure() axis = fig.gca(projection='3d') axis.scatter([0], [0], [0], color='y') #sun plot_planet(asteroid, t0=ast_time, color=(1, 0.4, 0), legend=True, units=AU, ax=axis) #asteroid plot_planet(pl, t0=ast_time, color=(0.8, 0.8, 1),
def __init__(self, seq=[jpl_lp('earth'), jpl_lp('venus'), jpl_lp('earth')], n_seg=[10] * 2, t0=[epoch(0), epoch(1000)], tof=[[200, 500], [200, 500]], vinf_dep=2.5, vinf_arr=2.0, mass=4000.0, Tmax=1.0, Isp=2000.0, fb_rel_vel=6, multi_objective=False, high_fidelity=False): """ prob = mga_lt_nep(seq = [jpl_lp('earth'),jpl_lp('venus'),jpl_lp('earth')], n_seg = [10]*2, t0 = [epoch(0),epoch(1000)], tof = [[200,500],[200,500]], vinf_dep=2.5, vinf_arr=2.0, mass=4000.0, Tmax=1.0, Isp=2000.0, multi_objective = False, fb_rel_vel = 6, high_fidelity=False) - seq: list of pykep.planet defining the encounter sequence for the trajectoty (including the initial planet) - n_seg: list of integers containing the number of segments to be used for each leg (len(n_seg) = len(seq)-1) - t0: list of pykep epochs defining the launch window - tof: minimum and maximum time of each leg (days) - vinf_dep: maximum launch hyperbolic velocity allowed (in km/sec) - vinf_arr: maximum arrival hyperbolic velocity allowed (in km/sec) - mass: spacecraft starting mass - Tmax: maximum thrust - Isp: engine specific impulse - fb_rel_vel = determines the bounds on the maximum allowed relative velocity at all fly-bys (in km/sec) - multi-objective: when True defines the problem as a multi-objective problem, returning total DV and time of flight - high_fidelity = makes the trajectory computations slower, but actually dynamically feasible. """ # 1) We compute the problem dimensions .... and call the base problem # constructor self.__n_legs = len(seq) - 1 n_fb = self.__n_legs - 1 # 1a) The decision vector length dim = 1 + self.__n_legs * 8 + sum(n_seg) * 3 # 1b) The total number of constraints (mismatch + fly-by + boundary + # throttles c_dim = self.__n_legs * 7 + n_fb * 2 + 2 + sum(n_seg) # 1c) The number of inequality constraints (boundary + fly-by angle + # throttles) c_ineq_dim = 2 + n_fb + sum(n_seg) # 1d) the number of objectives f_dim = multi_objective + 1 # First we call the constructor for the base pygmo problem # As our problem is n dimensional, box-bounded (may be multi-objective), we write # (dim, integer dim, number of obj, number of con, number of inequality con, tolerance on con violation) super(mga_lt_nep, self).__init__( dim, 0, f_dim, c_dim, c_ineq_dim, 1e-4) # 2) We then define some class data members # public: self.seq = seq # private: self.__n_seg = n_seg self.__vinf_dep = vinf_dep * 1000 self.__vinf_arr = vinf_arr * 1000 self.__sc = spacecraft(mass, Tmax, Isp) self.__leg = leg() self.__leg.set_mu(MU_SUN) self.__leg.set_spacecraft(self.__sc) self.__leg.high_fidelity = high_fidelity fb_rel_vel *= 1000 # 3) We compute the bounds lb = [t0[0].mjd2000] + [0, mass / 2, -fb_rel_vel, -fb_rel_vel, -fb_rel_vel, - fb_rel_vel, -fb_rel_vel, -fb_rel_vel] * self.__n_legs + [-1, -1, -1] * sum(self.__n_seg) ub = [t0[1].mjd2000] + [1, mass, fb_rel_vel, fb_rel_vel, fb_rel_vel, fb_rel_vel, fb_rel_vel, fb_rel_vel] * self.__n_legs + [1, 1, 1] * sum(self.__n_seg) # 3a ... and account for the bounds on the vinfs...... lb[3:6] = [-self.__vinf_dep] * 3 ub[3:6] = [self.__vinf_dep] * 3 lb[-sum(self.__n_seg) * 3 - 3:-sum(self.__n_seg) * 3] = [-self.__vinf_arr] * 3 ub[-sum(self.__n_seg) * 3 - 3:-sum(self.__n_seg) * 3] = [self.__vinf_arr] * 3 # 3b... and for the time of flight lb[1:1 + 8 * self.__n_legs:8] = [el[0] for el in tof] ub[1:1 + 8 * self.__n_legs:8] = [el[1] for el in tof] # 4) And we set the bounds self.set_bounds(lb, ub)
from pykep.trajopt import mga, pl2pl_N_impulses from pykep import planet # Some hidden variables _seq_cassini = [planet.jpl_lp('earth'), planet.jpl_lp('venus'), planet.jpl_lp( 'venus'), planet.jpl_lp('earth'), planet.jpl_lp('jupiter'), planet.jpl_lp('saturn')] class _cassini1_udp(mga): def __init__(self): super(_cassini1_udp, self).__init__( seq=_seq_cassini, t0=[-1000., 0.], tof=[[30,400], [100,470], [30, 400], [400, 2000], [1000, 6000]], vinf=3., tof_encoding='direct', orbit_insertion=True, e_target = 0.98, rp_target = 108950000) def get_name(self): return "Cassini MGA direct tof encoding (Trajectory Optimisation Gym P1)" def get_extra_info(self): retval = "\tTrajectory Optimisation Gym problem (P1): Cassini MGA, single objective, direct encoding\n" retval+= "\tPlanetary sequence" + str([pl.name for pl in _seq_cassini]) return retval def __repr__(self): return self.get_name() class _cassini1a_udp(mga): def __init__(self): super(_cassini1a_udp, self).__init__( seq=_seq_cassini, t0=[-1000., 0.],
from pykep.trajopt import mga, pl2pl_N_impulses from pykep import planet # Some hidden variables _seq_cassini = [ planet.jpl_lp('earth'), planet.jpl_lp('venus'), planet.jpl_lp('venus'), planet.jpl_lp('earth'), planet.jpl_lp('jupiter'), planet.jpl_lp('saturn') ] class _cassini1_udp(mga): def __init__(self): super(_cassini1_udp, self).__init__(seq=_seq_cassini, t0=[-1000., 0.], tof=[[30, 400], [100, 470], [30, 400], [400, 2000], [1000, 6000]], vinf=3., tof_encoding='direct', orbit_insertion=True, e_target=0.98, rp_target=108950000) def get_name(self): return "Cassini MGA direct tof encoding (Trajectory Optimisation Gym P1)" def get_extra_info(self):
def __init__(self, start=jpl_lp('earth'), target=jpl_lp('venus'), N_max=3, tof=[20., 400.], vinf=[0., 4.], phase_free=True, multi_objective=False, t0=None): """ prob = pykep.trajopt.pl2pl_N_impulses(start=jpl_lp('earth'), target=jpl_lp('venus'), N_max=3, tof=[20., 400.], vinf=[0., 4.], phase_free=True, multi_objective=False, t0=None) Args: - start (``pykep.planet``): the starting planet - target (``pykep.planet``): the target planet - N_max (``int``): maximum number of impulses - tof (``list``): the box bounds [lower,upper] for the time of flight (days) - vinf (``list``): the box bounds [lower,upper] for each DV magnitude (km/sec) - phase_free (``bool``): when True, no randezvous condition are enforced and start and arrival anomalies will be free - multi_objective (``bool``): when True, a multi-objective problem is constructed with DV and time of flight as objectives - t0 (``list``): the box bounds on the launch window containing two pykep.epoch. This is not needed if phase_free is True. """ # Sanity checks # 1) all planets need to have the same mu_central_body if (start.mu_central_body != target.mu_central_body): raise ValueError( 'Starting and ending pykep.planet must have the same mu_central_body' ) # 2) Number of impulses must be at least 2 if N_max < 2: raise ValueError('Number of impulses N is less than 2') # 3) If phase_free is True, t0 does not make sense if (t0 is None and not phase_free): t0 = [epoch(0), epoch(1000)] if (t0 is not None and phase_free): raise ValueError('When phase_free is True no t0 can be specified') if (type(t0[0]) != type(epoch(0))): t0[0] = epoch(t0[0]) if (type(t0[1]) != type(epoch(0))): t0[1] = epoch(t0[1]) self.obj_dim = multi_objective + 1 # We then define all class data members self.start = start self.target = target self.N_max = N_max self.phase_free = phase_free self.multi_objective = multi_objective self.vinf = [s * 1000 for s in vinf] self.__common_mu = start.mu_central_body # And we compute the bounds if phase_free: self._lb = [ 0, tof[0] ] + [1e-3, 0.0, 0.0, vinf[0] * 1000] * (N_max - 2) + [1e-3] + [0] self._ub = [ 2 * start.compute_period(epoch(0)) * SEC2DAY, tof[1] ] + [1.0 - 1e-3, 1.0, 1.0, vinf[1] * 1000] * (N_max - 2) + [ 1.0 - 1e-3 ] + [2 * target.compute_period(epoch(0)) * SEC2DAY] else: self._lb = [t0[0].mjd2000, tof[0]] + \ [1e-3, 0.0, 0.0, vinf[0] * 1000] * (N_max - 2) + [1e-3] self._ub = [t0[1].mjd2000, tof[1]] + \ [1.0-1e-3, 1.0, 1.0, vinf[1] * 1000] * (N_max - 2) + [1.0-1e-3]
def __init__(self, seq=[jpl_lp('earth'), jpl_lp('venus'), jpl_lp('earth')], t0=[0, 1000], tof=[[30, 200], [200, 300]], vinf=2.5, multi_objective=False, tof_encoding='direct', orbit_insertion=False, e_target=None, rp_target=None, max_revs=0): """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 recommended - 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 (in m) - max_revs (``int``): maximal number of revolutions for lambert transfer 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 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(epoch(0))): t0[i] = epoch(t0[i]) # 3 - Check the tof bounds if tof_encoding == 'alpha': if len(tof) != 2: raise ValueError( r'When the tof_encoding is \'alpha\', tof is expected to be something like [lb, ub]' ) elif tof_encoding == '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 == 'eta': try: float(tof) except TypeError: 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 self.max_revs = max_revs
def __init__(self, prob_id=1, constrained=True): """ The TandEM problem of the trajectory gym consists in 48 different instances varying in fly-by sequence and the presence of a time constraint. Args: - prob_id (``int``): The problem id defines the fly-by sequence. - constrained (``bool``): Activates the constraint on the time of flight (fitness will thus return two numbers, the objectove function and the inequality constraint violation) """ # Redefining the planets as to change their safe radius earth = jpl_lp('earth') earth.safe_radius = 1.05 # We need the Earth eph in the fitnes venus = jpl_lp('venus') venus.safe_radius = 1.05 mars = jpl_lp('mars') mars.safe_radius = 1.05 jupiter = jpl_lp('jupiter') jupiter.safe_radius = 1.7 saturn = jpl_lp('saturn') # Defining the different sequences seq_tandem = [] seq_tandem.append([earth, venus, venus, venus, saturn]) seq_tandem.append([earth, venus, venus, earth, saturn]) seq_tandem.append([earth, venus, venus, mars, saturn]) seq_tandem.append([earth, venus, venus, jupiter, saturn]) seq_tandem.append([earth, venus, earth, venus, saturn]) seq_tandem.append([earth, venus, earth, earth, saturn]) seq_tandem.append([earth, venus, earth, mars, saturn]) seq_tandem.append([earth, venus, earth, jupiter, saturn]) seq_tandem.append([earth, venus, mars, venus, saturn]) seq_tandem.append([earth, venus, mars, earth, saturn]) seq_tandem.append([earth, venus, mars, mars, saturn]) seq_tandem.append([earth, venus, mars, jupiter, saturn]) seq_tandem.append([earth, earth, venus, venus, saturn]) seq_tandem.append([earth, earth, venus, earth, saturn]) seq_tandem.append([earth, earth, venus, mars, saturn]) seq_tandem.append([earth, earth, venus, jupiter, saturn]) seq_tandem.append([earth, earth, earth, venus, saturn]) seq_tandem.append([earth, earth, earth, earth, saturn]) seq_tandem.append([earth, earth, earth, mars, saturn]) seq_tandem.append([earth, earth, earth, jupiter, saturn]) seq_tandem.append([earth, earth, mars, venus, saturn]) seq_tandem.append([earth, earth, mars, earth, saturn]) seq_tandem.append([earth, earth, mars, mars, saturn]) seq_tandem.append([earth, earth, mars, jupiter, saturn]) if prob_id > 24 or type(prob_id) != int or prob_id < 1: raise ValueError("TandEM problem id must be an integer in [1, 24]") super().__init__(seq=seq_tandem[prob_id - 1], t0=[5475, 9132], tof=[[20, 2500], [20, 2500], [20, 2500], [20, 2500]], vinf=[2.5, 4.9], add_vinf_dep=False, add_vinf_arr=True, tof_encoding='direct', multi_objective=False, orbit_insertion=True, e_target=0.98531407996358, rp_target=80330000, eta_lb=0.01, eta_ub=0.99, rp_ub=10) self.prob_id = prob_id self.constrained = constrained
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 __init__(self, seq=[jpl_lp('earth'), jpl_lp('venus'), jpl_lp('earth')], n_seg=[10] * 2, t0=[epoch(0), epoch(1000)], tof=[[200, 500], [200, 500]], vinf_dep=2.5, vinf_arr=2.0, mass=4000.0, Tmax=1.0, Isp=2000.0, fb_rel_vel=6, multi_objective=False, high_fidelity=False): """ prob = mga_lt_nep(seq = [jpl_lp('earth'),jpl_lp('venus'),jpl_lp('earth')], n_seg = [10]*2, t0 = [epoch(0),epoch(1000)], tof = [[200,500],[200,500]], vinf_dep=2.5, vinf_arr=2.0, mass=4000.0, Tmax=1.0, Isp=2000.0, multi_objective = False, fb_rel_vel = 6, high_fidelity=False) - seq: list of pykep.planet defining the encounter sequence for the trajectoty (including the initial planet) - n_seg: list of integers containing the number of segments to be used for each leg (len(n_seg) = len(seq)-1) - t0: list of pykep epochs defining the launch window - tof: minimum and maximum time of each leg (days) - vinf_dep: maximum launch hyperbolic velocity allowed (in km/sec) - vinf_arr: maximum arrival hyperbolic velocity allowed (in km/sec) - mass: spacecraft starting mass - Tmax: maximum thrust - Isp: engine specific impulse - fb_rel_vel = determines the bounds on the maximum allowed relative velocity at all fly-bys (in km/sec) - multi-objective: when True defines the problem as a multi-objective problem, returning total DV and time of flight - high_fidelity = makes the trajectory computations slower, but actually dynamically feasible. """ # 1) We compute the problem dimensions .... and call the base problem # constructor self.__n_legs = len(seq) - 1 n_fb = self.__n_legs - 1 # 1a) The decision vector length dim = 1 + self.__n_legs * 8 + sum(n_seg) * 3 # 1b) The total number of constraints (mismatch + fly-by + boundary + # throttles c_dim = self.__n_legs * 7 + n_fb * 2 + 2 + sum(n_seg) # 1c) The number of inequality constraints (boundary + fly-by angle + # throttles) c_ineq_dim = 2 + n_fb + sum(n_seg) # 1d) the number of objectives f_dim = multi_objective + 1 # First we call the constructor for the base pygmo problem # As our problem is n dimensional, box-bounded (may be multi-objective), we write # (dim, integer dim, number of obj, number of con, number of inequality con, tolerance on con violation) super(mga_lt_nep, self).__init__(dim, 0, f_dim, c_dim, c_ineq_dim, 1e-4) # 2) We then define some class data members # public: self.seq = seq # private: self.__n_seg = n_seg self.__vinf_dep = vinf_dep * 1000 self.__vinf_arr = vinf_arr * 1000 self.__sc = spacecraft(mass, Tmax, Isp) self.__leg = leg() self.__leg.set_mu(MU_SUN) self.__leg.set_spacecraft(self.__sc) self.__leg.high_fidelity = high_fidelity fb_rel_vel *= 1000 # 3) We compute the bounds lb = [t0[0].mjd2000] + [ 0, mass / 2, -fb_rel_vel, -fb_rel_vel, -fb_rel_vel, -fb_rel_vel, -fb_rel_vel, -fb_rel_vel ] * self.__n_legs + [-1, -1, -1] * sum(self.__n_seg) ub = [t0[1].mjd2000] + [ 1, mass, fb_rel_vel, fb_rel_vel, fb_rel_vel, fb_rel_vel, fb_rel_vel, fb_rel_vel ] * self.__n_legs + [1, 1, 1] * sum(self.__n_seg) # 3a ... and account for the bounds on the vinfs...... lb[3:6] = [-self.__vinf_dep] * 3 ub[3:6] = [self.__vinf_dep] * 3 lb[-sum(self.__n_seg) * 3 - 3:-sum(self.__n_seg) * 3] = [-self.__vinf_arr] * 3 ub[-sum(self.__n_seg) * 3 - 3:-sum(self.__n_seg) * 3] = [self.__vinf_arr] * 3 # 3b... and for the time of flight lb[1:1 + 8 * self.__n_legs:8] = [el[0] for el in tof] ub[1:1 + 8 * self.__n_legs:8] = [el[1] for el in tof] # 4) And we set the bounds self.set_bounds(lb, ub)