Exemple #1
0
def get_horizons_coord(body, time='now', id_type='majorbody', *, include_velocity=False):
    """
    Queries JPL HORIZONS and returns a `~astropy.coordinates.SkyCoord` for the location of a
    solar-system body at a specified time.  This location is the instantaneous or "true" location,
    and is not corrected for light travel time or observer motion.

    .. note::
        This function requires the Astroquery package to be installed and
        requires an Internet connection.

    Parameters
    ----------
    body : `str`
        The solar-system body for which to calculate positions.  One can also use the search form
        linked below to find valid names or ID numbers.
    id_type : `str`
        If 'majorbody', search by name for planets, satellites, or other major bodies.
        If 'smallbody', search by name for asteroids or comets.
        If 'id', search by ID number.
    time : {parse_time_types}, `dict`
        Time to use in a parse_time-compatible format.

        Alternatively, this can be a dictionary defining a range of times and
        dates; the range dictionary has to be of the form
        {{'start': start_time, 'stop': stop_time, 'step':’n[y|d|m|s]’}}.
        ``start_time`` and ``stop_time`` must be in a parse_time-compatible format,
        and are interpreted as UTC time. ``step`` must be a string with either a
        number and interval length (e.g. for every 10 seconds, ``'10s'``), or a
        plain number for a number of evenly spaced intervals. For more information
        see the docstring of `astroquery.jplhorizons.HorizonsClass`.

    Keyword Arguments
    -----------------
    include_velocity : `bool`
        If True, include the body's velocity in the output coordinate.  Defaults to False.

    Returns
    -------
    `~astropy.coordinates.SkyCoord`
        Location of the solar-system body

    Notes
    -----
    Be aware that there can be discrepancies between the coordinates returned by JPL HORIZONS,
    the coordinates reported in mission data files, and the coordinates returned by
    `~sunpy.coordinates.get_body_heliographic_stonyhurst`.

    References
    ----------
    * `JPL HORIZONS <https://ssd.jpl.nasa.gov/?horizons>`_
    * `JPL HORIZONS form to search bodies <https://ssd.jpl.nasa.gov/horizons.cgi?s_target=1#top>`_
    * `Astroquery <https://astroquery.readthedocs.io/en/latest/>`_

    Examples
    --------
    >>> from sunpy.coordinates.ephemeris import get_horizons_coord

    Query the location of Venus

    >>> get_horizons_coord('Venus barycenter', '2001-02-03 04:05:06')  # doctest: +REMOTE_DATA
    INFO: Obtained JPL HORIZONS location for Venus Barycenter (2) [sunpy.coordinates.ephemeris]
    <SkyCoord (HeliographicStonyhurst: obstime=2001-02-03T04:05:06.000, rsun=695700.0 km): (lon, lat, radius) in (deg, deg, AU)
        (-33.93155836, -1.64998443, 0.71915147)>

    Query the location of the SDO spacecraft

    >>> get_horizons_coord('SDO', '2011-11-11 11:11:11')  # doctest: +REMOTE_DATA
    INFO: Obtained JPL HORIZONS location for Solar Dynamics Observatory (spac [sunpy.coordinates.ephemeris]
    <SkyCoord (HeliographicStonyhurst: obstime=2011-11-11T11:11:11.000, rsun=695700.0 km): (lon, lat, radius) in (deg, deg, AU)
        (0.01019118, 3.29640728, 0.99011042)>

    Query the location of the SOHO spacecraft via its ID number (-21)

    >>> get_horizons_coord(-21, '2004-05-06 11:22:33', 'id')  # doctest: +REMOTE_DATA
    INFO: Obtained JPL HORIZONS location for SOHO (spacecraft) (-21) [sunpy.coordinates.ephemeris]
    <SkyCoord (HeliographicStonyhurst: obstime=2004-05-06T11:22:33.000, rsun=695700.0 km): (lon, lat, radius) in (deg, deg, AU)
        (0.25234902, -3.55863633, 0.99923086)>

    Query the location and velocity of the asteroid Juno

    >>> get_horizons_coord('Juno', '1995-07-18 07:17', 'smallbody', include_velocity=True)  # doctest: +REMOTE_DATA
    INFO: Obtained JPL HORIZONS location for 3 Juno (A804 RA) [sunpy.coordinates.ephemeris]
    <SkyCoord (HeliographicStonyhurst: obstime=1995-07-18T07:17:00.000, rsun=695700.0 km): (lon, lat, radius) in (deg, deg, AU)
        (-25.16107532, 14.59098438, 3.17667664)
     (d_lon, d_lat, d_radius) in (arcsec / s, arcsec / s, km / s)
        (-0.03306548, 0.00052415, -2.66709222)>

    Query the location of Solar Orbiter at a set of 12 regularly sampled times

    >>> get_horizons_coord('Solar Orbiter',
    ...                    time={{'start': '2020-12-01',
    ...                           'stop': '2020-12-02',
    ...                           'step': '12'}})  # doctest: +REMOTE_DATA
    INFO: Obtained JPL HORIZONS location for Solar Orbiter (spacecraft) (-144 [sunpy.coordinates.ephemeris]
    ...
    """
    if isinstance(time, dict):
        if set(time.keys()) != set(['start', 'stop', 'step']):
            raise ValueError('time dictionary must have the keys ["start", "stop", "step"]')
        epochs = time
        jpl_fmt = '%Y-%m-%d %H:%M:%S'
        epochs['start'] = parse_time(epochs['start']).tdb.strftime(jpl_fmt)
        epochs['stop'] = parse_time(epochs['stop']).tdb.strftime(jpl_fmt)
    else:
        obstime = parse_time(time)
        array_time = np.reshape(obstime, (-1,))  # Convert to an array, even if scalar
        epochs = array_time.tdb.jd.tolist()  # Time must be provided in JD TDB

    # Import here so that astroquery is not a module-level dependency
    from astroquery.jplhorizons import Horizons
    query = Horizons(id=body, id_type=id_type,
                     location='500@10',      # Heliocentric (mean ecliptic)
                     epochs=epochs)
    try:
        result = query.vectors()
    except Exception as e:  # Catch and re-raise all exceptions, and also provide query URL if generated
        if query.uri is not None:
            log.error(f"See the raw output from the JPL HORIZONS query at {query.uri}")
        raise e
    finally:
        query._session.close()
    log.info(f"Obtained JPL HORIZONS location for {result[0]['targetname']}")
    log.debug(f"See the raw output from the JPL HORIZONS query at {query.uri}")

    if isinstance(time, dict):
        obstime = parse_time(result['datetime_jd'], format='jd', scale='tdb')
    else:
        # JPL HORIZONS results are sorted by observation time, so this sorting needs to be undone.
        # Calling argsort() on an array returns the sequence of indices of the unsorted list to put the
        # list in order.  Calling argsort() again on the output of argsort() reverses the mapping:
        # the output is the sequence of indices of the sorted list to put that list back in the
        # original unsorted order.
        unsorted_indices = obstime.argsort().argsort()
        result = result[unsorted_indices]

    vector = CartesianRepresentation(result['x'], result['y'], result['z'])
    if include_velocity:
        velocity = CartesianDifferential(result['vx'], result['vy'], result['vz'])
        vector = vector.with_differentials(velocity)
    coord = SkyCoord(vector, frame=HeliocentricEclipticIAU76, obstime=obstime)

    return coord.transform_to(HeliographicStonyhurst).reshape(obstime.shape)
