예제 #1
0
def test_orbit_wrong_dimensions_fails():
    bad_r = [[1000, 0, 0]] * u.km
    bad_v = [[[0, 10, 0]]] * u.km / u.s

    with pytest.raises(ValueError) as excinfo:
        Orbit.from_vectors(Earth, bad_r, bad_v)
    assert "ValueError: Vectors must have dimension 1, got 2 and 3" in excinfo.exconly()
예제 #2
0
def test_from_horizons_raise_valueerror():
    with pytest.raises(ValueError) as exep:
        Orbit.from_horizons(name="Dummy")
    assert (
        "ValueError: Unknown target (Dummy). Maybe try different id_type?"
        in exep.exconly()
    )
예제 #3
0
def test_frozen_orbit_altitude():
    with pytest.raises(ValueError) as excinfo:
        Orbit.frozen(Earth, -1 * u.m)
    assert excinfo.type == ValueError
    assert (
        str(excinfo.value)
        == "The semimajor axis may not be smaller that Earth's radius"
    )
예제 #4
0
def test_frozen_orbit_non_spherical_arguments():
    with pytest.raises(AttributeError) as excinfo:
        Orbit.frozen(Jupiter, 1 * u.m)
    assert excinfo.type == AttributeError
    assert (
        str(excinfo.value)
        == "Attractor Jupiter has not spherical harmonics implemented"
    )
예제 #5
0
def test_geostationary_input(attractor):
    with pytest.raises(ValueError) as excinfo:
        Orbit.geostationary(attractor=attractor)

    assert (
        "ValueError: At least one among angular_velocity or period must be passed"
        in excinfo.exconly()
    )
예제 #6
0
def test_geostationary_non_existence_condition(attractor, period, hill_radius):
    with pytest.raises(ValueError) as excinfo:
        Orbit.geostationary(attractor=attractor, period=period, hill_radius=hill_radius)

    assert (
        "Geostationary orbit for the given parameters doesn't exist"
        in excinfo.exconly()
    )
예제 #7
0
def test_from_sbdb_raise_valueerror():
    with pytest.raises(ValueError) as excinfo:
        Orbit.from_sbdb(name="Halley")

    assert (
        str(excinfo.value)
        == "2 different objects found: \n2688 Halley (1982 HG1)\n1P/Halley\n"
    )
예제 #8
0
def test_from_ephem_raises_warning_if_time_is_not_tdb_with_proper_time(recwarn):
    body = Earth
    epoch = Time("2017-09-29 07:31:26", scale="utc")
    expected_epoch_string = "2017-09-29 07:32:35.182"  # epoch.tdb.value

    Orbit.from_body_ephem(body, epoch)

    w = recwarn.pop(TimeScaleWarning)
    assert expected_epoch_string in str(w.message)
예제 #9
0
def test_bad_hyperbolic_raises_exception():
    bad_a = 1.0 * u.AU
    ecc = 1.5 * u.one
    _inc = 100 * u.deg  # Unused inclination
    _a = 1.0 * u.deg  # Unused angle
    _body = Sun  # Unused body
    with pytest.raises(ValueError) as excinfo:
        Orbit.from_classical(_body, bad_a, ecc, _inc, _a, _a, _a)
    assert "Hyperbolic orbits have negative semimajor axis" in excinfo.exconly()
예제 #10
0
def test_state_raises_unitserror_if_rv_units_are_wrong():
    _d = [1.0, 0.0, 0.0] * u.AU
    wrong_v = [0.0, 1.0e-6, 0.0] * u.AU
    with pytest.raises(u.UnitsError) as excinfo:
        Orbit.from_vectors(Sun, _d, wrong_v)
    assert (
        "UnitsError: Argument 'v' to function 'from_vectors' must be in units convertible to 'm / s'."
        in excinfo.exconly()
    )
예제 #11
0
def test_plot_trajectory_sets_label():
    op = OrbitPlotter()
    earth = Orbit.from_body_ephem(Earth)
    mars = Orbit.from_body_ephem(Mars)
    trajectory = earth.sample()
    op.plot(mars, label="Mars")
    op.plot_trajectory(trajectory, label="Earth")
    legend = plt.gca().get_legend()
    assert legend.get_texts()[1].get_text() == "Earth"
