Exemple #1
0
    def __init__(self, sc=spacecraft(1000, 0.3, 2500), mu=MU_SUN, alpha=1, bound=True):

        # check spacecraft
        if isinstance(sc, spacecraft):
            self.spacecraft = sc
        else:
            raise TypeError(
                "Spacecraft should be instance of pontryagin.spacecraft class.")

        # check gravitational parametre
        if not (isinstance(mu, float) or isinstance(mu, int)):
            raise TypeError(
                "Gravitational parametre, mu, must be supplied as either int or float.")
        elif not mu > 0:
            raise TypeError(
                "Gravitational parametre, mu, must be a positive number.")
        else:
            self.mu = float(mu)

        # check homotopy
        if not (isinstance(alpha, float) or isinstance(alpha, int)):
            raise TypeError(
                "Homotopy parametre, alpha, must be supplied as float or int.")
        elif not (alpha >= 0 and alpha <= 1):
            raise ValueError(
                "Homotopy parametre, alpha, must be between 0 and 1.")
        else:
            self.alpha = float(alpha)

        # check bound
        if not isinstance(bound, bool):
            raise TypeError(
                "Control bounding parametre, bound, supplied as boolean.")
        else:
            self.bound = bool(bound)

        # check control validity
        if (self.alpha == 1 and self.bound == False):
            raise ValueError(
                "Control can only be unbounded with quadratic control, i.e. bound == True if alpha == 1.")
        else:
            pass

        # spacecraft parametres
        self.c1 = self.spacecraft.thrust
        self.c2 = self.spacecraft.thrust / (self.spacecraft.isp * G0)

        # define nondimenional units
        self.L = AU
        self.V = EARTH_VELOCITY
        self.M = self.spacecraft.mass
        self.A = (self.V * self.V) / self.L
        self.F = self.M * self.A
        self.T = self.L / self.V
        self.Q = self.F / self.V

        # nondimensionalise parametres
        self.c1 /= self.F
        self.c2 /= self.Q
        self.mu /= MU_SUN
Exemple #2
0
    def __init__(self, sc=spacecraft(1000, 0.3, 2500), mu=MU_SUN, alpha=1, bound=True):

        # check spacecraft
        if isinstance(sc, spacecraft):
            self.spacecraft = sc
        else:
            raise TypeError(
                "Spacecraft should be instance of pontryagin.spacecraft class.")

        # check gravitational parameter
        if not (isinstance(mu, float) or isinstance(mu, int)):
            raise TypeError(
                "Gravitational parameter, mu, must be supplied as either int or float.")
        elif not mu > 0:
            raise TypeError(
                "Gravitational parameter, mu, must be a positive number.")
        else:
            self.mu = float(mu)

        # check homotopy
        if not (isinstance(alpha, float) or isinstance(alpha, int)):
            raise TypeError(
                "Homotopy parameter, alpha, must be supplied as float or int.")
        elif not (alpha >= 0 and alpha <= 1):
            raise ValueError(
                "Homotopy parameter, alpha, must be between 0 and 1.")
        else:
            self.alpha = float(alpha)

        # check bound
        if not isinstance(bound, bool):
            raise TypeError(
                "Control bounding parameter, bound, supplied as boolean.")
        else:
            self.bound = bool(bound)

        # check control validity
        if (self.alpha == 1 and self.bound == False):
            raise ValueError(
                "Control can only be unbounded with quadratic control, i.e. bound == True if alpha == 1.")
        else:
            pass

        # spacecraft parameter
        self.c1 = self.spacecraft.thrust
        self.c2 = self.spacecraft.thrust / (self.spacecraft.isp * G0)

        # define nondimensional units
        self.L = AU
        self.V = EARTH_VELOCITY
        self.M = self.spacecraft.mass
        self.A = (self.V * self.V) / self.L
        self.F = self.M * self.A
        self.T = self.L / self.V
        self.Q = self.F / self.V

        # nondimensionalise parameters
        self.c1 /= self.F
        self.c2 /= self.Q
        self.mu /= MU_SUN
