예제 #1
0
    def pretty(self, x):
        """
        prob.pretty(x)

        - x: encoded trajectory

        Prints human readable information on the trajectory represented by 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 * G0 * np.log(m_i / m_f)

        dt = np.append(self.__fwd_dt, self.__bwd_dt) * T / DAY2SEC
        time_thrusts_on = sum(dt[i] for i in range(len(thrusts)) if thrusts[i] > 0.1)

        print("Departure:", epoch(t0), "(", t0, "mjd2000 )")
        print("Time of flight:", T, "days")
        print("Arrival:", epoch(tf), "(", tf, "mjd2000 )")
        print("Delta-v:", deltaV, "m/s")
        print("Propellant consumption:", mP, "kg")
        print("Thrust-on time:", time_thrusts_on, "days")
예제 #2
0
    def double_segments(self,x):
        """
        new_prob, new_x = prob.double_segments(self,x)

        - x: encoded trajectory

        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 "almost"
        feasible, due to the new refined Earth gravity that is now different in the 2 halves of each segment).
        """
        new_x = list(x[:3])
        for i in range(self.__n_seg):
            new_x.extend(x[3 + 3 * i : 6 + 3 * i] * 2)

        new_prob = earth_gravity(
             target = self.target,
             n_seg = 2 * self.__n_seg,
             grid_type = self.__grid_type,
             t0 = [epoch(self.lb[0]), 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,
             start = self.__start
        )

        return new_prob, new_x
예제 #3
0
    def plot_orbits(self, pop, ax=None):
        import matplotlib.pylab as plt
        from mpl_toolkits.mplot3d import Axes3D

        A1, A2 = self._ast1, self._ast2

        if ax is None:
            fig = plt.figure()
            axis = fig.add_subplot(111, projection='3d')
        else:
            axis = ax

        plot_planet(A1, ax=axis, s=10, t0=epoch(self.lb[0]))
        plot_planet(A2, ax=axis, s=10, t0=epoch(self.ub[0]))
        for ind in pop:
            if ind.cur_f[0] == self._UNFEASIBLE:
                continue
            dep, arr = ind.cur_x
            rdep, vdep = A1.eph(epoch(dep))
            rarr, varr = A2.eph(epoch(arr))
            l = lambert_problem(rdep, rarr, (arr - dep) * DAY2SEC,
                                A1.mu_central_body, False, 1)
            axis = plot_lambert(l, ax=axis, alpha=0.8, color='k')

        if ax is None:
            plt.show()

        return axis
예제 #4
0
    def plot_orbits(self, pop, ax=None):
        import matplotlib.pylab as plt
        from mpl_toolkits.mplot3d import Axes3D

        A1, A2 = self._ast1, self._ast2

        if ax is None:
            fig = plt.figure()
            axis = fig.add_subplot(111, projection='3d')
        else:
            axis = ax

        plot_planet(A1, ax=axis, s=10, t0=epoch(self.lb[0]))
        plot_planet(A2, ax=axis, s=10, t0=epoch(self.ub[0]))
        for ind in pop:
            if ind.cur_f[0] == self._UNFEASIBLE:
                continue
            dep, arr = ind.cur_x
            rdep, vdep = A1.eph(epoch(dep))
            rarr, varr = A2.eph(epoch(arr))
            l = lambert_problem(rdep, rarr, (arr - dep) * DAY2SEC, A1.mu_central_body, False, 1)
            axis = plot_lambert(l, ax=axis, alpha=0.8, color='k')

        if ax is None:
            plt.show()

        return axis
예제 #5
0
    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 (years)
        - 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
        dim = 7 + (self.__n_legs - 1) * 4
        obj_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_1dsm, self).__init__(dim, 0, obj_dim, 0, 0, 0)

        # 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

        # And we compute the bounds
        lb = [t0[0].mjd2000, tof[0] * 365.25] + [
            0.0, 0.0, vinf[0] * 1000, 1e-5, 1e-5
        ] + [-2 * pi, 1.1, 1e-5, 1e-5] * (self.__n_legs - 1)
        ub = [t0[1].mjd2000, tof[1] * 365.25] + [
            1.0, 1.0, vinf[1] * 1000, 1.0 - 1e-5, 1.0 - 1e-5
        ] + [2 * pi, 30.0, 1.0 - 1e-5, 1.0 - 1e-5] * (self.__n_legs - 1)

        # Accounting that each planet has a different safe radius......
        for i, pl in enumerate(seq[1:-1]):
            lb[8 + 4 * i] = pl.safe_radius / pl.radius

        # And we set them
        self.set_bounds(lb, ub)
예제 #6
0
    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],
                 mga_sol=None,
                 add_vinf_dep=False,
                 add_vinf_arr=True,
                 multi_objective=False,
                 avoid=[]):
        """
        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 (years)
        - 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)
        """

        # 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)
        dim = 7 + (len(seq) - 2) * 4
        obj_dim = multi_objective + 1
        super(mga_1dsm_transx, self).__init__(seq, dim, obj_dim, avoid)

        self.__add_vinf_dep = add_vinf_dep
        self.__add_vinf_arr = add_vinf_arr

        # And we compute the bounds
        lb = [t0[0].mjd2000, tof[0] * 365.25] + [
            0.0, 0.0, vinf[0] * 1000, 1e-5, 1e-5
        ] + [-2 * pi, 1.1, 1e-5, 1e-5] * (self.n_legs - 1)
        ub = [t0[1].mjd2000, tof[1] * 365.25] + [
            1.0, 1.0, vinf[1] * 1000, 1.0 - 1e-5, 1.0 - 1e-5
        ] + [2 * pi, 30.0, 1.0 - 1e-5, 1.0 - 1e-5] * (self.n_legs - 1)

        self.__mga_sol = mga_sol

        # Accounting that each planet has a different safe radius......
        for i, pl in enumerate(seq[1:-1]):
            lb[8 + 4 * i] = pl.safe_radius / pl.radius

        # And we set them
        self.set_bounds(lb, ub)
예제 #7
0
    def _objfun_impl(self, x):
        # 1 -  we 'decode' the chromosome recording the various deep space
        # manouvres timing (days) in the list T
        T = list([0] * (self.N_max - 1))

        for i in range(len(T)):
            T[i] = log(x[2 + 4 * i])
        total = sum(T)
        T = [x[1] * time / total for time in T]

        # 2 - We compute the starting and ending position
        r_start, v_start = self.start.eph(epoch(x[0]))
        if self.phase_free:
            r_target, v_target = self.target.eph(epoch(x[-1]))
        else:
            r_target, v_target = self.target.eph(epoch(x[0] + x[1]))

        # 3 - We loop across inner impulses
        rsc = r_start
        vsc = v_start
        for i, time in enumerate(T[:-1]):
            theta = 2 * pi * x[3 + 4 * i]
            phi = acos(2 * x[4 + 4 * i] - 1) - pi / 2

            Vinfx = x[5 + 4 * i] * cos(phi) * cos(theta)
            Vinfy = x[5 + 4 * i] * cos(phi) * sin(theta)
            Vinfz = x[5 + 4 * i] * sin(phi)

            # We apply the (i+1)-th impulse
            vsc = [a + b for a, b in zip(vsc, [Vinfx, Vinfy, Vinfz])]
            rsc, vsc = propagate_lagrangian(
                rsc, vsc, T[i] * DAY2SEC, self.__common_mu)
        cw = (ic2par(rsc, vsc, self.start.mu_central_body)[2] > pi / 2)

        # We now compute the remaining two final impulses
        # Lambert arc to reach seq[1]
        dt = T[-1] * DAY2SEC
        l = lambert_problem(rsc, r_target, dt, self.__common_mu, cw, False)
        v_end_l = l.get_v2()[0]
        v_beg_l = l.get_v1()[0]

        DV1 = norm([a - b for a, b in zip(v_beg_l, vsc)])
        DV2 = norm([a - b for a, b in zip(v_end_l, v_target)])
        DV_others = sum(x[5::4])
        if self.f_dimension == 1:
            return (DV1 + DV2 + DV_others,)
        else:
            return (DV1 + DV2 + DV_others, x[1])
예제 #8
0
    def _objfun_impl(self, x):
        # 1 -  we 'decode' the chromosome recording the various deep space
        # manouvres timing (days) in the list T
        T = list([0] * (self.N_max - 1))

        for i in range(len(T)):
            T[i] = log(x[2 + 4 * i])
        total = sum(T)
        T = [x[1] * time / total for time in T]

        # 2 - We compute the starting and ending position
        r_start, v_start = self.start.eph(epoch(x[0]))
        if self.phase_free:
            r_target, v_target = self.target.eph(epoch(x[-1]))
        else:
            r_target, v_target = self.target.eph(epoch(x[0] + x[1]))

        # 3 - We loop across inner impulses
        rsc = r_start
        vsc = v_start
        for i, time in enumerate(T[:-1]):
            theta = 2 * pi * x[3 + 4 * i]
            phi = acos(2 * x[4 + 4 * i] - 1) - pi / 2

            Vinfx = x[5 + 4 * i] * cos(phi) * cos(theta)
            Vinfy = x[5 + 4 * i] * cos(phi) * sin(theta)
            Vinfz = x[5 + 4 * i] * sin(phi)

            # We apply the (i+1)-th impulse
            vsc = [a + b for a, b in zip(vsc, [Vinfx, Vinfy, Vinfz])]
            rsc, vsc = propagate_lagrangian(rsc, vsc, T[i] * DAY2SEC,
                                            self.__common_mu)
        cw = (ic2par(rsc, vsc, self.start.mu_central_body)[2] > pi / 2)

        # We now compute the remaining two final impulses
        # Lambert arc to reach seq[1]
        dt = T[-1] * DAY2SEC
        l = lambert_problem(rsc, r_target, dt, self.__common_mu, cw, False)
        v_end_l = l.get_v2()[0]
        v_beg_l = l.get_v1()[0]

        DV1 = norm([a - b for a, b in zip(v_beg_l, vsc)])
        DV2 = norm([a - b for a, b in zip(v_end_l, v_target)])
        DV_others = sum(x[5::4])
        if self.f_dimension == 1:
            return (DV1 + DV2 + DV_others, )
        else:
            return (DV1 + DV2 + DV_others, x[1])
예제 #9
0
    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], mga_sol = None,  add_vinf_dep=False, add_vinf_arr=True, multi_objective=False, avoid = []):
        """
        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 (years)
        - 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)
        """

        # 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)
        dim = 7 + (len(seq) - 2) * 4
        obj_dim = multi_objective + 1
        super(mga_1dsm_transx, self).__init__(seq, dim, obj_dim, avoid)

        self.__add_vinf_dep = add_vinf_dep
        self.__add_vinf_arr = add_vinf_arr

        # And we compute the bounds
        lb = [t0[0].mjd2000, tof[0] * 365.25] + [0.0, 0.0, vinf[0] * 1000, 1e-5, 1e-5] + [-2 * pi, 1.1, 1e-5, 1e-5] * (self.n_legs - 1)
        ub = [t0[1].mjd2000, tof[1] * 365.25] + [1.0, 1.0, vinf[1] * 1000, 1.0 - 1e-5, 1.0 - 1e-5] + [2 * pi, 30.0, 1.0 - 1e-5, 1.0 - 1e-5] * (self.n_legs - 1)

        self.__mga_sol = mga_sol

        # Accounting that each planet has a different safe radius......
        for i, pl in enumerate(seq[1:-1]):
            lb[8 + 4 * i] = pl.safe_radius / pl.radius

        # And we set them
        self.set_bounds(lb, ub)
예제 #10
0
    def _objfun_impl(self, x):
        # 1 -  we 'decode' the chromosome recording the various times of flight
        # (days) in the list T and the cartesian components of vinf
        T, Vinfx, Vinfy, Vinfz = self._decode_times_and_vinf(x)

        # 2 - We compute the epochs and ephemerides of the planetary encounters
        t_P = list([None] * (self.__n_legs + 1))
        r_P = list([None] * (self.__n_legs + 1))
        v_P = list([None] * (self.__n_legs + 1))
        DV = list([0.0] * (self.__n_legs + 1))
        for i, planet in enumerate(self.seq):
            t_P[i] = epoch(x[0] + sum(T[0:i]))
            r_P[i], v_P[i] = self.seq[i].eph(t_P[i])

        # 3 - We start with the first leg
        v0 = [a + b for a, b in zip(v_P[0], [Vinfx, Vinfy, Vinfz])]
        r, v = propagate_lagrangian(r_P[0], v0, x[5] * T[0] * DAY2SEC,
                                    self.common_mu)

        # Lambert arc to reach seq[1]
        dt = (1 - x[5]) * T[0] * DAY2SEC
        l = lambert_problem(r, r_P[1], dt, self.common_mu, False, False)
        v_end_l = l.get_v2()[0]
        v_beg_l = l.get_v1()[0]

        # First DSM occuring at time nu1*T1
        DV[0] = norm([a - b for a, b in zip(v_beg_l, v)])

        # 4 - And we proceed with each successive leg
        for i in range(1, self.__n_legs):
            # Fly-by
            v_out = fb_prop(v_end_l, v_P[i],
                            x[8 + (i - 1) * 4] * self.seq[i].radius,
                            x[7 + (i - 1) * 4], self.seq[i].mu_self)
            # s/c propagation before the DSM
            r, v = propagate_lagrangian(r_P[i], v_out,
                                        x[9 + (i - 1) * 4] * T[i] * DAY2SEC,
                                        self.common_mu)
            # Lambert arc to reach Earth during (1-nu2)*T2 (second segment)
            dt = (1 - x[9 + (i - 1) * 4]) * T[i] * DAY2SEC
            l = lambert_problem(r, r_P[i + 1], dt, self.common_mu, False,
                                False)
            v_end_l = l.get_v2()[0]
            v_beg_l = l.get_v1()[0]
            # DSM occuring at time nu2*T2
            DV[i] = norm([a - b for a, b in zip(v_beg_l, v)])

        # Last Delta-v
        if self.__add_vinf_arr:
            DV[-1] = norm([a - b for a, b in zip(v_end_l, v_P[-1])])

        if self.__add_vinf_dep:
            DV[0] += x[3]

        if self.f_dimension == 1:
            return (sum(DV), )
        else:
            return (sum(DV), sum(T))
예제 #11
0
    def _objfun_impl(self, x):
        # 1 -  we 'decode' the chromosome recording the various times of flight
        # (days) in the list T and the cartesian components of vinf
        T, Vinfx, Vinfy, Vinfz = self._decode_times_and_vinf(x)

        # 2 - We compute the epochs and ephemerides of the planetary encounters
        t_P = list([None] * (self.__n_legs + 1))
        r_P = list([None] * (self.__n_legs + 1))
        v_P = list([None] * (self.__n_legs + 1))
        DV = list([0.0] * (self.__n_legs + 1))
        for i, planet in enumerate(self.seq):
            t_P[i] = epoch(x[0] + sum(T[0:i]))
            r_P[i], v_P[i] = self.seq[i].eph(t_P[i])

        # 3 - We start with the first leg
        v0 = [a + b for a, b in zip(v_P[0], [Vinfx, Vinfy, Vinfz])]
        r, v = propagate_lagrangian(r_P[0], v0, x[5] * T[0] * DAY2SEC, self.common_mu)

        # Lambert arc to reach seq[1]
        dt = (1 - x[5]) * T[0] * DAY2SEC
        l = lambert_problem(r, r_P[1], dt, self.common_mu, False, False)
        v_end_l = l.get_v2()[0]
        v_beg_l = l.get_v1()[0]

        # First DSM occuring at time nu1*T1
        DV[0] = norm([a - b for a, b in zip(v_beg_l, v)])

        # 4 - And we proceed with each successive leg
        for i in range(1, self.__n_legs):
            # Fly-by
            v_out = fb_prop(v_end_l, v_P[i], x[8 + (i - 1) * 4] * self.seq[i].radius, x[7 + (i - 1) * 4], self.seq[i].mu_self)
            # s/c propagation before the DSM
            r, v = propagate_lagrangian(r_P[i], v_out, x[9 + (i - 1) * 4] * T[i] * DAY2SEC, self.common_mu)
            # Lambert arc to reach Earth during (1-nu2)*T2 (second segment)
            dt = (1 - x[9 + (i - 1) * 4]) * T[i] * DAY2SEC
            l = lambert_problem(r, r_P[i + 1], dt, self.common_mu, False, False)
            v_end_l = l.get_v2()[0]
            v_beg_l = l.get_v1()[0]
            # DSM occuring at time nu2*T2
            DV[i] = norm([a - b for a, b in zip(v_beg_l, v)])

        # Last Delta-v
        if self.__add_vinf_arr:
            DV[-1] = norm([a - b for a, b in zip(v_end_l, v_P[-1])])

        if self.__add_vinf_dep:
            DV[0] += x[3]

        if self.f_dimension == 1:
            return (sum(DV),)
        else:
            return (sum(DV), sum(T))
예제 #12
0
    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 (years)
        - 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
        dim = 7 + (self.__n_legs - 1) * 4
        obj_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_1dsm, self).__init__(dim, 0, obj_dim, 0, 0, 0)

        # 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

        # And we compute the bounds
        lb = [t0[0].mjd2000, tof[0] * 365.25] + [0.0, 0.0, vinf[0] * 1000, 1e-5, 1e-5] + [-2 * pi, 1.1, 1e-5, 1e-5] * (self.__n_legs - 1)
        ub = [t0[1].mjd2000, tof[1] * 365.25] + [1.0, 1.0, vinf[1] * 1000, 1.0 - 1e-5, 1.0 - 1e-5] + [2 * pi, 30.0, 1.0 - 1e-5, 1.0 - 1e-5] * (self.__n_legs - 1)

        # Accounting that each planet has a different safe radius......
        for i, pl in enumerate(seq[1:-1]):
            lb[8 + 4 * i] = pl.safe_radius / pl.radius

        # And we set them
        self.set_bounds(lb, ub)
예제 #13
0
    def pretty(self, x):
        """
        prob.plot(x)

        - x: encoded trajectory

        Prints human readable information on the trajectory represented by the decision vector x

        Example::

          print(prob.pretty(x))
        """
        # 1 -  we 'decode' the chromosome recording the various times of flight
        # (days) in the list T and the cartesian components of vinf
        T, Vinfx, Vinfy, Vinfz = self._decode_times_and_vinf(x)

        # 2 - We compute the epochs and ephemerides of the planetary encounters
        t_P = list([None] * (self.__n_legs + 1))
        r_P = list([None] * (self.__n_legs + 1))
        v_P = list([None] * (self.__n_legs + 1))
        DV = list([None] * (self.__n_legs + 1))

        for i, planet in enumerate(self.seq):
            t_P[i] = epoch(x[0] + sum(T[0:i]))
            r_P[i], v_P[i] = self.seq[i].eph(t_P[i])

        # 3 - We start with the first leg
        print("First Leg: " + self.seq[0].name + " to " + self.seq[1].name)
        print("Departure: " + str(t_P[0]) + " (" + str(t_P[0].mjd2000) +
              " mjd2000) ")
        print("Duration: " + str(T[0]) + "days")
        print("VINF: " + str(x[4] / 1000) + " km/sec")

        v0 = [a + b for a, b in zip(v_P[0], [Vinfx, Vinfy, Vinfz])]
        r, v = propagate_lagrangian(r_P[0], v0, x[5] * T[0] * DAY2SEC,
                                    self.common_mu)

        print("DSM after " + str(x[5] * T[0]) + " days")

        # Lambert arc to reach seq[1]
        dt = (1 - x[5]) * T[0] * DAY2SEC
        l = lambert_problem(r, r_P[1], dt, self.common_mu, False, False)
        v_end_l = l.get_v2()[0]
        v_beg_l = l.get_v1()[0]

        # First DSM occuring at time nu1*T1
        DV[0] = norm([a - b for a, b in zip(v_beg_l, v)])
        print("DSM magnitude: " + str(DV[0]) + "m/s")

        # 4 - And we proceed with each successive leg
        for i in range(1, self.__n_legs):
            print("\nleg no. " + str(i + 1) + ": " + self.seq[i].name +
                  " to " + self.seq[i + 1].name)
            print("Duration: " + str(T[i]) + "days")
            # Fly-by
            v_out = fb_prop(v_end_l, v_P[i],
                            x[8 + (i - 1) * 4] * self.seq[i].radius,
                            x[7 + (i - 1) * 4], self.seq[i].mu_self)
            print("Fly-by epoch: " + str(t_P[i]) + " (" + str(t_P[i].mjd2000) +
                  " mjd2000) ")
            print("Fly-by radius: " + str(x[8 + (i - 1) * 4]) +
                  " planetary radii")
            # s/c propagation before the DSM
            r, v = propagate_lagrangian(r_P[i], v_out,
                                        x[9 + (i - 1) * 4] * T[i] * DAY2SEC,
                                        self.common_mu)
            print("DSM after " + str(x[9 + (i - 1) * 4] * T[i]) + " days")
            # Lambert arc to reach Earth during (1-nu2)*T2 (second segment)
            dt = (1 - x[9 + (i - 1) * 4]) * T[i] * DAY2SEC
            l = lambert_problem(r, r_P[i + 1], dt, self.common_mu, False,
                                False)
            v_end_l = l.get_v2()[0]
            v_beg_l = l.get_v1()[0]
            # DSM occuring at time nu2*T2
            DV[i] = norm([a - b for a, b in zip(v_beg_l, v)])
            print("DSM magnitude: " + str(DV[i]) + "m/s")

        # Last Delta-v
        print("\nArrival at " + self.seq[-1].name)
        DV[-1] = norm([a - b for a, b in zip(v_end_l, v_P[-1])])
        print("Arrival epoch: " + str(t_P[-1]) + " (" + str(t_P[-1].mjd2000) +
              " mjd2000) ")
        print("Arrival Vinf: " + str(DV[-1]) + "m/s")
        print("Total mission time: " + str(sum(T) / 365.25) + " years")
예제 #14
0
    def plot_trajectory(self, x, units=AU, plot_segments=True, ax=None):
        """
        ax = prob.plot_trajectory(self, x, units=AU, plot_segments=True, ax=None)

        - x: encoded trajectory
        - units: the length unit to be used in the plot
        - plot_segments: when true plots also the segments boundaries
        - [out] ax: matplotlib axis where to plot

        Plots the trajectory
        """
        import matplotlib as mpl
        import matplotlib.pyplot as plt
        from mpl_toolkits.mplot3d import Axes3D
        from PyKEP.orbit_plots import plot_planet, plot_taylor

        # 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

        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 * 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 = self._propagate(x)

        # Plotting the Sun, the Earth and the target
        axis.scatter([0], [0], [0], color='y')
        plot_planet(self.__earth, epoch(t0), units=units, legend=True, color=(0.7, 0.7, 1), ax=axis)
        plot_planet(self.target, epoch(t0 + T), units=units, legend=True, color=(0.7, 0.7, 1), ax=axis)

        # 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):
            plot_taylor(rfwd[i], vfwd[i], mfwd[i], ufwd[i], fwd_dt[i], MU_SUN, veff, N=10, units=units, color=(alphas[i], 0, 1-alphas[i]), ax=axis)
            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:
            axis.scatter(xfwd[:-1], yfwd[:-1], zfwd[:-1], label='nodes', marker='o', s=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] / units
        ybwd[-1] = rbwd[-1][1] / units
        zbwd[-1] = rbwd[-1][2] / units

        for i in range(bwd_seg):
            plot_taylor(rbwd[-i-1], vbwd[-i-1], mbwd[-i-1], ubwd[-i-1], -bwd_dt[-i-1], MU_SUN, veff, N=10, units=units, color=(alphas[-i-1], 0, 1-alphas[-i-1]), ax=axis)
            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:
            axis.scatter(xbwd[1:], ybwd[1:], zbwd[1:], marker='o', s=1)

        if ax is None:  # show only if axis is not set
            plt.show()

        return axis
예제 #15
0
    def calc_objective(self, x, should_print=False):
        # 1 -  we 'decode' the chromosome recording the various times of flight
        # (days) in the list T and the cartesian components of vinf
        T, Vinfx, Vinfy, Vinfz = self._decode_times_and_vinf(x)

        Vinf = [Vinfx, Vinfy, Vinfz]

        # 2 - We compute the epochs and ephemerides of the planetary encounters
        t_P = list([None] * (self.n_legs + 1))
        r_P = list([None] * (self.n_legs + 1))
        v_P = list([None] * (self.n_legs + 1))
        DV = list([0.0] * (self.n_legs + 1))
        for i, planet in enumerate(self.seq):
            t_P[i] = epoch(x[0] + sum(T[0:i]))
            r_P[i], v_P[i] = self.seq[i].eph(t_P[i])

        if should_print:
            self.print_time_info(self.seq, t_P)

        if self.__add_vinf_dep:
            DV[0] += self.burn_cost(self.seq[0], Vinf)
            if should_print:
                self.print_escape(self.seq[0], v_P[0], r_P[0], Vinf,
                                  t_P[0].mjd)

        # 3 - We start with the first leg
        v0 = [a + b for a, b in zip(v_P[0], Vinf)]
        r, v = propagate_lagrangian(r_P[0], v0, x[5] * T[0] * DAY2SEC,
                                    self.common_mu)

        # Lambert arc to reach seq[1]
        dt = (1 - x[5]) * T[0] * DAY2SEC
        l = lambert_problem(r, r_P[1], dt, self.common_mu, False, False)
        v_beg_l = l.get_v1()[0]
        v_end_l = l.get_v2()[0]

        # First DSM occuring at time nu1*T1
        deltaV = [a - b for a, b in zip(v_beg_l, v)]
        DV[0] += norm(deltaV)

        if should_print:
            self.print_dsm(v, r, deltaV, v_beg_l, t_P[0].mjd + dt / DAY2SEC)

        # 4 - And we proceed with each successive leg
        for i in range(1, self.n_legs):
            # Fly-by
            radius = x[8 + (i - 1) * 4] * self.seq[i].radius
            beta = x[7 + (i - 1) * 4]
            v_out = fb_prop(v_end_l, v_P[i], radius, beta, self.seq[i].mu_self)

            if should_print:
                v_rel_in = [a - b for a, b in zip(v_end_l, v_P[i])]
                v_rel_out = [a - b for a, b in zip(v_out, v_P[i])]
                self.print_flyby(self.seq[i], v_P[i], r_P[i], v_rel_in,
                                 v_rel_out, t_P[i].mjd)

            # s/c propagation before the DSM
            r, v = propagate_lagrangian(r_P[i], v_out,
                                        x[9 + (i - 1) * 4] * T[i] * DAY2SEC,
                                        self.common_mu)
            # Lambert arc to reach Earth during (1-nu2)*T2 (second segment)
            dt = (1 - x[9 + (i - 1) * 4]) * T[i] * DAY2SEC
            l = lambert_problem(r, r_P[i + 1], dt, self.common_mu, False,
                                False)
            v_end_l = l.get_v2()[0]
            v_beg_l = l.get_v1()[0]
            # DSM occuring at time nu2*T2
            deltaV = [a - b for a, b in zip(v_beg_l, v)]
            DV[i] = norm(deltaV)
            if should_print:
                self.print_dsm(v, r, deltaV, v_beg_l,
                               t_P[i].mjd + dt / DAY2SEC)

        # Last Delta-v
        if self.__add_vinf_arr:
            Vexc_arr = [a - b for a, b in zip(v_end_l, v_P[-1])]
            DV[-1] = self.burn_cost(self.seq[-1], Vexc_arr)
            if should_print:
                self.print_arrival(self.seq[-1], Vexc_arr, t_P[-1].mjd)

        fuelCost = sum(DV)

        if should_print:
            print("Total fuel cost:     %10.3f m/s" % round(fuelCost, 3))

        if self.f_dimension == 1:
            return (fuelCost, )
        else:
            return (fuelCost, sum(T))
예제 #16
0
    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)
예제 #17
0
    def ic_from_mga_1dsm(self, x):
        """
        x_lt = prob.ic_from_mga_1dsm(x_mga)

        - x_mga: compatible trajectory as encoded by an mga_1dsm problem

        Returns an initial guess for the low-thrust trajectory, converting the mga_1dsm solution x_dsm. The user
        is responsible that x_mga makes sense (i.e. it is a viable mga_1dsm representation). The conversion is done by importing in the
        low-thrust encoding a) the launch date b) all the legs durations, c) the in and out relative velocities at each planet.
        All throttles are put to zero.

        Example::

          x_lt= prob.ic_from_mga_1dsm(x_mga)
        """
        from math import pi, cos, sin, acos
        from scipy.linalg import norm
        from PyKEP import propagate_lagrangian, lambert_problem, DAY2SEC, fb_prop

        retval = list([0.0] * self.dimension)
        # 1 -  we 'decode' the chromosome recording the various times of flight (days) in the list T
        T = list([0] * (self.__n_legs))

        for i in range(len(T)):
            T[i] = log(x[2 + 4 * i])
        total = sum(T)
        T = [x[1] * time / total for time in T]

        retval[0] = x[0]
        for i in range(self.__n_legs):
            retval[1 + 8 * i] = T[i]
            retval[2 + 8 * i] = self.__sc.mass

        # 2 - We compute the epochs and ephemerides of the planetary encounters
        t_P = list([None] * (self.__n_legs + 1))
        r_P = list([None] * (self.__n_legs + 1))
        v_P = list([None] * (self.__n_legs + 1))
        DV = list([None] * (self.__n_legs + 1))

        for i, planet in enumerate(self.seq):
            t_P[i] = epoch(x[0] + sum(T[0:i]))
            r_P[i], v_P[i] = self.seq[i].eph(t_P[i])

        # 3 - We start with the first leg
        theta = 2 * pi * x[1]
        phi = acos(2 * x[2] - 1) - pi / 2

        Vinfx = x[3] * cos(phi) * cos(theta)
        Vinfy = x[3] * cos(phi) * sin(theta)
        Vinfz = x[3] * sin(phi)

        retval[3:6] = [Vinfx, Vinfy, Vinfz]

        v0 = [a + b for a, b in zip(v_P[0], [Vinfx, Vinfy, Vinfz])]
        r, v = propagate_lagrangian(r_P[0], v0, x[4] * T[0] * DAY2SEC, MU_SUN)

        # Lambert arc to reach seq[1]
        dt = (1 - x[4]) * T[0] * DAY2SEC
        l = lambert_problem(r, r_P[1], dt, MU_SUN)
        v_end_l = l.get_v2()[0]
        v_beg_l = l.get_v1()[0]

        retval[6:9] = [a - b for a, b in zip(v_end_l, v_P[1])]

        # 4 - And we proceed with each successive leg
        for i in range(1, self.__n_legs):
            # Fly-by
            v_out = fb_prop(v_end_l, v_P[i],
                            x[7 + (i - 1) * 4] * self.seq[i].radius,
                            x[6 + (i - 1) * 4], self.seq[i].mu_self)
            retval[3 + i * 8:6 +
                   i * 8] = [a - b for a, b in zip(v_out, v_P[i])]
            # s/c propagation before the DSM
            r, v = propagate_lagrangian(r_P[i], v_out,
                                        x[8 + (i - 1) * 4] * T[i] * DAY2SEC,
                                        MU_SUN)
            # Lambert arc to reach Earth during (1-nu2)*T2 (second segment)
            dt = (1 - x[8 + (i - 1) * 4]) * T[i] * DAY2SEC
            l = lambert_problem(r, r_P[i + 1], dt, MU_SUN)
            v_end_l = l.get_v2()[0]
            v_beg_l = l.get_v1()[0]
            # DSM occuring at time nu2*T2
            DV[i] = norm([a - b for a, b in zip(v_beg_l, v)])
            retval[6 + i * 8:9 +
                   i * 8] = [a - b for a, b in zip(v_end_l, v_P[i + 1])]
        return retval
예제 #18
0
    def _compute_constraints_impl(self, x):
        # 1 - We decode the chromosome extracting the time of flights
        T = list([0] * (self.__n_legs))
        for i in range(self.__n_legs):
            T[i] = x[1 + i * 8]

        # 2 - We compute the epochs and ephemerides of the planetary encounters
        t_P = list([None] * (self.__n_legs + 1))
        r_P = list([None] * (self.__n_legs + 1))
        v_P = list([None] * (self.__n_legs + 1))

        for i, planet in enumerate(self.seq):
            t_P[i] = epoch(x[0] + sum(T[0:i]))
            r_P[i], v_P[i] = self.seq[i].eph(t_P[i])

        # 3 - We iterate through legs to compute mismatches and throttles constraints
        ceq = list()
        cineq = list()
        m0 = self.__sc.mass
        for i in range(self.__n_legs):
            # First Leg
            v = [a + b for a, b in zip(v_P[i], x[(3 + i * 8):(6 + i * 8)])]
            x0 = sc_state(r_P[i], v, m0)
            v = [a + b for a, b in zip(v_P[i + 1], x[(6 + i * 8):(9 + i * 8)])]
            xe = sc_state(r_P[i + 1], v, x[2 + i * 8])
            throttles = x[(1 + 8 * self.__n_legs + 3 * sum(self.__n_seg[:i])):(
                1 + 8 * self.__n_legs + 3 * sum(self.__n_seg[:i]) +
                3 * self.__n_seg[i])]
            self.__leg.set(t_P[i], x0, throttles, t_P[i + 1], xe)
            # update mass!
            m0 = x[2 + 8 * i]
            ceq.extend(self.__leg.mismatch_constraints())
            cineq.extend(self.__leg.throttles_constraints())

        # Adding the boundary constraints
        # departure
        v_dep_con = (x[3]**2 + x[4]**2 + x[5]**2 -
                     self.__vinf_dep**2) / (EARTH_VELOCITY**2)
        # arrival
        v_arr_con = (x[6 +
                       (self.__n_legs - 1) * 8]**2 + x[7 +
                                                       (self.__n_legs - 1) * 8]
                     **2 + x[8 + (self.__n_legs - 1) * 8]**2 -
                     self.__vinf_arr**2) / (EARTH_VELOCITY**2)
        cineq.append(v_dep_con * 100)
        cineq.append(v_arr_con * 100)

        # We add the fly-by constraints
        for i in range(self.__n_legs - 1):
            DV_eq, alpha_ineq = fb_con(x[6 + i * 8:9 + i * 8],
                                       x[11 + i * 8:14 + i * 8],
                                       self.seq[i + 1])
            ceq.append(DV_eq / (EARTH_VELOCITY**2))
            cineq.append(alpha_ineq)

        # Making the mismatches non dimensional
        for i in range(self.__n_legs):
            ceq[0 + i * 7] /= AU
            ceq[1 + i * 7] /= AU
            ceq[2 + i * 7] /= AU
            ceq[3 + i * 7] /= EARTH_VELOCITY
            ceq[4 + i * 7] /= EARTH_VELOCITY
            ceq[5 + i * 7] /= EARTH_VELOCITY
            ceq[6 + i * 7] /= self.__sc.mass

        # We assemble the constraint vector
        retval = list()
        retval.extend(ceq)
        retval.extend(cineq)

        return retval
예제 #19
0
    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 legs .......
        # 1 - We decode the chromosome extracting the time of flights
        T = list([0] * (self.__n_legs))
        for i in range(self.__n_legs):
            T[i] = x[1 + i * 8]

        # 2 - We compute the epochs and ephemerides of the planetary encounters
        t_P = list([None] * (self.__n_legs + 1))
        r_P = list([None] * (self.__n_legs + 1))
        v_P = list([None] * (self.__n_legs + 1))

        for i, planet in enumerate(self.seq):
            t_P[i] = epoch(x[0] + sum(T[0:i]))
            r_P[i], v_P[i] = self.seq[i].eph(t_P[i])

        # 3 - We iterate through legs to compute mismatches and throttles constraints
        ceq = list()
        cineq = list()
        m0 = self.__sc.mass
        for i in range(self.__n_legs):
            # First Leg
            v = [a + b for a, b in zip(v_P[i], x[(3 + i * 8):(6 + i * 8)])]
            x0 = sc_state(r_P[i], v, m0)
            v = [
                a + b for a, b in zip(v_P[i + 1], x[(6 + i * 8):(11 + i * 8)])
            ]
            xe = sc_state(r_P[i + 1], v, x[2 + i * 8])
            throttles = x[(1 + 8 * self.__n_legs + 3 * sum(self.__n_seg[:i])):(
                1 + 8 * self.__n_legs + 3 * sum(self.__n_seg[:i]) +
                3 * self.__n_seg[i])]
            self.__leg.set(t_P[i], x0, throttles, t_P[i + 1], xe)
            # update mass!
            m0 = x[2 + 8 * i]
            plot_sf_leg(self.__leg, units=AU, N=10, ax=axis)

        # Plotting planets
        for i, planet in enumerate(self.seq):
            plot_planet(planet,
                        t_P[i],
                        units=AU,
                        legend=True,
                        color=(0.7, 0.7, 1),
                        ax=axis)

        plt.show()
        return axis
예제 #20
0
    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)
예제 #21
0
    def ic_from_mga_1dsm(self, x):
        """
        x_lt = prob.ic_from_mga_1dsm(x_mga)

        - x_mga: compatible trajectory as encoded by an mga_1dsm problem

        Returns an initial guess for the low-thrust trajectory, converting the mga_1dsm solution x_dsm. The user
        is responsible that x_mga makes sense (i.e. it is a viable mga_1dsm representation). The conversion is done by importing in the
        low-thrust encoding a) the launch date b) all the legs durations, c) the in and out relative velocities at each planet.
        All throttles are put to zero.

        Example::

          x_lt= prob.ic_from_mga_1dsm(x_mga)
        """
        from math import pi, cos, sin, acos
        from scipy.linalg import norm
        from PyKEP import propagate_lagrangian, lambert_problem, DAY2SEC, fb_prop

        retval = list([0.0] * self.dimension)
        # 1 -  we 'decode' the chromosome recording the various times of flight (days) in the list T
        T = list([0] * (self.__n_legs))

        for i in range(len(T)):
            T[i] = log(x[2 + 4 * i])
        total = sum(T)
        T = [x[1] * time / total for time in T]

        retval[0] = x[0]
        for i in range(self.__n_legs):
            retval[1 + 8 * i] = T[i]
            retval[2 + 8 * i] = self.__sc.mass

        # 2 - We compute the epochs and ephemerides of the planetary encounters
        t_P = list([None] * (self.__n_legs + 1))
        r_P = list([None] * (self.__n_legs + 1))
        v_P = list([None] * (self.__n_legs + 1))
        DV = list([None] * (self.__n_legs + 1))

        for i, planet in enumerate(self.seq):
            t_P[i] = epoch(x[0] + sum(T[0:i]))
            r_P[i], v_P[i] = self.seq[i].eph(t_P[i])

        # 3 - We start with the first leg
        theta = 2 * pi * x[1]
        phi = acos(2 * x[2] - 1) - pi / 2

        Vinfx = x[3] * cos(phi) * cos(theta)
        Vinfy = x[3] * cos(phi) * sin(theta)
        Vinfz = x[3] * sin(phi)

        retval[3:6] = [Vinfx, Vinfy, Vinfz]

        v0 = [a + b for a, b in zip(v_P[0], [Vinfx, Vinfy, Vinfz])]
        r, v = propagate_lagrangian(r_P[0], v0, x[4] * T[0] * DAY2SEC, MU_SUN)

        # Lambert arc to reach seq[1]
        dt = (1 - x[4]) * T[0] * DAY2SEC
        l = lambert_problem(r, r_P[1], dt, MU_SUN)
        v_end_l = l.get_v2()[0]
        v_beg_l = l.get_v1()[0]

        retval[6:9] = [a - b for a, b in zip(v_end_l, v_P[1])]

        # 4 - And we proceed with each successive leg
        for i in range(1, self.__n_legs):
            # Fly-by
            v_out = fb_prop(v_end_l, v_P[i], x[7 + (i - 1) * 4] * self.seq[i].radius, x[6 + (i - 1) * 4], self.seq[i].mu_self)
            retval[3 + i * 8:6 + i * 8] = [a - b for a, b in zip(v_out, v_P[i])]
            # s/c propagation before the DSM
            r, v = propagate_lagrangian(r_P[i], v_out, x[8 + (i - 1) * 4] * T[i] * DAY2SEC, MU_SUN)
            # Lambert arc to reach Earth during (1-nu2)*T2 (second segment)
            dt = (1 - x[8 + (i - 1) * 4]) * T[i] * DAY2SEC
            l = lambert_problem(r, r_P[i + 1], dt, MU_SUN)
            v_end_l = l.get_v2()[0]
            v_beg_l = l.get_v1()[0]
            # DSM occuring at time nu2*T2
            DV[i] = norm([a - b for a, b in zip(v_beg_l, v)])
            retval[6 + i * 8:9 + i * 8] = [a - b for a, b in zip(v_end_l, v_P[i + 1])]
        return retval
예제 #22
0
    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.orbit_plots import plot_planet, plot_lambert, plot_kepler

        if ax is None:
            mpl.rcParams['legend.fontsize'] = 10
            fig = plt.figure()
            axis = fig.gca(projection='3d')
        else:
            axis = ax

        axis.scatter(0, 0, 0, color='y')

        # 1 -  we 'decode' the chromosome recording the various times of flight
        # (days) in the list T and the cartesian components of vinf
        T, Vinfx, Vinfy, Vinfz = self._decode_times_and_vinf(x)

        # 2 - We compute the epochs and ephemerides of the planetary encounters
        t_P = list([None] * (self.__n_legs + 1))
        r_P = list([None] * (self.__n_legs + 1))
        v_P = list([None] * (self.__n_legs + 1))
        DV = list([None] * (self.__n_legs + 1))

        for i, planet in enumerate(self.seq):
            t_P[i] = epoch(x[0] + sum(T[0:i]))
            r_P[i], v_P[i] = planet.eph(t_P[i])
            plot_planet(planet,
                        t0=t_P[i],
                        color=(0.8, 0.6, 0.8),
                        legend=True,
                        units=AU,
                        ax=axis)

        # 3 - We start with the first leg
        v0 = [a + b for a, b in zip(v_P[0], [Vinfx, Vinfy, Vinfz])]
        r, v = propagate_lagrangian(r_P[0], v0, x[5] * T[0] * DAY2SEC,
                                    self.common_mu)

        plot_kepler(r_P[0],
                    v0,
                    x[5] * T[0] * DAY2SEC,
                    self.common_mu,
                    N=100,
                    color='b',
                    legend=False,
                    units=AU,
                    ax=axis)

        # Lambert arc to reach seq[1]
        dt = (1 - x[5]) * T[0] * DAY2SEC
        l = lambert_problem(r, r_P[1], dt, self.common_mu, False, False)
        plot_lambert(l, sol=0, color='r', legend=False, units=AU, ax=axis)
        v_end_l = l.get_v2()[0]
        v_beg_l = l.get_v1()[0]

        # First DSM occuring at time nu1*T1
        DV[0] = norm([a - b for a, b in zip(v_beg_l, v)])

        # 4 - And we proceed with each successive leg
        for i in range(1, self.__n_legs):
            # Fly-by
            v_out = fb_prop(v_end_l, v_P[i],
                            x[8 + (i - 1) * 4] * self.seq[i].radius,
                            x[7 + (i - 1) * 4], self.seq[i].mu_self)
            # s/c propagation before the DSM
            r, v = propagate_lagrangian(r_P[i], v_out,
                                        x[9 + (i - 1) * 4] * T[i] * DAY2SEC,
                                        self.common_mu)
            plot_kepler(r_P[i],
                        v_out,
                        x[9 + (i - 1) * 4] * T[i] * DAY2SEC,
                        self.common_mu,
                        N=100,
                        color='b',
                        legend=False,
                        units=AU,
                        ax=axis)
            # Lambert arc to reach Earth during (1-nu2)*T2 (second segment)
            dt = (1 - x[9 + (i - 1) * 4]) * T[i] * DAY2SEC

            l = lambert_problem(r, r_P[i + 1], dt, self.common_mu, False,
                                False)
            plot_lambert(l,
                         sol=0,
                         color='r',
                         legend=False,
                         units=AU,
                         N=1000,
                         ax=axis)

            v_end_l = l.get_v2()[0]
            v_beg_l = l.get_v1()[0]
            # DSM occuring at time nu2*T2
            DV[i] = norm([a - b for a, b in zip(v_beg_l, v)])
        plt.show()
        return axis
예제 #23
0
    def point(self, x, filename):
        """
	prob.point(decision_vector, filename)
	
	This method will save all the relevant simulation data for the trajectory described by decision_vector
	in json form in the file 'filename.json'.
	The data generated can then be used by the postprocessing toolbox (from this fork of PyKEP : PyKEP/postProcessingToolbox/), without having to
	re-create a prob abject. Indeed, if the problem definition is changed, the decision_vector will not mean anything:
	it only encode a trajectory for a very specific problem. When tens or hundreds of trajectories are generated, and 
	then compared, keeping only the decision vector is not a good idea, if the parameters of the problems have been tweaked 
	to realize those tens or hundreds of different simulations.
	
	The data stored in the file can be imported using import.json from the json package. The description of the stored data
	has still to be described in detail
	// TODO : description of the content of the .json file
	Those files are to be given as parameters for the postprocessing toolbox.
	"""

        from PyKEP import epoch, AU
        from PyKEP.sims_flanagan import sc_state
        from PyKEP.orbit_plots import plot_planet, plot_sf_leg
        from PyKEP.orbit_plots import point_sf_leg, point_kepler, point_taylor, point_planet
        from scipy.linalg import norm
        from math import sqrt
        import csv
        import pprint
        from PyKEP.trajopt.motor import getObjectMotor
        from PyKEP.trajopt.spacecraft import getObjectSpacecraft

        XYZ = []
        xx = []
        yy = []
        zz = []
        tt = []
        mm = []
        x_bounds = []
        y_bounds = []
        z_bounds = []

        seq1 = self.seq1
        seq2 = self.seq2

        data = {}

        # Plotting the legs .......
        # 1 - We decode the chromosome extracting the time of flights
        T = list([0] * (self.__n_legs))
        for i in range(self.__n_legs):
            T[i] = x[3 + i * 8]

    # 2 - We compute the epochs and ephemerides of the planetary encounters
        t_P = list([None] * (self.__n_legs + 2))
        r_P = list([None] * (self.__n_legs + 2))
        v_P = list([None] * (self.__n_legs + 2))

        for i, planet in enumerate(self.seq1):
            t_P[i] = epoch(x[0] + sum(T[0:i]))
            r_P[i], v_P[i] = self.seq1[i].eph(t_P[i])
        for i, planet in enumerate(self.seq2):
            t_P[i + len(seq1)] = epoch(x[0] + sum(T[0:i + len(seq1) - 1]) +
                                       x[1])
            r_P[i + len(seq1)], v_P[i + len(seq1)] = self.seq2[i].eph(
                t_P[i + len(seq1)])

    # 3 - We iterate through legs to compute mismatches and throttles constraints
        ceq = list()
        cineq = list()
        m0 = x[2]
        data['legs'] = []
        massesAlongTheWay = [m0]
        self.__leg.set_spacecraft(self.__spacecrafts[0])
        sc = self.__spacecrafts[0]
        for i in range(len(self.seq1) - 1):
            # First Leg
            v = [a + b for a, b in zip(v_P[i], x[(5 + i * 8):(8 + i * 8)])]
            x0 = sc_state(r_P[i], v, m0)
            v = [
                a + b for a, b in zip(v_P[i + 1], x[(8 + i * 8):(11 + i * 8)])
            ]
            xe = sc_state(r_P[i + 1], v, x[4 + i * 8])
            throttles = x[(3 + 8 * self.__n_legs + 3 * sum(self.__n_seg[:i])):(
                3 + 8 * self.__n_legs + 3 * sum(self.__n_seg[:i]) +
                3 * self.__n_seg[i])]
            self.__leg.set(t_P[i], x0, throttles, t_P[i + 1], xe)
            # update mass!
            minit = m0
            m0 = x[4 + 8 * i]
            massesAlongTheWay = massesAlongTheWay + [m0]
            xi, yi, zi, mi, ti, Txi, Tyi, Tzi, Tmaxi, x_boundsi, y_boundsi, z_boundsi = point_sf_leg(
                self.__leg, units=AU, N=10)
            xx = xx + xi
            yy = yy + yi
            zz = zz + zi
            ti = [e + t_P[i].jd for e in ti]
            #for k in range(len(Txi)):
            #    print norm([Tyi[k],Txi[k],Tzi[k]])
            data['legs'] = data['legs'] + [{
                'x': [e for e in xi],
                'y': [e for e in yi],
                'z': [e for e in zi],
                'm': [e for e in mi],
                't': [e for e in ti],
                'P_tot': [sc.get_totalPower(norm(e)) for e in zip(xi, yi, zi)],
                'P_engine': [
                    sc.DutyCycle *
                    sc.get_powerThrust(norm(e[0:3]) * e[3] / sc.DutyCycle)
                    for e in zip(Txi, Tyi, Tzi, Tmaxi)
                ],
                'Tx': [e for e in Txi],
                'Ty': [e for e in Tyi],
                'Tz': [e for e in Tzi],
                'Tmax': [e for e in Tmaxi],
                'mi':
                minit,
                'mf':
                m0,
                'planet1': {
                    'name': seq1[i].name,
                    'date': t_P[i].jd
                },
                'planet2': {
                    'name': seq1[i + 1].name,
                    'date': t_P[i + 1].jd
                }
            }]
            XYZ = XYZ + [xi] + [yi] + [zi]
            x_bounds = x_bounds + x_boundsi
            y_bounds = y_bounds + y_boundsi
            z_bounds = z_bounds + z_boundsi
    #outbound
        m0 = m0 - self.__dm  # mass lost around ceres
        massesAlongTheWay = massesAlongTheWay + [m0]
        self.__leg.set_spacecraft(self.__spacecrafts[1])
        sc = self.__spacecrafts[1]
        for i in range(
                len(self.seq1) - 1,
                len(self.seq1) + len(self.seq2) - 2):
            # First Leg
            v = [a + b for a, b in zip(v_P[i + 1], x[(5 + i * 8):(8 + i * 8)])]
            x0 = sc_state(r_P[i + 1], v, m0)
            v = [
                a + b for a, b in zip(v_P[i + 2], x[(8 + i * 8):(11 + i * 8)])
            ]
            xe = sc_state(r_P[i + 2], v, x[4 + i * 8])
            throttles = x[(3 + 8 * self.__n_legs + 3 * sum(self.__n_seg[:i])):(
                3 + 8 * self.__n_legs + 3 * sum(self.__n_seg[:i]) +
                3 * self.__n_seg[i])]
            self.__leg.set(t_P[i + 1], x0, throttles, t_P[i + 2], xe)
            # update mass!
            minit = m0
            m0 = x[4 + 8 * i]
            massesAlongTheWay = massesAlongTheWay + [m0]
            xi, yi, zi, mi, ti, Txi, Tyi, Tzi, Tmaxi, x_boundsi, y_boundsi, z_boundsi = point_sf_leg(
                self.__leg, units=AU, N=10)
            xx = xx + xi
            yy = yy + yi
            zz = zz + zi
            ti = [e + t_P[i + 1].jd for e in ti]
            #for k in range(len(Txi)):
            #    print norm([Tyi[k],Txi[k],Tzi[k]])
            data['legs'] = data['legs'] + [{
                'x': [e for e in xi],
                'y': [e for e in yi],
                'z': [e for e in zi],
                'm': [e for e in mi],
                't': [e for e in ti],
                'P_tot': [sc.get_totalPower(norm(e)) for e in zip(xi, yi, zi)],
                'P_engine': [
                    sc.DutyCycle *
                    sc.get_powerThrust(norm(e[0:3]) * e[3] / sc.DutyCycle)
                    for e in zip(Txi, Tyi, Tzi, Tmaxi)
                ],
                'Tx': [e for e in Txi],
                'Ty': [e for e in Tyi],
                'Tz': [e for e in Tzi],
                'Tmax': [e for e in Tmaxi],
                'mi':
                minit,
                'mf':
                m0,
                'planet1': {
                    'name': seq2[i - len(seq1) - 2].name,
                    'date': t_P[i + 1].jd
                },
                'planet2': {
                    'name': seq2[i + 1 - len(seq1) - 2].name,
                    'date': t_P[i + 2].jd
                }
            }]
            XYZ = XYZ + [xi] + [yi] + [zi]
            x_bounds = x_bounds + x_boundsi
            y_bounds = y_bounds + y_boundsi
            z_bounds = z_bounds + z_boundsi

        XYZplanet = []
        data['planetOrbits'] = []
        data['planetPosition'] = []
        listAlreadySaved = []
        for i, planet in enumerate(self.seq1):
            xp, yp, zp = point_planet(planet, t_P[i], units=AU)
            #Save orbit if it has not been done already
            if (seq1[i].name not in listAlreadySaved):
                listAlreadySaved.append(seq1[i].name)
                data['planetOrbits'].append({
                    'name': seq1[i].name,
                    'x': [e for e in xp],
                    'y': [e for e in yp],
                    'z': [e for e in zp]
                })
            data['planetPosition'].append({
                'name': seq1[i].name,
                'x': xp[0],
                'y': yp[0],
                'z': zp[0],
                'dateS': pprint.pformat(t_P[i])[0:20],
                'date': t_P[i].jd,
                'scmass': massesAlongTheWay[i]
            })
        for i, planet in enumerate(self.seq2):
            xp, yp, zp = point_planet(planet, t_P[i + len(seq1)], units=AU)
            #Save orbit if it has not been done already
            if (seq2[i].name not in listAlreadySaved):
                listAlreadySaved.append(seq2[i].name)
                data['planetOrbits'].append({
                    'name': seq2[i].name,
                    'x': [e for e in xp],
                    'y': [e for e in yp],
                    'z': [e for e in zp]
                })
            data['planetPosition'].append({
                'name':
                seq2[i].name,
                'x':
                xp[0],
                'y':
                yp[0],
                'z':
                zp[0],
                'dateS':
                pprint.pformat(t_P[i + len(seq1)])[0:20],
                'date':
                t_P[i + len(seq1)].jd,
                'scmass':
                massesAlongTheWay[i + 3]
            })

    #Calculate vinf velocities
        v_dep_1 = sqrt(x[5]**2 + x[6]**2 + x[7]**2)
        v_arr_1 = sqrt(x[8 + (len(seq1) - 2) * 8]**2 +
                       x[9 + (len(seq1) - 2) * 8]**2 +
                       x[10 + (len(seq1) - 2) * 8]**2)
        v_dep_2 = sqrt(x[5 + (len(seq1) - 1) * 8]**2 +
                       x[6 + (len(seq1) - 1) * 8]**2 +
                       x[7 + (len(seq1) - 1) * 8]**2)
        v_arr_2 = sqrt(x[8 + (len(seq1) - 1 + len(seq2) - 2) * 8]**2 +
                       x[9 + (len(seq1) - 1 + len(seq2) - 2)]**2 +
                       x[10 * (len(seq1) - 1 + len(seq2) - 2)]**2)

        #Logging all trajectory parameters
        data['traj'] = {}
        data['traj']['high_fidelity'] = self.__leg.high_fidelity
        data['traj']['solar_powered'] = self.__leg.solar_powered
        data['traj']['outbound'] = [[seq1[i].name, t_P[i].jd]
                                    for i in range(len(seq1))]
        data['traj']['inbound'] = [[seq2[i].name, t_P[i + len(seq1)].jd]
                                   for i in range(len(seq2))]
        data['traj']['vinf'] = {
            'v_dep1': v_dep_1,
            'v_dep2': v_dep_2,
            'v_arr1': v_arr_1,
            'v_arr2': v_arr_2
        }
        data['traj']['spacecrafts'] = [
            getObjectSpacecraft(self.__spacecrafts[0]),
            getObjectSpacecraft(self.__spacecrafts[1])
        ]
        data['traj']['duty_cycle'] = [
            self.__spacecrafts[0].DutyCycle,
            self.__spacecrafts[1].DutyCycle,
        ]
        data['traj']['dm'] = self.__dm
        data['traj']['mi'] = x[2]
        data['traj']['mf'] = self.__mf
        data['traj']['decision_vector'] = x
        data['traj']['dt'] = x[1]
        data['traj']['t_launch'] = t_P[0].jd
        data['traj']['t_launchS'] = pprint.pformat(t_P[0])[0:20]
        data['traj']['t_return'] = t_P[-1].jd
        data['traj']['t_returnS'] = pprint.pformat(t_P[-1])[0:20]
        data['traj']['duration'] = t_P[-1].jd - t_P[0].jd

        import json
        with open(filename, 'w') as outfile:
            json.dump(data, outfile)

    # File structure:
    # Number of legs, length points, number of planets to plot, length points
    # Legs trajectories
    # Planets trajectories
    # Planets names
    #with open('test1.csv', 'w') as csvfile:
    #    writer = csv.writer(csvfile)
    #    #writer.writerow([self.__n_legs, len(XYZ[0]), len(list_planet),len(XYZplanet[0])])
    #    for i in range(len(XYZ)):
    #        writer.writerow(XYZ[i])
    #    for i in range(len(XYZplanet)):
    #        writer.writerow(XYZplanet[i])
    #    #writer.writerow(list_planet)

        return xx, yy, zz, x_bounds, y_bounds, z_bounds, data
예제 #24
0
    def plot_dists_thrust(self, x, ax=None):
        """
        ax = prob.plot_dists_thrust(self, x, ax=None)

        - x: encoded trajectory
        - [out] ax: matplotlib axis where to plot

        Plots the distance of the spacecraft from the Earth/Sun and the thrust profile
        """
        import matplotlib as mpl
        import matplotlib.pyplot as plt

        # Creating the axis if necessary
        if ax is None:
            mpl.rcParams['legend.fontsize'] = 10
            fig = plt.figure()
            axis = fig.add_subplot(111)
        else:
            axis = ax

        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 = [x[3 + 3 * i : 6 + 3 * i] for i in range(n_seg)]
        thrusts = [min(1., np.linalg.norm(t)) for t in throttles]
        thrusts.append(thrusts[-1]) # duplicate the last for plotting

        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] / AU
        yfwd[0] = rfwd[0][1] / AU
        zfwd[0] = rfwd[0][2] / AU
        r_E = [ri/AU for ri in self.__earth.eph(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] / AU
            yfwd[i+1] = rfwd[i+1][1] / AU
            zfwd[i+1] = rfwd[i+1][2] / AU
            r_E = [ri/AU for ri in self.__earth.eph(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] / AU
        ybwd[-1] = rbwd[-1][1] / AU
        zbwd[-1] = rbwd[-1][2] / AU
        r_E = [ri/AU for ri in self.__earth.eph(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] / AU
            ybwd[-i-2] = rbwd[-i-2][1] / AU
            zbwd[-i-2] = rbwd[-i-2][2] / AU
            r_E = [ri/AU for ri in self.__earth.eph(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]])

        axis.set_xlabel("t [mjd2000]")
        # Plot Earth distance
        axis.plot(times,dist_earth, c = 'b', label = "sc-Earth")
        # Plot Sun distance
        axis.plot(times,dist_sun, c = 'y', label = "sc-Sun")
        axis.set_ylabel("distance [AU]", color = 'k')
        axis.set_ylim(bottom = 0.)
        axis.tick_params('y', colors = 'k')
        axis.legend(loc=2)
        # draw threshold where Earth gravity equals 0.1*Tmax
        axis.axhline(y = np.sqrt(MU_EARTH * self.__sc.mass / (self.__sc.thrust * 0.1)) / AU, c = 'g', ls = ":", lw = 1)
        # Plot thrust profile
        axis = axis.twinx()
        axis.step(np.concatenate((fwd_grid, bwd_grid[1:])), thrusts, where = "post", c = 'r', linestyle = '--')
        axis.set_ylabel("T/Tmax",color='r')
        axis.tick_params('y',colors='r')
        axis.set_xlim([times[0],times[-1]])
        axis.set_ylim([0,1.2])

        if ax is None:  # show only if axis is not set
            plt.show()

        return axis
예제 #25
0
    def __init__(self,
                 target = jpl_lp('mars'),
                 n_seg = 20,
                 grid_type = "uniform",
                 t0 = [epoch(0), epoch(1000)],
                 tof = [200, 500],
                 m0 = 50.0,
                 Tmax = 0.001,
                 Isp = 2000.0,
                 earth_gravity = False,
                 start = "earth"):
        """
        prob = lt_margo(target = jpl_lp('mars'), n_seg = 20, grid_type = "uniform", t0 = [epoch(0), epoch(1000)],
        tof = [200, 500], m0 = 50.0, Tmax = 0.001, Isp = 2000.0, earth_gravity = False, start = "earth")

        - target: target PyKEP.planet
        - n_seg: number of segments
        - grid_type: "uniform" for uniform segments, "nonuniform" for a denser grid in the first part of the trajectory
        - t0: list of two epochs defining the launch window
        - tof: list of two floats definind the minimum and maximum time of flight (days)
        - m0: initial mass of the spacecraft
        - Tmax: maximum thrust
        - Isp: engine specific impulse
        - earth_gravity: boolean specifying whether to take Earth's gravity into account
        - start: 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
        """

        # 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")

        # 1a) The decision vector length ([t0, tof, mf, [Tx,Ty,Tz] * n_seg])
        dim = 3 + n_seg * 3
        # 1b) The total number of constraints (mismatch + throttles)
        c_dim = 7 + n_seg
        # 1c) The number of inequality constraints (throttles)
        c_ineq_dim = n_seg
        # First we call the constructor for the base PyGMO problem
        super(lt_margo, self).__init__(dim, 0, 1, c_dim, c_ineq_dim, 1e-4)

        # 2) We then define some class data members
        # public:
        self.target = target
        # private:
        self.__n_seg = n_seg
        self.__grid_type = grid_type # gridding function (must be 0 in 0, 1 in 1, and strictly increasing)
        self.__sc = spacecraft(m0, Tmax, Isp)
        self.__earth = jpl_lp('earth')
        self.__earth_gravity = earth_gravity
        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)])
        fwd_seg = np.searchsorted(grid, 0.5, side='right') # index corresponding to the middle of the transfer
        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)]) * 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)]) * DAY2SEC

        # 3) We compute the 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

        # 4) And we set the bounds
        self.set_bounds(lb, ub)
예제 #26
0
    def _compute_constraints_impl(self, x):

        seq1 = self.seq1
        seq2 = self.seq2
        # 1 - We decode the chromosome extracting the time of flights
        T = list([0] * (self.__n_legs))
        for i in range(self.__n_legs):
            T[i] = x[3 + i * 8]

        # 2 - We compute the epochs and ephemerides of the planetary encounters
        t_P = list([None] * (self.__n_legs + 2))
        r_P = list([None] * (self.__n_legs + 2))
        v_P = list([None] * (self.__n_legs + 2))

        for i, planet in enumerate(self.seq1):
            t_P[i] = epoch(x[0] + sum(T[0:i]))
            r_P[i], v_P[i] = self.seq1[i].eph(t_P[i])
        for i, planet in enumerate(self.seq2):
            t_P[i + len(seq1)] = epoch(x[0] + sum(T[0:i + len(seq1) - 1]) +
                                       x[1])
            r_P[i + len(seq1)], v_P[i + len(seq1)] = self.seq2[i].eph(
                t_P[i + len(seq1)])

        # 3 - We iterate through legs to compute mismatches and throttles constraints
        ceq = list()
        cineq = list()
        m0 = x[2]
        #inbound
        self.__leg.set_spacecraft(self.__spacecrafts[0])
        for i in range(len(self.seq1) - 1):
            # First Leg
            v = [a + b for a, b in zip(v_P[i], x[(5 + i * 8):(8 + i * 8)])]
            x0 = sc_state(r_P[i], v, m0)
            v = [
                a + b for a, b in zip(v_P[i + 1], x[(8 + i * 8):(11 + i * 8)])
            ]
            xe = sc_state(r_P[i + 1], v, x[4 + i * 8])
            throttles = x[(3 + 8 * self.__n_legs + 3 * sum(self.__n_seg[:i])):(
                3 + 8 * self.__n_legs + 3 * sum(self.__n_seg[:i]) +
                3 * self.__n_seg[i])]
            self.__leg.set(t_P[i], x0, throttles, t_P[i + 1], xe)
            # update mass!
            m0 = x[4 + 8 * i]
            ceq.extend(self.__leg.mismatch_constraints())
            cineq.extend(self.__leg.throttles_constraints())
        #outbound
        self.__leg.set_spacecraft(self.__spacecrafts[1])
        m0 = m0 - self.__dm  # mass lost around ceres
        for i in range(
                len(self.seq1) - 1,
                len(self.seq1) + len(self.seq2) - 2):
            # First Leg
            v = [a + b for a, b in zip(v_P[i + 1], x[(5 + i * 8):(8 + i * 8)])]
            x0 = sc_state(r_P[i + 1], v, m0)
            v = [
                a + b for a, b in zip(v_P[i + 2], x[(8 + i * 8):(11 + i * 8)])
            ]
            xe = sc_state(r_P[i + 2], v, x[4 + i * 8])
            throttles = x[(3 + 8 * self.__n_legs + 3 * sum(self.__n_seg[:i])):(
                3 + 8 * self.__n_legs + 3 * sum(self.__n_seg[:i]) +
                3 * self.__n_seg[i])]
            self.__leg.set(t_P[i + 1], x0, throttles, t_P[i + 2], xe)
            # update mass!
            m0 = x[4 + 8 * i]
            ceq.extend(self.__leg.mismatch_constraints())
            cineq.extend(self.__leg.throttles_constraints())

        # Adding the boundary constraints
        # departure1
        v_dep_con1 = (x[5]**2 + x[6]**2 + x[7]**2 -
                      self.__vinf_dep1**2) / (EARTH_VELOCITY**2)
        # arrival1
        v_arr_con1 = (x[8 + (len(seq1) - 2) * 8]**2 +
                      x[9 +
                        (len(seq1) - 2) * 8]**2 + x[10 +
                                                    (len(seq1) - 2) * 8]**2 -
                      self.__vinf_arr1**2) / (EARTH_VELOCITY**2)
        # departure2
        v_dep_con2 = (x[5 + (len(seq1) - 1) * 8]**2 +
                      x[6 +
                        (len(seq1) - 1) * 8]**2 + x[7 +
                                                    (len(seq1) - 1) * 8]**2 -
                      self.__vinf_dep2**2) / (EARTH_VELOCITY**2)
        # arrival2
        v_arr_con2 = (x[8 + (len(seq1) - 1 + len(seq2) - 2) * 8]**2 +
                      x[9 + (len(seq1) - 1 + len(seq2) - 2)]**2 +
                      x[10 * (len(seq1) - 1 + len(seq2) - 2)]**2 -
                      self.__vinf_arr2**2) / (EARTH_VELOCITY**2)
        cineq.append(v_dep_con1 * 100)
        cineq.append(v_arr_con1 * 100)
        cineq.append(v_dep_con2 * 100)
        cineq.append(v_arr_con2 * 100)

        # We add the fly-by constraints
        for i in range(len(seq1) - 2):
            DV_eq, alpha_ineq = fb_con(x[8 + i * 8:11 + i * 8],
                                       x[13 + i * 8:16 + i * 8],
                                       self.seq1[i + 1])
            ceq.append(DV_eq / (EARTH_VELOCITY**2))
            cineq.append(alpha_ineq)
        for i in range(len(seq2) - 2):
            DV_eq, alpha_ineq = fb_con(
                x[8 + (i + len(seq1) - 1) * 8:11 + (i + len(seq1) - 1) * 8],
                x[13 + (i + len(seq1) - 1) * 8:16 + (i + len(seq1) - 1) * 8],
                self.seq2[i + 1])
            ceq.append(DV_eq / (EARTH_VELOCITY**2))
            cineq.append(alpha_ineq)

        #Adding the mass constraint
        mass_con = self.__mf - m0
        ceq.append(mass_con / self.__mf)

        # Making the mismatches non dimensional
        for i in range(self.__n_legs):
            ceq[0 + i * 7] /= AU
            ceq[1 + i * 7] /= AU
            ceq[2 + i * 7] /= AU
            ceq[3 + i * 7] /= EARTH_VELOCITY
            ceq[4 + i * 7] /= EARTH_VELOCITY
            ceq[5 + i * 7] /= EARTH_VELOCITY
            ceq[6 + i * 7] /= self.__mf

        # We assemble the constraint vector
        retval = list()
        retval.extend(ceq)
        retval.extend(cineq)

        return retval
예제 #27
0
    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)

        - start:            a PyKEP planet defining the starting orbit
        - target:           a PyKEP planet defining the target orbit
        - N_max:            maximum number of impulses
        - tof:              a list containing the box bounds [lower,upper] for the time of flight (days)
        - vinf:             a list containing the box bounds [lower,upper] for each DV magnitude (km/sec)
        - phase_free:       when True, no randezvous condition is enforced and the final orbit will be reached at an optimal true anomaly
        - multi_objective:  when True, a multi-objective problem is constructed with DV and time of flight as objectives
        - t0:               launch window defined as a list of two epochs [epoch,epoch]
        """

        # 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')

        # We compute the PyGMO problem dimensions
        dim = 2 + 4 * (N_max - 2) + 1 + phase_free
        obj_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(pl2pl_N_impulses, self).__init__(dim, 0, obj_dim, 0, 0, 0)

        # 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.__common_mu = start.mu_central_body

        # And we compute the bounds
        if phase_free:
            lb = [start.ref_epoch.mjd2000, tof[0]
                  ] + [0.0, 0.0, 0.0, vinf[0] * 1000] * (N_max - 2) + [0.0] + [
                      target.ref_epoch.mjd2000
                  ]
            ub = [
                start.ref_epoch.mjd2000 + 2 * start.period * SEC2DAY, tof[1]
            ] + [1.0, 1.0, 1.0, vinf[1] * 1000] * (N_max - 2) + [1.0] + [
                target.ref_epoch.mjd2000 + 2 * target.period * SEC2DAY
            ]
        else:
            lb = [t0[0].mjd2000, tof[0]
                  ] + [0.0, 0.0, 0.0, vinf[0] * 1000] * (N_max - 2) + [0.0]
            ub = [t0[1].mjd2000, tof[1]
                  ] + [1.0, 1.0, 1.0, vinf[1] * 1000] * (N_max - 2) + [1.0]

        # And we set them
        self.set_bounds(lb, ub)