예제 #12
0
def test_bad_inclination_raises_exception():
    _d = 1.0 * u.AU  # Unused distance
    _ = 0.5 * u.one  # Unused dimensionless value
    _a = 1.0 * u.deg  # Unused angle
    _body = Sun  # Unused body
    bad_inc = 200 * u.deg
    with pytest.raises(ValueError) as excinfo:
        Orbit.from_classical(_body, _d, _, bad_inc, _a, _a, _a)
    assert (
        "ValueError: Inclination must be between 0 and 180 degrees" in excinfo.exconly()
    )
예제 #13
0
def test_state_raises_unitserror_if_elements_units_are_wrong():
    _d = 1.0 * u.AU  # Unused distance
    _ = 0.5 * u.one  # Unused dimensionless value
    _a = 1.0 * u.deg  # Unused angle
    wrong_angle = 1.0 * u.AU
    with pytest.raises(u.UnitsError) as excinfo:
        Orbit.from_classical(Sun, _d, _, _a, _a, _a, wrong_angle)
    assert (
        "UnitsError: Argument 'nu' to function 'from_classical' must be in units convertible to 'rad'."
        in excinfo.exconly()
    )
예제 #14
0
def test_parabolic_elements_fail_early():
    attractor = Earth
    ecc = 1.0 * u.one
    _d = 1.0 * u.AU  # Unused distance
    _a = 1.0 * u.deg  # Unused angle
    with pytest.raises(ValueError) as excinfo:
        Orbit.from_classical(attractor, _d, ecc, _a, _a, _a, _a)
    assert (
        "ValueError: For parabolic orbits use Orbit.parabolic instead"
        in excinfo.exconly()
    )
예제 #15
0
def test_from_coord_fails_if_no_time_differential():
    pos = [30000, 0, 0] * u.km
    cartrep = CartesianRepresentation(*pos)

    # Method fails if coordinate instance doesn't contain a differential with
    # respect to time
    with pytest.raises(ValueError) as excinfo:
        Orbit.from_coords(Earth, SkyCoord(cartrep))
    assert (
        "ValueError: Coordinate instance doesn't have a differential with respect to time"
        in excinfo.exconly()
    )
예제 #16
0
def test_from_coord_fails_for_multiple_positions(obstime):
    cartdiff = CartesianDifferential(
        [[0, 1, 0], [-0.1, 0.9, 0]] * u.km / u.s, xyz_axis=1
    )
    cartrep = CartesianRepresentation(
        [[1, 0, 0], [0.9, 0.1, 0]] * u.km, differentials=cartdiff, xyz_axis=1
    )
    coords = GCRS(cartrep, representation_type=CartesianRepresentation, obstime=obstime)

    with pytest.raises(ValueError) as excinfo:
        Orbit.from_coords(Earth, coords)
    assert (
        "ValueError: Coordinate instance must represents exactly 1 position, found: 2"
        in excinfo.exconly()
    )
예제 #17
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
예제 #18
0
def test_inertial_body_centered_to_pqw():
    molniya_r_peri, molniya_v_peri = coordinates.inertial_body_centered_to_pqw(molniya.r, molniya.v, bodies.Earth)

    molniya_peri = Orbit.from_vectors(bodies.Earth, molniya_r_peri, molniya_v_peri, molniya.epoch)

    assert_quantity_allclose(molniya_peri.e_vec[-2:], [0, 0], atol=1e-12)
    assert_quantity_allclose(norm(molniya_peri.e_vec), norm(molniya.e_vec))
예제 #19
0
def test_perifocal_points_to_perigee():
    _d = 1.0 * u.AU  # Unused distance
    _ = 0.5 * u.one  # Unused dimensionless value
    _a = 1.0 * u.deg  # Unused angle
    ss = Orbit.from_classical(Sun, _d, _, _a, _a, _a, _a)
    p, _, _ = ss.pqw()
    assert_allclose(p, ss.e_vec / ss.ecc)