Exemple #3
0
    def __init__(self,
                 seq=[jpl_lp('earth'),
                      jpl_lp('venus'),
                      jpl_lp('mercury')],
                 n_seg=[5, 20],
                 t0=[3000, 4000],
                 tof=[[100, 1000], [200, 2000]],
                 vinf_dep=3,
                 vinf_arr=2,
                 mass=[1200., 2000.0],
                 Tmax=0.5,
                 Isp=3500.0,
                 fb_rel_vel=6,
                 multi_objective=False,
                 high_fidelity=False):
        """
        Args:
            - seq (```list of pykep.planet```): defines the encounter sequence for the trajectory (including the initial planet).
            - n_seg (```list``` of ```int```): the number of segments to be used for each leg.
            - t0 (```list``` of ```floats```): the launch window (in mjd2000).
            - tof (```list``` of ```2D-list```): minimum and maximum time of each leg (days).
            - vinf_dep (```float```): maximum launch hyperbolic velocity allowed (in km/sec).
            - vinf_arr (```float```): maximum arrival hyperbolic velocity allowed (in km/sec).
            - mass (```float```): spacecraft starting mass. (in kg).
            - Tmax (```float```): maximum thrust (in N).
            - Isp (```float```):: engine specific impulse (in s).
.           - fb_rel_vel (```float```): determines the bounds on the maximum allowed relative velocity at all fly-bys (in km/sec).
            - multi-objective (```bool```): when True defines the problem as a multi-objective problem, returning total DV and time of flight.
            - high_fidelity (```bool```):makes the trajectory computations slower, but actually dynamically feasible.
        """
        # We define some data members (we use the double underscore to
        # indicate they are private)
        self._seq = seq
        self._n_seg = n_seg
        self._t0 = t0
        self._tof = tof
        self._vinf_dep = vinf_dep * 1000
        self._vinf_arr = vinf_arr * 1000
        self._mass = mass
        self._Tmax = Tmax
        self._fb_rel_vel = fb_rel_vel
        self._multiobjective = multi_objective
        self._high_fidelity = high_fidelity

        self._n_legs = len(seq) - 1
        self._sc = spacecraft(mass[1], Tmax, Isp)
        self._leg = leg()
        self._leg.set_mu(MU_SUN)
        self._leg.set_spacecraft(self._sc)