예제 #28
0
    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.orbit_plots import plot_planet, plot_lambert, plot_kepler

        if ax is None:
            mpl.rcParams['legend.fontsize'] = 10
            fig = plt.figure()
            axis = fig.gca(projection='3d')
        else:
            axis = ax

        axis.scatter(0, 0, 0, color='y')

        # 1 -  we 'decode' the chromosome recording the various deep space
        # manouvres timing (days) in the list T
        T = list([0] * (self.N_max - 1))

        for i in range(len(T)):
            T[i] = log(x[2 + 4 * i])
        total = sum(T)
        T = [x[1] * time / total for time in T]

        # 2 - We compute the starting and ending position
        r_start, v_start = self.start.eph(epoch(x[0]))
        if self.phase_free:
            r_target, v_target = self.target.eph(epoch(x[-1]))
        else:
            r_target, v_target = self.target.eph(epoch(x[0] + x[1]))
        plot_planet(self.start,
                    t0=epoch(x[0]),
                    color=(0.8, 0.6, 0.8),
                    legend=True,
                    units=AU,
                    ax=axis)
        plot_planet(self.target,
                    t0=epoch(x[0] + x[1]),
                    color=(0.8, 0.6, 0.8),
                    legend=True,
                    units=AU,
                    ax=axis)

        # 3 - We loop across inner impulses
        rsc = r_start
        vsc = v_start
        for i, time in enumerate(T[:-1]):
            theta = 2 * pi * x[3 + 4 * i]
            phi = acos(2 * x[4 + 4 * i] - 1) - pi / 2

            Vinfx = x[5 + 4 * i] * cos(phi) * cos(theta)
            Vinfy = x[5 + 4 * i] * cos(phi) * sin(theta)
            Vinfz = x[5 + 4 * i] * sin(phi)

            # We apply the (i+1)-th impulse
            vsc = [a + b for a, b in zip(vsc, [Vinfx, Vinfy, Vinfz])]
            plot_kepler(rsc,
                        vsc,
                        T[i] * DAY2SEC,
                        self.__common_mu,
                        N=200,
                        color='b',
                        legend=False,
                        units=AU,
                        ax=axis)
            rsc, vsc = propagate_lagrangian(rsc, vsc, T[i] * DAY2SEC,
                                            self.__common_mu)

        cw = (ic2par(rsc, vsc, self.start.mu_central_body)[2] > pi / 2)
        # We now compute the remaining two final impulses
        # Lambert arc to reach seq[1]
        dt = T[-1] * DAY2SEC
        l = lambert_problem(rsc, r_target, dt, self.__common_mu, cw, False)
        plot_lambert(l,
                     sol=0,
                     color='r',
                     legend=False,
                     units=AU,
                     ax=axis,
                     N=200)
        plt.show()
        return axis