예제 #20
0
def transform(orbit, frame_orig, frame_dest):
    """Transforms Orbit from one frame to another.

    Parameters
    ----------
    orbit : ~poliastro.bodies.Orbit
        Orbit to transform
    frame_orig : ~astropy.coordinates.BaseCoordinateFrame
        Initial frame
    frame_dest : ~astropy.coordinates.BaseCoordinateFrame
        Final frame

    Returns
    -------
    orbit: ~poliastro.bodies.Orbit
        Orbit in the new frame

    """

    orbit_orig = frame_orig(x=orbit.r[0], y=orbit.r[1], z=orbit.r[2],
                            v_x=orbit.v[0], v_y=orbit.v[1], v_z=orbit.v[2],
                            representation=CartesianRepresentation,
                            differential_type=CartesianDifferential)

    orbit_dest = orbit_orig.transform_to(frame_dest(obstime=orbit.epoch))
    orbit_dest.representation = CartesianRepresentation

    return Orbit.from_vectors(orbit.attractor,
                              orbit_dest.data.xyz,
                              orbit_dest.data.differentials['s'].d_xyz,
                              epoch=orbit.epoch)
예제 #21
0
def plot_solar_system(outer=True, epoch=None):
    """
    Plots the whole solar system in one single call.

    .. versionadded:: 0.9.0

    Parameters
    ------------
    outer : bool, optional
        Whether to print the outer Solar System, default to True.
    epoch: ~astropy.time.Time, optional
        Epoch value of the plot, default to J2000.
    """
    bodies = [Mercury, Venus, Earth, Mars]
    if outer:
        bodies.extend([Jupiter, Saturn, Uranus, Neptune])

    op = OrbitPlotter()
    for body in bodies:
        orb = Orbit.from_body_ephem(body, epoch)
        op.plot(orb, label=str(body))

    # Sets frame to the orbit of the Earth by default
    # TODO: Wait until https://github.com/poliastro/poliastro/issues/316
    # op.set_frame(*Orbit.from_body_ephem(Earth, epoch).pqw())

    return op
예제 #22
0
def test_parabolic_has_proper_eccentricity():
    attractor = Earth
    _d = 1.0 * u.AU  # Unused distance
    _a = 1.0 * u.deg  # Unused angle
    expected_ecc = 1.0 * u.one
    ss = Orbit.parabolic(attractor, _d, _a, _a, _a, _a)
    assert_allclose(ss.ecc, expected_ecc)
예제 #23
0
def test_orbit_representation():
    ss = Orbit.circular(
        Earth, 600 * u.km, 20 * u.deg, epoch=Time("2018-09-08 09:04:00", scale="tdb")
    )
    expected_str = "6978 x 6978 km x 20.0 deg (GCRS) orbit around Earth (\u2641) at epoch 2018-09-08 09:04:00.000 (TDB)"

    assert str(ss) == repr(ss) == expected_str
예제 #24
0
def test_orbit_accepts_ecliptic_plane():
    r = [1e09, -4e09, -1e09] * u.km
    v = [5e00, -1e01, -4e00] * u.km / u.s

    ss = Orbit.from_vectors(Sun, r, v, plane=Planes.EARTH_ECLIPTIC)

    assert ss.frame.is_equivalent_frame(HeliocentricEclipticJ2000(obstime=J2000))
예제 #25
0
def test_orbit_plot_static_3d():
    # Data from Curtis, example 4.3
    r = [-6045, -3490, 2500] * u.km
    v = [-3.457, 6.618, 2.533] * u.km / u.s
    ss = Orbit.from_vectors(Earth, r, v)
    with pytest.raises(ValueError, match="static and use_3d cannot be true"):
        ss.plot(static=True, use_3d=True)
예제 #26
0
def test_sample_numpoints():
    _d = 1.0 * u.AU  # Unused distance
    _ = 0.5 * u.one  # Unused dimensionless value
    _a = 1.0 * u.deg  # Unused angle
    _body = Sun  # Unused body
    ss = Orbit.from_classical(_body, _d, _, _a, _a, _a, _a)
    positions = ss.sample(values=50)
    assert len(positions) == 50