Exemple #4
0
    def __init__(self,
                 t0=None,
                 x0=None,
                 l0=None,
                 tf=None,
                 xf=None,
                 sc=spacecraft(1000, 0.3, 2500),
                 mu=MU_SUN,
                 freemass=True,
                 freetime=True,
                 alpha=1,
                 bound=True):
        """Initialises an indirect optimal control transcription trajectory leg.

        Args:
            - t0 (``pykep.epoch``, ``None``): Departure time [mjd2000].
            - x0 (``pykep.sims_flanagan.sc_state``, ``None``): Cartesian departure state [m, m, m, m/s, m/s, m/s, kg].
            - l0 (``numpy.ndarray``, ``list``, ``tuple``, ``None``): Costate variables [ND, ND, ND, ND, ND, ND, ND].
            - tf (``pykep.epoch``, ``None``): Arrival time [mjd2000].
            - xf (``pykep.sims_flanagan.sc_state``, ``None``): Cartesian arrival state [m, m, m, m/s, m/s, m/s, kg].
            - sc (``pykep.sims_flanagan.spacecraft``): Generic spacecraft with propulsive properties.
            - mu (``float``, ``int``): Gravitational parametre of primary body [m^3/s^2].
            - freemass (``bool``): Activates final mass transversality condition.
            - freetime (``bool``): Activates final time transversality condition. Allows final time to vary.
            - alpha (``float``, ``int``): Homotopy parametre, governing the degree to which the theoretical control law is intended to reduce propellant expenditure or energy. Setting the parametre to 1 enforces a mass-optimal control law, with a characteristic bang-bang control profile (either full throttle or off). Setting the parametre to 0 enforces a pure quadratic control law.
            - bound (``bool``): Activates bounded control, in which the control throttle is bounded between 0 and 1, otherwise the control throttle is allowed to unbounded.

        Raises:
            - TypeError: If ``sc`` is not supplied as an instance of `pykep.sims_flanagan.spacecraft`.
            - TypeError: If ``mu`` is neither supplied as an instance of ``float`` nor ``int``.
            - ValueError: If ``mu`` is not supplied as a positive number.
            - TypeError: If either ``freemass``, ``freetime``, or ``bound`` is not supplied as an instance of ``bool``.
            - AttributeError: If equality constraint dimension cannot be determined form ``freemass`` and ``freetime``.
            - TypeError: If ``alpha`` is neither supplied as an instance of ``float`` nor ``int``.
            - ValueError: If ``alpha`` is not in between 0 and 1.
            - ValueError: If ``alpha == 1`` and ``bound == False``. Control cannot be unbounded with mass-optimal control.
            - TypeError: If either ``t0`` or ``tf`` is not supplied as an instance of ``pykep.epoch``.
            - ValueError: If departure time, ``t0.mjd2000`` does not occur before arrival time, `t`f.mjd2000``.
            - TypeError: If either ``x0`` or ``xf`` is not supplied as an instance of ``pykep.sims_flanagan.sc_state``.
            - TypeError: If costate, ``l0``, is neither supplied as an instance of ``numpy.ndarray``, ``list``, nor ``tuple``.
            - TypeError: If costate, ``l0``, is does not have 7 elements. Each element of ``l0`` corresponds to the respective elements of ``x0``.

        Examples:
            >>> l = pykep.pontryagin.leg()
            >>> l = pykep.pontryagin.leg(t0, x0, l0, tf, xf)

        .. note::
            Typically spacecraft trajectories are optimised to reduce final
            mass, which theoretically results in a bang-bang control profile.
            However, a bang-bang control profile (either 0 or 1) is problematic
            to an optimiser due to its discontinous nature. The trajectory
            optimisation problem becomes easier when one first optimises with
            unbounded quadratic control (``alpha == 0 and bound == False``),
            stores the solution, then uses the solution to optimise with
            bounded quadratic control (``alpha == 0 and bound == True``). Then
            using the solution from bounded quadratic control, one can
            incrementally optimise for increasing homotopy parametres
            (e.g. ``alphas = numpy.linspace(0, 1, 200)``) until a mass-optimal
            control solution converges.

        .. note::
            Boundary conditions ``t0``, ``x0``, ``l0``, ``tf``, and ``xf``
            are optional in the constructor. If some, but not all, boundary
            conditions are supplied, they are not set and disregarded. If the
            boundary conditions are not set upon construction (``__init__``),
            they must be set with ``set(t0, x0, l0, tf, xf)``.

        .. note::
            ``mismatch_constraints`` will not work unless the boundary
            conditions have been set either through ``__init__`` or ``set``.
        """

        # check spacecraft
        if isinstance(sc, spacecraft):
            self.spacecraft = sc
        else:
            raise TypeError(
                "Spacecraft, sc, must be of pontryagin.spacecraft type.")

        # check gravitational parametre
        if not (isinstance(mu, float) or not isinstance(mu, int)):
            raise TypeError(
                "Gravitational parametre, mu, must be supplied as float or int."
            )
        elif not mu > 0:
            raise ValueError("Gravitational parametre, mu, must be positive.")
        else:
            self.mu = float(mu)

        # dynamics
        self._dynamics = _dynamics(sc=self.spacecraft,
                                   mu=mu,
                                   alpha=alpha,
                                   bound=bound)

        # check freetime, freemass, and bound
        if not all(
            [isinstance(param, bool)
             for param in [freemass, freetime, bound]]):
            raise TypeError(
                "Freemass, freetime, bound parametres must supplied as booleans."
            )
        else:
            self.freemass = bool(freemass)
            self.freetime = bool(freetime)
            self.bound = bool(bound)

        # equality constraint dimensionality
        if self.freemass and self.freetime:
            self.nec = 8
        elif self.freemass and not self.freetime:
            self.nec = 7
        elif not self.freemass and self.freetime:
            self.nec = 8
        elif not self.freemass and not self.freetime:
            self.nec = 7
        else:
            raise AttributeError(
                "Could not determine equality constraint dimensionality.")

        # check alpha
        if not (isinstance(alpha, float) or isinstance(alpha, int)):
            raise TypeError(
                "Homotopy parametre, alpha, must be supplied as float or int.")
        elif not (alpha >= 0 and alpha <= 1):
            raise ValueError(
                "Homotopy parametre, alpha, must be between 0 and 1.")
        elif (alpha == 1 and self.bound == False):
            raise ValueError(
                "If homotopy parametre, alpha, is 1, control must be bounded.")
        else:
            self.alpha = float(alpha)

        # if any of the necessary boundaries are not supplied
        if any(elem is None for elem in [t0, x0, l0, tf, xf]):
            pass

        # check validity if they're all supplied
        else:

            # check departure and arrival times
            if not all([isinstance(t, epoch) for t in [t0, tf]]):
                raise TypeError(
                    "Departure and arrival times, t0 & tf, must be supplied as pykep.epoch."
                )
            elif not t0.mjd2000 < tf.mjd2000:
                raise ValueError(
                    "Departure time must occur before arrival time.")
            else:
                self.t0 = float(t0.mjd2000)
                self.tf = float(tf.mjd2000)

            # check departure and arrival states
            states = [x0, xf]
            if not all([isinstance(state, sc_state) for state in states]):
                raise TypeError(
                    "x0 and xf must be instances of pykep.sims_flanagan.sc_state."
                )
            else:
                self.x0 = np.asarray(x0.get(), np.float64)
                self.xf = np.asarray(xf.get(), np.float64)

            # check departure costate
            if not (isinstance(l0, list) or isinstance(l0, np.ndarray)
                    or isinstance(l0, tuple)):
                raise TypeError(
                    "Departure costate, l0, must be supplied as either a list, numpy.ndarray, or tuple."
                )
            elif len(l0) != 7:
                raise TypeError("Costate vector, l0, must be 7-dimensional.")
            else:
                self.l0 = np.asarray(l0, np.float64)

        # integrator
        self._integrator = ode(
            lambda t, fs: self._dynamics._eom_fullstate(fs),
            #lambda t, fs: self._dynamics._eom_fullstate_jac(fs)
        )