예제 #29
0
    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 * 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)
        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)

        # 2 - We compute the initial and final epochs and ephemerides
        t_i = 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 = 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]):
            ufwd[i] = [max_thrust * thr for thr in t]
            if self.__earth_gravity:
                r_E, v_E = self.__earth.eph(epoch(fwd_grid[i]))
                r_delta = [a - b for a,b in zip(r_E, rfwd[i])]
                r3 = sum([r**2 for r in r_delta])**(3/2)
                ufwd[i] = [ui + mfwd[i] * MU_EARTH / r3 * ri for ui,ri in zip(ufwd[i], r_delta)]
            rfwd[i+1], vfwd[i+1], mfwd[i+1] = propagate_taylor(rfwd[i],vfwd[i],mfwd[i],ufwd[i],fwd_dt[i],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]):
            ubwd[-i-1] = [max_thrust * thr for thr in t]
            if self.__earth_gravity:
                r_E, v_E = self.__earth.eph(epoch(bwd_grid[-i-1]))
                r_delta = [a - b for a,b in zip(r_E, rbwd[-i-1])]
                r3 = sum([r**2 for r in r_delta])**(3/2)
                ubwd[-i-1] = [ui + mbwd[-i-1] * MU_EARTH / r3 * ri for ui,ri in zip(ubwd[-i-1], r_delta)]
            rbwd[-i-2], vbwd[-i-2], mbwd[-i-2] = propagate_taylor(rbwd[-i-1],vbwd[-i-1],mbwd[-i-1],ubwd[-i-1],-bwd_dt[-i-1],MU_SUN,veff,-10,-10)

        return rfwd, rbwd, vfwd, vbwd, mfwd, mbwd, ufwd, ubwd, fwd_dt, bwd_dt