예제 #27
0
def test_geostationary_creation_with_Hill_radius(
    attractor, period, hill_radius, expected_a
):
    ss = Orbit.geostationary(
        attractor=attractor, period=period, hill_radius=hill_radius
    )
    assert_quantity_allclose(ss.a, expected_a, rtol=1.0e-7)
    assert_quantity_allclose(ss.period, period, rtol=1.0e-7)
예제 #28
0
def test_default_time_for_new_state():
    _d = 1.0 * u.AU  # Unused distance
    _ = 0.5 * u.one  # Unused dimensionless value
    _a = 1.0 * u.deg  # Unused angle
    _body = Sun  # Unused body
    expected_epoch = J2000
    ss = Orbit.from_classical(_body, _d, _, _a, _a, _a, _a)
    assert ss.epoch == expected_epoch
예제 #29
0
def test_show_calls_prepare_plot(mock_prepare_plot, mock_iplot):
    m = OrbitPlotter2D()
    earth = Orbit.from_body_ephem(Earth)
    m.plot(orbit=earth, label="Obj")
    m.show()

    assert mock_iplot.call_count == 1
    mock_prepare_plot.assert_called_once_with()
예제 #30
0
def test_orbit_no_frame_representation():
    date_launch = Time("2011-11-26 15:02", scale="utc")
    r = [61445.76498656, 24827.93010168, 0.0] * u.km
    v = [-0.42581645, -0.18867869, 0.0] * u.km / u.s
    ss = Orbit.from_vectors(Moon, r, v, date_launch)
    expected_str = "106 x -142299 km x 180.0 deg orbit around Moon (\u263E) at epoch 2011-11-26 15:02:00.000 (UTC)"

    assert str(ss) == repr(ss) == expected_str
예제 #31
0
def orbit_from_orbit(init_orbit, part_of_period, alfa_init):  # alfa in degrees
    period_init = init_orbit.period
    t_maneuver = part_of_period * period_init
    mean_motion_init = init_orbit.n
    anomaly_init = (alfa_init / 180 * np.pi +
                    mean_motion_init * t_maneuver) * u.rad

    orbit_dprt = init_orbit.propagate_to_anomaly(anomaly_init)

    r = orbit_dprt.r
    v = orbit_dprt.v

    date_arrival = time.Time((DATA_LAUNCH.unix + t_maneuver), format='unix')

    orbit = Orbit.from_vectors(Earth, r, v, epoch=date_arrival)
    return orbit
예제 #32
0
def test_orbit_represent_as_produces_correct_data():
    r = [1e09, -4e09, -1e09] * u.km
    v = [5e00, -1e01, -4e00] * u.km / u.s

    ss = Orbit.from_vectors(Sun, r, v)

    expected_result = CartesianRepresentation(
        *r, differentials=CartesianDifferential(*v))

    result = ss.represent_as(CartesianRepresentation)

    # We can't directly compare the objects, see
    # https://github.com/astropy/astropy/issues/7793
    assert (result.xyz == expected_result.xyz).all()
    assert (result.differentials["s"].d_xyz ==
            expected_result.differentials["s"].d_xyz).all()
예제 #33
0
def test_expected_angular_momentum():
    # Example from Curtis
    expected_ang_mag = 72472 * u.km**2

    attractor = Earth

    _a = 1.0 * u.deg  # Unused angle
    a = 15_300 * u.km
    ecc = 0.37255 * u.one
    nu = 120 * u.deg

    orbit = Orbit.from_classical(attractor, a, ecc, _a, _a, _a, nu)
    orbit_h_mag = orbit.h_mag

    assert_quantity_allclose(orbit_h_mag.value,
                             expected_ang_mag.value,
                             rtol=1e-2)