Exemple #2
0
def get_horizons_coord(body,
                       time='now',
                       id_type='majorbody',
                       *,
                       include_velocity=False):
    """
    Queries JPL HORIZONS and returns a `~astropy.coordinates.SkyCoord` for the location of a
    solar-system body at a specified time.  This location is the instantaneous or "true" location,
    and is not corrected for light travel time or observer motion.

    .. note::
        This function requires the Astroquery package to be installed and
        requires an Internet connection.

    Parameters
    ----------
    body : `str`
        The solar-system body for which to calculate positions.  One can also use the search form
        linked below to find valid names or ID numbers.
    id_type : `str`
        If 'majorbody', search by name for planets, satellites, or other major bodies.
        If 'smallbody', search by name for asteroids or comets.
        If 'id', search by ID number.
    time : {parse_time_types}
        Time to use in a parse_time-compatible format

    Keyword Arguments
    -----------------
    include_velocity : `bool`
        If True, include the body's velocity in the output coordinate.  Defaults to False.

    Returns
    -------
    `~astropy.coordinates.SkyCoord`
        Location of the solar-system body

    Notes
    -----
    Be aware that there can be discrepancies between the coordinates returned by JPL HORIZONS,
    the coordinates reported in mission data files, and the coordinates returned by
    `~sunpy.coordinates.get_body_heliographic_stonyhurst`.

    References
    ----------
    * `JPL HORIZONS <https://ssd.jpl.nasa.gov/?horizons>`_
    * `JPL HORIZONS form to search bodies <https://ssd.jpl.nasa.gov/horizons.cgi?s_target=1#top>`_
    * `Astroquery <https://astroquery.readthedocs.io/en/latest/>`_

    Examples
    --------
    >>> from sunpy.coordinates.ephemeris import get_horizons_coord

    Query the location of Venus

    >>> get_horizons_coord('Venus barycenter', '2001-02-03 04:05:06')  # doctest: +REMOTE_DATA
    INFO: Obtained JPL HORIZONS location for Venus Barycenter (2) [sunpy.coordinates.ephemeris]
    <SkyCoord (HeliographicStonyhurst: obstime=2001-02-03T04:05:06.000): (lon, lat, radius) in (deg, deg, AU)
        (-33.93155836, -1.64998443, 0.71915147)>

    Query the location of the SDO spacecraft

    >>> get_horizons_coord('SDO', '2011-11-11 11:11:11')  # doctest: +REMOTE_DATA
    INFO: Obtained JPL HORIZONS location for Solar Dynamics Observatory (spac [sunpy.coordinates.ephemeris]
    <SkyCoord (HeliographicStonyhurst: obstime=2011-11-11T11:11:11.000): (lon, lat, radius) in (deg, deg, AU)
        (0.01019118, 3.29640728, 0.99011042)>

    Query the location of the SOHO spacecraft via its ID number (-21)

    >>> get_horizons_coord(-21, '2004-05-06 11:22:33', 'id')  # doctest: +REMOTE_DATA
    INFO: Obtained JPL HORIZONS location for SOHO (spacecraft) (-21) [sunpy.coordinates.ephemeris]
    <SkyCoord (HeliographicStonyhurst: obstime=2004-05-06T11:22:33.000): (lon, lat, radius) in (deg, deg, AU)
        (0.25234902, -3.55863633, 0.99923086)>

    Query the location and velocity of the asteroid Juno

    >>> get_horizons_coord('Juno', '1995-07-18 07:17', 'smallbody', include_velocity=True)  # doctest: +REMOTE_DATA
    INFO: Obtained JPL HORIZONS location for 3 Juno [sunpy.coordinates.ephemeris]
    <SkyCoord (HeliographicStonyhurst: obstime=1995-07-18T07:17:00.000): (lon, lat, radius) in (deg, deg, AU)
        (-25.16107572, 14.59098456, 3.17667662)
     (d_lon, d_lat, d_radius) in (arcsec / s, arcsec / s, km / s)
        (-0.00514936, -0.00205857, 8.89781348)>
    """
    obstime = parse_time(time)
    array_time = np.reshape(obstime,
                            (-1, ))  # Convert to an array, even if scalar

    # Import here so that astroquery is not a module-level dependency
    from astroquery.jplhorizons import Horizons
    query = Horizons(
        id=body,
        id_type=id_type,
        location='500@10',  # Heliocentric (mean ecliptic)
        epochs=array_time.tdb.jd.tolist())  # Time must be provided in JD TDB
    try:
        result = query.vectors()
    except Exception as e:  # Catch and re-raise all exceptions, and also provide query URL if generated
        if query.uri is not None:
            log.error(
                f"See the raw output from the JPL HORIZONS query at {query.uri}"
            )
        raise e
    finally:
        query._session.close()
    log.info(f"Obtained JPL HORIZONS location for {result[0]['targetname']}")
    log.debug(f"See the raw output from the JPL HORIZONS query at {query.uri}")

    # JPL HORIZONS results are sorted by observation time, so this sorting needs to be undone.
    # Calling argsort() on an array returns the sequence of indices of the unsorted list to put the
    # list in order.  Calling argsort() again on the output of argsort() reverses the mapping:
    # the output is the sequence of indices of the sorted list to put that list back in the
    # original unsorted order.
    unsorted_indices = obstime.argsort().argsort()
    result = result[unsorted_indices]

    vector = CartesianRepresentation(result['x'], result['y'], result['z'])
    if include_velocity:
        velocity = CartesianDifferential(result['vx'], result['vy'],
                                         result['vz'])
        vector = vector.with_differentials(velocity)
    coord = SkyCoord(vector, frame=HeliocentricEclipticIAU76, obstime=obstime)

    return coord.transform_to(HeliographicStonyhurst).reshape(obstime.shape)