예제 #30
0
    def __init__(
            self,
            seq1=['earth', 'mars', 'ceres'],
            seq2=['ceres', 'mars', 'earth'],
            n_seg=[15] * 4,
            t0=[epoch(11000), epoch(13000)],
            tos=[200, 1000],  # time of stay on planet
            tof=[[40, 900]] * 4,
            vinf_dep1=0.001,
            vinf_arr1=0.001,
            vinf_dep2=0.001,
            vinf_arr2=5,
            dm=400.0,
            mass_end=700.0,
            Tmax=0.4,
            Isp=3800.0,
            spacecrafts=None,
            fb_rel_vel=6,
            multi_objective=False,
            high_fidelity=True,
            solar_powered=True):
        """
        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.
        """

        # We instanciate the sequences
        if seq1[-1] != seq2[0]:
            print 'Error : last planet of inbound and first planet of outbound must be the same'
        else:
            seq1 = self.make_sequence(seq1)
            seq2 = self.make_sequence(seq2)

        # 1) We compute the problem dimensions .... and call the base problem constructor
        self.__n_legs = len(seq1) + len(seq2) - 2
        n_fb = self.__n_legs - 2  # number of fylbys
        # 1a) The decision vector length
        dim = 1 + 1 + 1 + self.__n_legs * 8 + sum(n_seg) * 3
        # 1b) The total number of constraints (mass + mismatch + fly-by + boundary + throttles
        c_dim = 1 + self.__n_legs * 7 + n_fb * 2 + 4 + sum(n_seg)
        # 1c) The number of inequality constraints (boundary + fly-by angle + throttles)
        c_ineq_dim = 4 + 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_return_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.seq1 = seq1
        self.seq2 = seq2
        # private:
        self.__n_seg = n_seg
        self.__vinf_dep1 = vinf_dep1 * 1000
        self.__vinf_arr1 = vinf_arr1 * 1000
        self.__vinf_dep2 = vinf_dep2 * 1000
        self.__vinf_arr2 = vinf_arr2 * 1000
        self.__mf = mass_end
        self.__dm = dm
        #Spacecaft(s)
        if spacecrafts == None:
            sc = spacecraft(mass_end, Tmax, Isp)
            print "!!Spacecraft not defined (motors)!!"
            #sc = spacecraft(mass_end, Tmax, Isp, 0.0000331,-0.0077, 9000, 2500, 29400, 300) #T6 x 2
            #sc = spacecraft(mass_end, Tmax, Isp, 0.0000331,-0.0077, 9000, 2500, 25000, 300) #T6 x 2
            self.__spacecrafts = [sc, sc]
        elif len(spacecrafts) == 1:
            print "Copying spacecraft twice"
            self.__spacecrafts = [spacecrafts, spacecrafts]
        elif len(spacecrafts) == 2:
            self.__spacecrafts = spacecrafts
        else:
            print "!!Spacecraft definition does ot have the right size!!"
            #sc = spacecraft(mass_end, Tmax, Isp, 0.0000331,-0.0077, 9000, 2500, 29400, 300) #T6 x 2
            #sc = spacecraft(mass_end, Tmax, Isp, 0.0000331,-0.0077, 9000, 2500, 25000, 300) #T6 x 2
        # T6 Qinetic x 2
        #self.__sc = spacecraft(mass_end, Tmax, Isp, 0.0000331,-0.0077, 9000, 2500, 25000, 300)
        #self.__sc = spacecraft(mass_end, Tmax, Isp, 0.00003333,-0.0072, 10000, 2000, 29400, 300)
        #self.__sc = spacecraft(mass_end, Tmax, Isp,0.0000,0.2, 9000, 2500, 10000, 300)
        self.__leg = leg()
        self.__leg.set_mu(MU_SUN)
        self.__leg.set_spacecraft(self.__spacecrafts[0])
        self.__leg.high_fidelity = high_fidelity
        self.__leg.solar_powered = solar_powered
        fb_rel_vel *= 1000
        # 3) We compute the bounds
        lb = [t0[0].mjd2000] + [tos[0]] + [1000] + [
            0, mass_end, -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] + [tos[1]] + [5000] + [
            1, 5000, 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......
        # 3a1 for departure 1
        lb[5:8] = [-self.__vinf_dep1] * 3
        ub[5:8] = [self.__vinf_dep1] * 3
        # 3a2 for arrival 1
        lb[5 + (len(seq1) - 2) * 8:8 +
           (len(seq1) - 2) * 8] = [-self.__vinf_arr1] * 3
        ub[5 + (len(seq1) - 2) * 8:8 +
           (len(seq1) - 2) * 8] = [self.__vinf_arr1] * 3
        # 3a3 for departure 2
        lb[5 + (len(seq1) - 2 + 1) * 8:8 +
           (len(seq1) - 2 + 1) * 8] = [-self.__vinf_dep2] * 3
        ub[5 + (len(seq1) - 2 + 1) * 8:8 +
           (len(seq1) - 2 + 1) * 8] = [self.__vinf_dep2] * 3
        # 3a4 for arrival 2
        lb[-sum(self.__n_seg) * 3 - 3:-sum(self.__n_seg) *
           3] = [-self.__vinf_arr2] * 3
        ub[-sum(self.__n_seg) * 3 - 3:-sum(self.__n_seg) *
           3] = [self.__vinf_arr2] * 3
        # 3b... and for the time of flight
        lb[3:1 + 8 * self.__n_legs:8] = [el[0] for el in tof]
        ub[3:1 + 8 * self.__n_legs:8] = [el[1] for el in tof]
        # 4) And we set the bounds
        self.set_bounds(lb, ub)