예제 #34
0
def test_convert_from_rv_to_coe():
    # Data from Vallado, example 2.6
    attractor = Earth
    p = 11067.790 * u.km
    ecc = 0.83285 * u.one
    inc = 87.87 * u.deg
    raan = 227.89 * u.deg
    argp = 53.38 * u.deg
    nu = 92.335 * u.deg
    expected_r = [6525.344, 6861.535, 6449.125] * u.km
    expected_v = [4.902276, 5.533124, -1.975709] * u.km / u.s

    r, v = Orbit.from_classical(attractor, p / (1 - ecc**2), ecc, inc, raan,
                                argp, nu).rv()

    assert_quantity_allclose(r, expected_r, rtol=1e-5)
    assert_quantity_allclose(v, expected_v, rtol=1e-5)
예제 #35
0
def test_expected_mean_anomaly():
    # Example from Curtis
    expected_mean_anomaly = 77.93 * u.deg

    attractor = Earth

    _a = 1.0 * u.deg  # Unused angle
    a = 15_300 * u.km
    ecc = 0.37255 * u.one
    nu = 120 * u.deg

    orbit = Orbit.from_classical(attractor, a, ecc, _a, _a, _a, nu)
    orbit_M = orbit.M

    assert_quantity_allclose(orbit_M.value,
                             expected_mean_anomaly.value,
                             rtol=1e-2)
예제 #36
0
def test_orbit_creation_using_skycoord(attractor):
    vel = [0, 2, 0] * u.km / u.s
    cartdiff = CartesianDifferential(*vel)

    pos = [30_000, 0, 0] * u.km
    cartrep = CartesianRepresentation(*pos, differentials=cartdiff)

    coord = SkyCoord(cartrep, frame="icrs")
    o = Orbit.from_coords(attractor, coord)

    inertial_frame_at_body_centre = get_frame(
        attractor, Planes.EARTH_EQUATOR, obstime=coord.obstime
    )

    coord_transformed_to_irf = coord.transform_to(inertial_frame_at_body_centre)
    pos_transformed_to_irf = coord_transformed_to_irf.cartesian.xyz
    vel_transformed_to_irf = coord_transformed_to_irf.cartesian.differentials["s"].d_xyz

    assert (o.r == pos_transformed_to_irf).all()
    assert (o.v == vel_transformed_to_irf).all()
예제 #37
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,
            86.01851107780747 * u.deg,
        )
    }

    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]
예제 #38
0
    def from_vectors(cls, r, v):
        """Return EarthSatellite with the `Orbit` from position and velocity vectors.

        Parameters
        ----------
        r : ~astropy.units.Quantity
            Position vector wrt attractor center.
        v : ~astropy.units.Quantity
            Velocity vector.

        Returns
        -------
        EarthSatellite
            New EarthSatellite with the'Orbit' position and velocity vectors.


        """

        orbit = Orbit.from_vectors(Earth, r, v)
        return cls(orbit)
예제 #39
0
def test_apply_maneuver_returns_intermediate_states_if_true():
    _d = 1.0 * u.AU  # Unused distance
    _ = 0.5 * u.one  # Unused dimensionless value
    _a = 1.0 * u.deg  # Unused angle
    ss = Orbit.from_classical(attractor=Sun,
                              a=_d,
                              ecc=_,
                              inc=_a,
                              raan=_a,
                              argp=_a,
                              nu=_a)
    dt1 = 0.5 * u.h
    dv1 = [5, 0, 10] * u.km / u.s
    dt2 = 0.5 * u.h
    dv2 = [0, 5, 10] * u.km / u.s

    states = ss.apply_maneuver([(dt1, dv1), (dt2, dv2)], intermediate=True)

    assert len(states) == 2
    assert states[-1].epoch == ss.epoch + dt1 + dt2
