Beispiel #1
0
    def from_sbdb(cls, name, **kargs):
        """Return osculating `Orbit` by using `SBDB` from Astroquery.

        Parameters
        ----------
        body_name: string
            Name of the body to make the request.

        Returns
        -------
        ss: poliastro.twobody.orbit.Orbit
            Orbit corresponding to body_name

        Examples
        --------
        >>> from poliastro.twobody.orbit import Orbit
        >>> apophis_orbit = Orbit.from_sbdb('apophis')
        """

        obj = SBDB.query(name, full_precision=True, **kargs)

        if "count" in obj:
            # no error till now ---> more than one object has been found
            # contains all the name of the objects
            objects_name = obj["list"]["name"]
            objects_name_in_str = (
                ""
            )  # used to store them in string form each in new line
            for i in objects_name:
                objects_name_in_str += i + "\n"

            raise ValueError(
                str(obj["count"]) + " different objects found: \n" + objects_name_in_str
            )

        a = obj["orbit"]["elements"]["a"].to(u.AU) * u.AU
        ecc = float(obj["orbit"]["elements"]["e"]) * u.one
        inc = obj["orbit"]["elements"]["i"].to(u.deg) * u.deg
        raan = obj["orbit"]["elements"]["om"].to(u.deg) * u.deg
        argp = obj["orbit"]["elements"]["w"].to(u.deg) * u.deg

        # Since JPL provides Mean Anomaly (M) we need to make
        # the conversion to the true anomaly (\nu)
        nu = M_to_nu(obj["orbit"]["elements"]["ma"].to(u.deg) * u.deg, ecc)

        epoch = time.Time(obj["orbit"]["epoch"].to(u.d), format="jd")

        ss = cls.from_classical(
            Sun,
            a,
            ecc,
            inc,
            raan,
            argp,
            nu,
            epoch=epoch.tdb,
            plane=Planes.EARTH_ECLIPTIC,
        )

        return ss
Beispiel #2
0
def orbit_from_record(record):
    """Return :py:class:`~poliastro.twobody.orbit.Orbit` given a record.

        Retrieve info from JPL DASTCOM5 database.

        Parameters
        ----------
        record : int
            Object record.

        Returns
        -------
        orbit : ~poliastro.twobody.orbit.Orbit
            NEO orbit.

        """
    body_data = read_record(record)
    a = body_data['A'].item() * u.au
    ecc = body_data['EC'].item() * u.one
    inc = body_data['IN'].item() * u.deg
    raan = body_data['OM'].item() * u.deg
    argp = body_data['W'].item() * u.deg
    m = body_data['MA'].item() * u.deg
    nu = M_to_nu(m, ecc)
    epoch = Time(body_data['EPOCH'].item(), format='jd')

    orbit = Orbit.from_classical(Sun, a, ecc, inc, raan, argp, nu, epoch)
    return orbit
Beispiel #3
0
def orbit_from_record(record):
    """Return :py:class:`~poliastro.twobody.orbit.Orbit` given a record.

        Retrieve info from JPL DASTCOM5 database.

        Parameters
        ----------
        record : int
            Object record.

        Returns
        -------
        orbit : ~poliastro.twobody.orbit.Orbit
            NEO orbit.

        """
    body_data = read_record(record)
    a = body_data["A"].item() * u.au
    ecc = body_data["EC"].item() * u.one
    inc = body_data["IN"].item() * u.deg
    raan = body_data["OM"].item() * u.deg
    argp = body_data["W"].item() * u.deg
    m = body_data["MA"].item() * u.deg
    nu = M_to_nu(m, ecc)
    epoch = Time(body_data["EPOCH"].item(), format="jd", scale="tdb")

    orbit = Orbit.from_classical(Sun, a, ecc, inc, raan, argp, nu, epoch)
    orbit._frame = HeliocentricEclipticJ2000(obstime=epoch)
    return orbit
Beispiel #4
0
def mean_motion(orbit, tof, **kwargs):
    r"""Propagates orbit using mean motion

    .. versionadded:: 0.9.0

    Parameters
    ----------
    orbit : ~poliastro.twobody.orbit.Orbit
        the Orbit object to propagate.
    tof : float
        Time of flight (s).

    Notes
    -----
    This method takes initial :math:`\vec{r}, \vec{v}`, calculates classical orbit parameters,
    increases mean anomaly and performs inverse transformation to get final :math:`\vec{r}, \vec{v}`
    The logic is based on formulae (4), (6) and (7) from http://dx.doi.org/10.1007/s10569-013-9476-9

    """

    k = orbit.attractor.k.to(u.km**3 / u.s**2).value
    r0 = orbit.r.to(u.km).value
    v0 = orbit.v.to(u.km / u.s).value

    # get the initial true anomaly and orbit parameters that are constant over time
    p, ecc, inc, raan, argp, nu0 = rv2coe(k, r0, v0)

    # get the initial mean anomaly
    M0 = nu_to_M(nu0, ecc)
    # strong elliptic or strong hyperbolic orbits
    if np.abs(ecc - 1.0) > 1e-2:
        a = p / (1.0 - ecc**2)
        # given the initial mean anomaly, calculate mean anomaly
        # at the end, mean motion (n) equals sqrt(mu / |a^3|)
        with u.set_enabled_equivalencies(u.dimensionless_angles()):
            M = M0 + tof * np.sqrt(k / np.abs(a**3)) * u.rad
            nu = M_to_nu(M, ecc)

    # near-parabolic orbit
    else:
        q = p * np.abs(1.0 - ecc) / np.abs(1.0 - ecc**2)
        # mean motion n = sqrt(mu / 2 q^3) for parabolic orbit
        with u.set_enabled_equivalencies(u.dimensionless_angles()):
            M = M0 + tof * np.sqrt(k / 2.0 / (q**3))
            nu = M_to_nu(M, ecc)
    with u.set_enabled_equivalencies(u.dimensionless_angles()):
        return coe2rv(k, p, ecc, inc, raan, argp, nu)