Exemple #5
0
    def __init__(self, t0=None, x0=None, l0=None, tf=None, xf=None, sc=spacecraft(1000, 0.3, 2500), mu=MU_SUN, freemass=True, freetime=True, alpha=1, bound=True):
        """Initialises an indirect optimal control transcription trajectory leg.

        Args:
            - t0 (``pykep.epoch``, ``None``): Departure time [mjd2000].
            - x0 (``pykep.sims_flanagan.sc_state``, ``None``): Cartesian departure state [m, m, m, m/s, m/s, m/s, kg].
            - l0 (``numpy.ndarray``, ``list``, ``tuple``, ``None``): Costate variables [ND, ND, ND, ND, ND, ND, ND].
            - tf (``pykep.epoch``, ``None``): Arrival time [mjd2000].
            - xf (``pykep.sims_flanagan.sc_state``, ``None``): Cartesian arrival state [m, m, m, m/s, m/s, m/s, kg].
            - sc (``pykep.sims_flanagan.spacecraft``): Generic spacecraft with propulsive properties.
            - mu (``float``, ``int``): Gravitational parametre of primary body [m^3/s^2].
            - freemass (``bool``): Activates final mass transversality condition.
            - freetime (``bool``): Activates final time transversality condition. Allows final time to vary.
            - alpha (``float``, ``int``): Homotopy parametre, governing the degree to which the theoretical control law is intended to reduce propellant expenditure or energy. Setting the parametre to 1 enforces a mass-optimal control law, with a characteristic bang-bang control profile (either full throttle or off). Setting the parametre to 0 enforces a pure quadratic control law.
            - bound (``bool``): Activates bounded control, in which the control throttle is bounded between 0 and 1, otherwise the control throttle is allowed to unbounded.

        Raises:
            - TypeError: If ``sc`` is not supplied as an instance of `pykep.sims_flanagan.spacecraft`.
            - TypeError: If ``mu`` is neither supplied as an instance of ``float`` nor ``int``.
            - ValueError: If ``mu`` is not supplied as a positive number.
            - TypeError: If either ``freemass``, ``freetime``, or ``bound`` is not supplied as an instance of ``bool``.
            - AttributeError: If equality constraint dimension cannot be determined form ``freemass`` and ``freetime``.
            - TypeError: If ``alpha`` is neither supplied as an instance of ``float`` nor ``int``.
            - ValueError: If ``alpha`` is not in between 0 and 1.
            - ValueError: If ``alpha == 1`` and ``bound == False``. Control cannot be unbounded with mass-optimal control.
            - TypeError: If either ``t0`` or ``tf`` is not supplied as an instance of ``pykep.epoch``.
            - ValueError: If departure time, ``t0.mjd2000`` does not occur before arrival time, `t`f.mjd2000``.
            - TypeError: If either ``x0`` or ``xf`` is not supplied as an instance of ``pykep.sims_flanagan.sc_state``.
            - TypeError: If costate, ``l0``, is neither supplied as an instance of ``numpy.ndarray``, ``list``, nor ``tuple``.
            - TypeError: If costate, ``l0``, is does not have 7 elements. Each element of ``l0`` corresponds to the respective elements of ``x0``.

        Examples:
            >>> l = pykep.pontryagin.leg()
            >>> l = pykep.pontryagin.leg(t0, x0, l0, tf, xf)

        .. note::
            Typically spacecraft trajectories are optimised to reduce final
            mass, which theoretically results in a bang-bang control profile.
            However, a bang-bang control profile (either 0 or 1) is problematic
            to an optimiser due to its discontinous nature. The trajectory
            optimisation problem becomes easier when one first optimises with
            unbounded quadratic control (``alpha == 0 and bound == False``),
            stores the solution, then uses the solution to optimise with
            bounded quadratic control (``alpha == 0 and bound == True``). Then
            using the solution from bounded quadratic control, one can
            incrementally optimise for increasing homotopy parametres
            (e.g. ``alphas = numpy.linspace(0, 1, 200)``) until a mass-optimal
            control solution converges.

        .. note::
            Boundary conditions ``t0``, ``x0``, ``l0``, ``tf``, and ``xf``
            are optional in the constructor. If some, but not all, boundary
            conditions are supplied, they are not set and disregarded. If the
            boundary conditions are not set upon construction (``__init__``),
            they must be set with ``set(t0, x0, l0, tf, xf)``.

        .. note::
            ``mismatch_constraints`` will not work unless the boundary
            conditions have been set either through ``__init__`` or ``set``.
        """

        # check spacecraft
        if isinstance(sc, spacecraft):
            self.spacecraft = sc
        else:
            raise TypeError(
                "Spacecraft, sc, must be of pontryagin.spacecraft type.")

        # check gravitational parametre
        if not (isinstance(mu, float) or not isinstance(mu, int)):
            raise TypeError(
                "Gravitational parametre, mu, must be supplied as float or int.")
        elif not mu > 0:
            raise ValueError("Gravitational parametre, mu, must be positive.")
        else:
            self.mu = float(mu)

        # dynamics
        self._dynamics = _dynamics(
            sc=self.spacecraft, mu=mu, alpha=alpha, bound=bound)

        # check freetime, freemass, and bound
        if not all([isinstance(param, bool) for param in [freemass, freetime, bound]]):
            raise TypeError(
                "Freemass, freetime, bound parametres must supplied as booleans.")
        else:
            self.freemass = bool(freemass)
            self.freetime = bool(freetime)
            self.bound = bool(bound)

        # equality constraint dimensionality
        if self.freemass and self.freetime:
            self.nec = 8
        elif self.freemass and not self.freetime:
            self.nec = 7
        elif not self.freemass and self.freetime:
            self.nec = 8
        elif not self.freemass and not self.freetime:
            self.nec = 7
        else:
            raise AttributeError(
                "Could not determine equality constraint dimensionality.")

        # check alpha
        if not (isinstance(alpha, float) or isinstance(alpha, int)):
            raise TypeError(
                "Homotopy parametre, alpha, must be supplied as float or int.")
        elif not (alpha >= 0 and alpha <= 1):
            raise ValueError(
                "Homotopy parametre, alpha, must be between 0 and 1.")
        elif (alpha == 1 and self.bound == False):
            raise ValueError(
                "If homotopy parametre, alpha, is 1, control must be bounded.")
        else:
            self.alpha = float(alpha)

        # if any of the necessary boundaries are not supplied
        if any(elem is None for elem in [t0, x0, l0, tf, xf]):
            pass

        # check validity if they're all supplied
        else:

            # check departure and arrival times
            if not all([isinstance(t, epoch) for t in [t0, tf]]):
                raise TypeError(
                    "Departure and arrival times, t0 & tf, must be supplied as pykep.epoch.")
            elif not t0.mjd2000 < tf.mjd2000:
                raise ValueError(
                    "Departure time must occur before arrival time.")
            else:
                self.t0 = float(t0.mjd2000)
                self.tf = float(tf.mjd2000)

            # check departure and arrival states
            states = [x0, xf]
            if not all([isinstance(state, sc_state) for state in states]):
                raise TypeError(
                    "x0 and xf must be instances of pykep.sims_flanagan.sc_state.")
            else:
                self.x0 = np.asarray(x0.get(), np.float64)
                self.xf = np.asarray(xf.get(), np.float64)

            # check departure costate
            if not (isinstance(l0, list) or isinstance(l0, np.ndarray) or isinstance(l0, tuple)):
                raise TypeError(
                    "Departure costate, l0, must be supplied as either a list, numpy.ndarray, or tuple.")
            elif len(l0) != 7:
                raise TypeError("Costate vector, l0, must be 7-dimensional.")
            else:
                self.l0 = np.asarray(l0, np.float64)

        # integrator
        self._integrator = ode(
            lambda t, fs: self._dynamics._eom_fullstate(fs),
            #lambda t, fs: self._dynamics._eom_fullstate_jac(fs)
        )