예제 #40
0
def test_orbit_creation_using_frame_obj(attractor, frame, obstime):
    vel = [0, 2, 0] * u.km / u.s
    cartdiff = CartesianDifferential(*vel)

    pos = [30_000, 0, 0] * u.km
    cartrep = CartesianRepresentation(*pos, differentials=cartdiff)

    coord = frame(cartrep, obstime=obstime)
    o = Orbit.from_coords(attractor, coord)

    inertial_frame_at_body_centre = get_frame(
        attractor, Planes.EARTH_EQUATOR, obstime=coord.obstime
    )

    coord_transformed_to_irf = coord.transform_to(inertial_frame_at_body_centre)

    pos_transformed_to_irf = coord_transformed_to_irf.cartesian.xyz
    vel_transformed_to_irf = coord_transformed_to_irf.cartesian.differentials["s"].d_xyz

    assert_quantity_allclose(o.r, pos_transformed_to_irf, atol=1e-5 * u.km)
    assert_quantity_allclose(o.v, vel_transformed_to_irf, atol=1e-5 * u.km / u.s)
예제 #41
0
def test_expected_last_perifocal_passage():
    # Example from Curtis
    expected_t_p = 4077 * u.s

    attractor = Earth

    _a = 1.0 * u.deg  # Unused angle
    a = 15_300 * u.km
    ecc = 0.37255 * u.one
    nu = 120 * u.deg

    orbit = Orbit.from_classical(attractor=attractor,
                                 a=a,
                                 ecc=ecc,
                                 inc=_a,
                                 raan=_a,
                                 argp=_a,
                                 nu=nu)
    orbit_t_p = orbit.t_p

    assert_quantity_allclose(orbit_t_p, expected_t_p, rtol=1e-2)
예제 #42
0
def test_expected_mean_anomaly():
    # Example from Curtis
    expected_mean_anomaly = 77.93 * u.deg

    attractor = Earth

    _a = 1.0 * u.deg  # Unused angle
    a = 15_300 * u.km
    ecc = 0.37255 * u.one
    nu = 120 * u.deg

    orbit = Orbit.from_classical(attractor=attractor,
                                 a=a,
                                 ecc=ecc,
                                 inc=_a,
                                 raan=_a,
                                 argp=_a,
                                 nu=nu)
    orbit_M = E_to_M(nu_to_E(orbit.nu, orbit.ecc), orbit.ecc)

    assert_quantity_allclose(orbit_M, expected_mean_anomaly, rtol=1e-2)
예제 #43
0
def test_from_orbit_has_desired_properties(method, rtol):
    epochs = Time(
        [
            "2020-02-01 12:00:00",
            "2020-02-13 12:00:00",
            "2020-03-04 12:00:00",
            "2020-03-17 12:00:00",
        ]
    )
    expected_coordinates = CartesianRepresentation(
        [
            (336.77109079, -1447.38211842, -743.72094119),
            (-1133.43957703, 449.41297342, 3129.10416554),
            (201.42480053, -1978.64139325, -287.25776291),
            (-1084.94556884, -1713.5357774, 3298.72284309),
        ]
        * u.km,
        xyz_axis=1,
        differentials=CartesianDifferential(
            [
                (-2.68502706, -14.85798508, 9.66683585),
                (1.36841306, 7.30080155, -4.88822441),
                (-3.46999908, -10.04899184, 11.19715233),
                (-1.46069855, 5.88696886, 3.28112281),
            ]
            * (u.km / u.s),
            xyz_axis=1,
        ),
    )

    r = [-1000, -2000, 3100] * u.km
    v = [-1.836, 5.218, 4.433] * u.km / u.s
    orb = Orbit.from_vectors(Earth, r, v)

    unused_plane = Planes.EARTH_EQUATOR
    ephem = Ephem.from_orbit(orbit=orb, epochs=epochs, plane=unused_plane)
    coordinates = ephem.sample()

    assert ephem.epochs is epochs
    assert_coordinates_allclose(coordinates, expected_coordinates, rtol=rtol)