Beispiel #5
0
def mean_motion(k, r0, v0, tof, **kwargs):
    r"""Propagates orbit using mean motion

    Parameters
    ----------
    k : float
        Gravitational constant of main attractor (km^3 / s^2).
    r0 : array
        Initial position (km).
    v0 : array
        Initial velocity (km).
    ad : function(t0, u, k), optional
         Non Keplerian acceleration (km/s2), default to None.
    tof : float
        Time of flight (s).

    Notes
    -----
    This method takes initial :math:`\vec{r}, \vec{v}`, calculates classical orbit parameters,
    increases mean anomaly and performs inverse transformation to get final :math:`\vec{r}, \vec{v}`
    The logic is based on formulae (4), (6) and (7) from http://dx.doi.org/10.1007/s10569-013-9476-9

    """

    # get the initial true anomaly and orbit parameters that are constant over time
    p, ecc, inc, raan, argp, nu0 = rv2coe(k, r0, v0)

    # get the initial mean anomaly
    M0 = nu_to_M(nu0, ecc)
    # elliptic or hyperbolic orbits
    if not np.isclose(ecc, 1.0, rtol=1e-06):
        a = p / (1.0 - ecc**2)
        # given the initial mean anomaly, calculate mean anomaly
        # at the end, mean motion (n) equals sqrt(mu / |a^3|)
        with u.set_enabled_equivalencies(u.dimensionless_angles()):
            M = M0 + tof * np.sqrt(k / np.abs(a**3)) * u.rad
            nu = M_to_nu(M, ecc)

    # parabolic orbit
    else:
        q = p / 2.0
        # mean motion n = sqrt(mu / 2 q^3) for parabolic orbit
        with u.set_enabled_equivalencies(u.dimensionless_angles()):
            M = M0 + tof * np.sqrt(k / (2.0 * q**3))

        # using Barker's equation, which is solved analytically
        # for parabolic orbit, get true anomaly
        B = 3.0 * M / 2.0
        A = (B + np.sqrt(1.0 + B**2))**(2.0 / 3.0)
        D = 2.0 * A * B / (1.0 + A + A**2)

        nu = 2.0 * np.arctan(D)
    with u.set_enabled_equivalencies(u.dimensionless_angles()):
        return coe2rv(k, p, ecc, inc, raan, argp, nu)
Beispiel #6
0
def orbit_from_spk_id(spk_id, api_key=None):
    """Return :py:class:`~poliastro.twobody.orbit.Orbit` given a SPK-ID.

    Retrieve info from NASA NeoWS API, and therefore
    it only works with NEAs (Near Earth Asteroids).

    Parameters
    ----------
    spk_id : str
        SPK-ID number, which is given to each body by JPL.
    api_key : str
        NASA OPEN APIs key (default: `DEMO_KEY`)

    Returns
    -------
    orbit : ~poliastro.twobody.orbit.Orbit
        NEA orbit.

    """
    payload = {"api_key": api_key or DEFAULT_API_KEY}

    response = requests.get(NEOWS_URL + spk_id, params=payload)
    response.raise_for_status()

    orbital_data = response.json()["orbital_data"]

    attractor = Sun
    a = float(orbital_data["semi_major_axis"]) * u.AU
    ecc = float(orbital_data["eccentricity"]) * u.one
    inc = float(orbital_data["inclination"]) * u.deg
    raan = float(orbital_data["ascending_node_longitude"]) * u.deg
    argp = float(orbital_data["perihelion_argument"]) * u.deg
    m = float(orbital_data["mean_anomaly"]) * u.deg
    nu = M_to_nu(m.to(u.rad), ecc)
    epoch = Time(float(orbital_data["epoch_osculation"]),
                 format="jd",
                 scale="tdb")

    ss = Orbit.from_classical(attractor,
                              a,
                              ecc,
                              inc,
                              raan,
                              argp,
                              nu,
                              epoch,
                              plane=Planes.EARTH_ECLIPTIC)
    return ss