예제 #44
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)
예제 #45
0
def transform(orbit, frame_orig, frame_dest):
    """Transforms Orbit from one frame to another.

    Parameters
    ----------
    orbit : ~poliastro.bodies.Orbit
        Orbit to transform
    frame_orig : ~astropy.coordinates.BaseCoordinateFrame
        Initial frame
    frame_dest : ~astropy.coordinates.BaseCoordinateFrame
        Final frame

    Returns
    -------
    orbit: ~poliastro.bodies.Orbit
        Orbit in the new frame

    """

    orbit_orig = frame_orig(
        x=orbit.r[0],
        y=orbit.r[1],
        z=orbit.r[2],
        v_x=orbit.v[0],
        v_y=orbit.v[1],
        v_z=orbit.v[2],
        representation=CartesianRepresentation,
        differential_type=CartesianDifferential,
    )

    orbit_dest = orbit_orig.transform_to(frame_dest(obstime=orbit.epoch))
    orbit_dest.representation = CartesianRepresentation

    return Orbit.from_vectors(
        orbit.attractor,
        orbit_dest.data.xyz,
        orbit_dest.data.differentials["s"].d_xyz,
        epoch=orbit.epoch,
    )
예제 #46
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.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]
예제 #47
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
    epoch = Time(body_data["EPOCH"].item(), format="jd", scale="tdb")

    # NOTE: It is unclear how this conversion should happen,
    # see https://ssd-api.jpl.nasa.gov/doc/sbdb.html
    if ecc < 1:
        M = (M + np.pi * u.rad) % (2 * np.pi * u.rad) - np.pi * u.rad
        nu = E_to_nu(M_to_E(M, ecc), ecc)
    elif ecc == 1:
        nu = D_to_nu(M_to_D(M))
    else:
        nu = F_to_nu(M_to_F(M, ecc), ecc)

    orbit = Orbit.from_classical(Sun, a, ecc, inc, raan, argp, nu, epoch)
    orbit._frame = HeliocentricEclipticJ2000(obstime=epoch)
    return orbit
예제 #48
0
def test_propagate_instance():
    tof = 1.0 * u.min
    ss0 = Orbit.from_classical(
        Earth,
        1000 * u.km,
        0.75 * u.one,
        63.4 * u.deg,
        0 * u.deg,
        270 * u.deg,
        80 * u.deg,
    )
    C_D = 2.2 * u.one  # dimentionless (any value would do)
    A = ((np.pi / 4.0) * (u.m**2)).to(u.km**2)
    m = 100 * u.kg
    spacecraft = Spacecraft(A, C_D, m)
    earth_satellite = EarthSatellite(ss0, spacecraft)
    orbit_with_j2 = earth_satellite.propagate(tof=tof, gravity=EarthGravity.J2)
    orbit_without_perturbation = earth_satellite.propagate(tof)
    orbit_with_atmosphere_and_j2 = earth_satellite.propagate(
        tof=tof, gravity=EarthGravity.J2, atmosphere=COESA76())
    assert isinstance(orbit_with_j2, EarthSatellite)
    assert isinstance(orbit_with_atmosphere_and_j2, EarthSatellite)
    assert isinstance(orbit_without_perturbation, EarthSatellite)
예제 #49
0
def test_convert_from_coe_to_rv():
    # Data from Vallado, example 2.5
    attractor = Earth
    r = [6524.384, 6862.875, 6448.296] * u.km
    v = [4.901327, 5.533756, -1.976341] * u.km / u.s

    expected_p = 11067.79 * u.km
    expected_ecc = 0.832853 * u.one
    expected_inc = 87.870 * u.deg
    expected_raan = 227.89 * u.deg
    expected_argp = 53.38 * u.deg
    expected_nu = 92.335 * u.deg

    ss = Orbit.from_vectors(attractor, r, v)

    _, ecc, inc, raan, argp, nu = ss.classical()
    p = ss.p

    assert_quantity_allclose(p, expected_p, rtol=1e-4)
    assert_quantity_allclose(ecc, expected_ecc, rtol=1e-4)
    assert_quantity_allclose(inc, expected_inc, rtol=1e-4)
    assert_quantity_allclose(raan, expected_raan, rtol=1e-4)
    assert_quantity_allclose(argp, expected_argp, rtol=1e-4)
    assert_quantity_allclose(nu, expected_nu, rtol=1e-4)
예제 #50
0
def test_propagate_instance():
    tof = 1.0 * u.min
    ss0 = Orbit.from_classical(
        attractor=Earth,
        a=1000 * u.km,
        ecc=0.75 * u.one,
        inc=63.4 * u.deg,
        raan=0 * u.deg,
        argp=270 * u.deg,
        nu=80 * u.deg,
    )
    C_D = 2.2 * u.one  # Dimensionless (any value would do)
    A = ((np.pi / 4.0) * (u.m**2)).to(u.km**2)
    m = 100 * u.kg
    spacecraft = Spacecraft(A, C_D, m)
    earth_satellite = EarthSatellite(ss0, spacecraft)
    orbit_with_j2 = earth_satellite.propagate(tof=tof, gravity=EarthGravity.J2)
    orbit_without_perturbation = earth_satellite.propagate(tof)
    # orbit_with_atmosphere_and_j2 = earth_satellite.propagate(
    #     tof=tof, gravity=EarthGravity.J2, atmosphere=COESA76()
    # )
    assert isinstance(orbit_with_j2, EarthSatellite)
    # assert isinstance(orbit_with_atmosphere_and_j2, EarthSatellite)
    assert isinstance(orbit_without_perturbation, EarthSatellite)
예제 #51
0
def test_from_sbdb_raise_valueerror():
    with pytest.raises(ValueError) as excinfo:
        Orbit.from_sbdb(name="Halley")

    assert (str(excinfo.value) ==
            "2 different objects found: \n2688 Halley (1982 HG1)\n1P/Halley\n")
예제 #52
0
def test_arglat_within_range():
    r = [3539.08827417, 5310.19903462, 3066.31301457] * u.km
    v = [-6.49780849, 3.24910291, 1.87521413] * u.km / u.s
    ss = Orbit.from_vectors(Earth, r, v)
    assert 0 * u.deg <= ss.arglat <= 360 * u.deg
예제 #53
0
def test_geostationary_creation_from_period(attractor, period, expected_a):
    ss = Orbit.geostationary(attractor=attractor, period=period)
    assert_quantity_allclose(ss.a, expected_a, rtol=1.0e-7)
    assert_quantity_allclose(ss.period, period, rtol=1.0e-7)
예제 #54
0
def test_plane_is_set_in_horizons():
    plane = Planes.EARTH_ECLIPTIC
    ss = Orbit.from_horizons(name="Ceres", plane=plane)
    assert ss.plane == plane
예제 #55
0
def test_from_horizons_raise_valueerror():
    with pytest.raises(ValueError) as exep:
        Orbit.from_horizons(name="Dummy")
    assert ("ValueError: Unknown target (Dummy). Maybe try different id_type?"
            in exep.exconly())
예제 #56
0
def test_orbit_from_ephem_is_in_icrs_frame(body):
    ss = Orbit.from_body_ephem(body)

    assert ss.frame.is_equivalent_frame(ICRS())
예제 #57
0
def test_frozen_orbit_altitude():
    with pytest.raises(ValueError) as excinfo:
        Orbit.frozen(Earth, -1 * u.m)
    assert excinfo.type == ValueError
    assert (str(excinfo.value) ==
            "The semimajor axis may not be smaller that Earth's radius")
예제 #58
0
def test_frozen_orbit_non_spherical_arguments():
    with pytest.raises(AttributeError) as excinfo:
        Orbit.frozen(Jupiter, 1 * u.m)
    assert excinfo.type == AttributeError
    assert (str(excinfo.value) ==
            "Attractor Jupiter has not spherical harmonics implemented")
예제 #59
0
def test_frozen_orbit_venus_special_case():
    with pytest.raises(NotImplementedError) as excinfo:
        Orbit.frozen(Venus, 1 * u.m)
    assert excinfo.type == NotImplementedError
    assert str(excinfo.value) == "This has not been implemented for Venus"
예제 #60
0
def test_frozen_orbit_non_critical_inclination():
    orbit = Orbit.frozen(Earth, 1e3 * u.km,
                         inc=0 * u.deg)  # Non-critical value
    assert orbit.argp in [np.pi / 2, 3 * np.pi / 2] * u.rad