Beispiel #7
0
    def from_sbdb(cls, name, **kargs):
        """Return osculating `Orbit` by using `SBDB` from Astroquery.

        Parameters
        ----------
        body_name: string
            Name of the body to make the request.

        Returns
        -------
        ss: poliastro.twobody.orbit.Orbit
            Orbit corresponding to body_name

        Examples
        --------
        >>> from poliastro.twobody.orbit import Orbit
        >>> apophis_orbit = Orbit.from_sbdb('apophis')
        """

        obj = SBDB.query(name, full_precision=True, **kargs)

        a = obj["orbit"]["elements"]["a"].to(u.AU) * u.AU
        ecc = float(obj["orbit"]["elements"]["e"]) * u.one
        inc = obj["orbit"]["elements"]["i"].to(u.deg) * u.deg
        raan = obj["orbit"]["elements"]["om"].to(u.deg) * u.deg
        argp = obj["orbit"]["elements"]["w"].to(u.deg) * u.deg

        # Since JPL provides Mean Anomaly (M) we need to make
        # the conversion to the true anomaly (\nu)
        nu = M_to_nu(obj["orbit"]["elements"]["ma"].to(u.deg) * u.deg, ecc)

        epoch = time.Time(obj["orbit"]["epoch"].to(u.d), format="jd")

        ss = cls.from_classical(
            Sun,
            a,
            ecc,
            inc,
            raan,
            argp,
            nu,
            epoch=epoch.tdb,
            plane=Planes.EARTH_ECLIPTIC,
        )

        return ss
def test_from_sbdb():

    # Dictionary with structure: 'Object': [a, e, i, raan, argp, nu, epoch]
    # Notice JPL provides Mean anomaly, a conversion is needed to obtain nu

    SBDB_DATA = {
        "Ceres": (
            2.769165146349478 * u.AU,
            0.07600902762923671 * u.one,
            10.59406732590292 * u.deg,
            80.30553084093981 * u.deg,
            73.59769486239257 * u.deg,
            M_to_nu(77.37209773768207 * u.deg, 0.07600902762923671 * u.one),
        )
    }

    for target_name in SBDB_DATA.keys():

        ss_target = Orbit.from_sbdb(target_name)
        ss_classical = ss_target.classical()

        assert ss_classical == SBDB_DATA[target_name]
Beispiel #9
0
def orbit_from_spk_id(spk_id, api_key='DEMO_KEY'):
    """Return :py:class:`~poliastro.twobody.orbit.Orbit` given a SPK-ID.

    Retrieve info from NASA NeoWS API, and therefore
    it only works with NEAs (Near Earth Asteroids).

    Parameters
    ----------
    spk_id : str
        SPK-ID number, which is given to each body by JPL.
    api_key : str
        NASA OPEN APIs key (default: `DEMO_KEY`)

    Returns
    -------
    orbit : ~poliastro.twobody.orbit.Orbit
        NEA orbit.

    """
    payload = {'api_key': api_key}

    response = requests.get(NEOWS_URL + spk_id, params=payload)
    response.raise_for_status()

    orbital_data = response.json()['orbital_data']

    attractor = Sun
    a = float(orbital_data['semi_major_axis']) * u.AU
    ecc = float(orbital_data['eccentricity']) * u.one
    inc = float(orbital_data['inclination']) * u.deg
    raan = float(orbital_data['ascending_node_longitude']) * u.deg
    argp = float(orbital_data['perihelion_argument']) * u.deg
    m = float(orbital_data['mean_anomaly']) * u.deg
    nu = M_to_nu(m.to(u.rad), ecc)
    epoch = Time(float(orbital_data['epoch_osculation']),
                 format='jd',
                 scale='tdb')

    return Orbit.from_classical(attractor, a, ecc, inc, raan, argp, nu, epoch)
Beispiel #10
0
def test_from_sbdb():

    # Dictionary with structure: 'Object': [a, e, i, raan, argp, nu, epoch]
    # Notice JPL provides Mean anomaly, a conversion is needed to obtain nu

    SBDB_DATA = {
        "Ceres": (
            2.76916515450648 * u.AU,
            0.07600902910070946 * u.one,
            10.59406704424526 * u.deg,
            80.30553156826473 * u.deg,
            73.597694115971 * u.deg,
            M_to_nu(77.37209588584763 * u.deg, 0.07600902910070946 * u.one),
        )
    }

    for target_name in SBDB_DATA.keys():

        ss_target = Orbit.from_sbdb(target_name)
        ss_classical = ss_target.classical()

        assert ss_classical == SBDB_DATA[target_name]
Beispiel #11
0
import numpy as np
from astropy import units as u
from poliastro.twobody import Orbit
from poliastro.twobody.angles import M_to_nu
from poliastro.bodies import Sun

MU69_ecc = 0.05046617 * u.one  # Eccentricity
MU69_i = 2.44996247 * u.deg  # Inclination
MU69_a = 6676495970 * u.km  # Semimajor axisº
MU69_raan = 159.04395317345 * u.deg  # Right ascension of the ascending node
MU69_argp = 181.14813924539 * u.deg  # Argument of perihelion
MU69_M = 310.91947579009 * u.deg  # Mean anomaly
MU69_nu = M_to_nu(MU69_M, MU69_ecc)  # True anomaly

orbit = Orbit.from_classical(Sun, MU69_a, MU69_ecc, MU69_i, MU69_raan,
                             MU69_argp, MU69_nu)