a
    ߙfbcO                     @   s  d Z ddlmZ ddlZddlZddlZddlm	Z	 ddl
mZ ddlmZmZ ddlmZ dd	lmZ dd
lmZ ddlmZ ddlmZmZ ddlmZmZmZm Z  ddl!m"Z" g dZ#dZ$dgddgddgdgddgddgdgdgdgdgdgdgdZ%dd d!d"d#d$d%d&d'Z&d(dd) Z'G d*d+ d+eZ(d,d- Z)dBd/d0Z*dCd1d2Z+dDd3d4Z,dEd5d6Z-dFd7d8Z.dGd9d:Z/d;d< e0 1 D D ]"Z2e2j j3ee'd"d d=e2_ qd>Z4ed?e4d@dA Z5dS )Hzc
This module contains convenience functions for retrieving solar system
ephemerides from jplephem.
    )urlparseN   )SkyCoord)download_file)classproperty
deprecated)ScienceState)indent)units)c)CartesianRepresentationCartesianDifferential)GCRSICRSITRSTETE)get_jd12)get_bodyget_moonget_body_barycentricget_body_barycentric_posvelsolar_system_ephemerisde430)r   
   )r   r   )r      )r      )r   i+  )r      )r   i  )r   i-  )r      )r      )r      )r      )r      )r   	   )sunmercuryvenusearth-moon-barycenterearthmoonmarsjupitersaturnuranusneptuneZplutor   r   r   r   r   r    r!   )r$   r%   r&   r)   r*   r+   r,   r-   a  
You can either give an explicit ephemeris or use a default, which is normally
a built-in ephemeris that does not require ephemeris files.  To change
the default to be the JPL ephemeris::

    >>> from astropy.coordinates import solar_system_ephemeris
    >>> solar_system_ephemeris.set('jpl')  # doctest: +SKIP

Use of any JPL ephemeris requires the jplephem package
(https://pypi.org/project/jplephem/).
If needed, the ephemeris file will be downloaded (and cached).

One can check which bodies are covered by a given ephemeris using::

    >>> solar_system_ephemeris.bodies
    ('earth', 'sun', 'moon', 'mercury', 'venus', 'earth-moon-barycenter', 'mars', 'jupiter', 'saturn', 'uranus', 'neptune')
c                   @   sH   e Zd ZdZdZdZedd Zedd Ze	dd	 Z
e	d
d ZdS )r   a  Default ephemerides for calculating positions of Solar-System bodies.

    This can be one of the following::

    - 'builtin': polynomial approximations to the orbital elements.
    - 'de430', 'de432s', 'de440', 'de440s': short-cuts for recent JPL dynamical models.
    - 'jpl': Alias for the default JPL ephemeris (currently, 'de430').
    - URL: (str) The url to a SPK ephemeris in SPICE binary (.bsp) format.
    - PATH: (str) File path to a SPK ephemeris in SPICE binary (.bsp) format.
    - `None`: Ensure an Exception is raised without an explicit ephemeris.

    The default is 'builtin', which uses the ``epv00`` and ``plan94``
    routines from the ``erfa`` implementation of the Standards Of Fundamental
    Astronomy library.

    Notes
    -----
    Any file required will be downloaded (and cached) when the state is set.
    The default Satellite Planet Kernel (SPK) file from NASA JPL (de430) is
    ~120MB, and covers years ~1550-2650 CE [1]_.  The smaller de432s file is
    ~10MB, and covers years 1950-2050 [2]_ (and similarly for the newer de440
    and de440s).  Older versions of the JPL ephemerides (such as the widely
    used de200) can be used via their URL [3]_.

    .. [1] https://naif.jpl.nasa.gov/pub/naif/generic_kernels/spk/planets/aareadme_de430-de431.txt
    .. [2] https://naif.jpl.nasa.gov/pub/naif/generic_kernels/spk/planets/aareadme_de432s.txt
    .. [3] https://naif.jpl.nasa.gov/pub/naif/generic_kernels/spk/planets/a_old_versions/
    builtinNc                 C   s   |d u r| j S | | |S N)_value
get_kernel)clsvalue r5   ?lib/python3.9/site-packages/astropy/coordinates/solar_system.pyvalidatem   s    
zsolar_system_ephemeris.validatec                 C   sV   | j d u s| j j|krP| j d ur4| j jj  d | _ t|}|d urJ||_|| _ | j S r0   )_kernelorigindaffileclose_get_kernel)r3   r4   kernelr5   r5   r6   r2   v   s    
z!solar_system_ephemeris.get_kernelc                 C   s   |  | jS r0   )r2   r1   r3   r5   r5   r6   r>      s    zsolar_system_ephemeris.kernelc                 C   s<   | j d u rd S | j  dkr,dtt  S tt S d S )Nr/   )r'   r#   r(   )r1   lowertuple PLAN94_BODY_NAME_TO_PLANET_INDEXkeysBODY_NAME_TO_KERNEL_SPECr?   r5   r5   r6   bodies   s    

zsolar_system_ephemeris.bodies)__name__
__module____qualname____doc__r1   r8   classmethodr7   r2   r   r>   rE   r5   r5   r5   r6   r   M   s   


r   c                 C   s   | du s|   dkrdS zddlm} W n tyB   tdY n0 |   dkrTt} |   dv rpd|   } nDtj| r|	| S zt
|  W n  ty   td	| Y n0 |	t| d
dS )z
    Try importing jplephem, download/retrieve from cache the Satellite Planet
    Kernel corresponding to the given ephemeris.
    Nr/   r   )SPKziSolar system JPL ephemeris calculations require the jplephem package (https://pypi.org/project/jplephem/)Zjpl)r   Zde432sZde440Zde440szGhttps://naif.jpl.nasa.gov/pub/naif/generic_kernels/spk/planets/{:s}.bspzT{} was not one of the standard strings and could not be parsed as a file path or URLT)cache)r@   Zjplephem.spkrK   ImportErrorDEFAULT_JPL_EPHEMERISformatospathisfileopenr   	Exception
ValueErrorr   )r4   rK   r5   r5   r6   r=      s*    
r=   Tc                 C   s  |du p|t ju }d}z|r:t  du r2ttt j}nt|}t|d\}}|du rB|  } t	
||\}}	| dkr|	}
n| dkrt	||}t	||	}
ndt	|	|}| dkr|}
nJzt|  }W n" ty   td| |Y n0 t	|||}t	||}
t|
d tjdd	d
}|rt|
d tjtj dd	d
}ndt| trzt|   }W n$ ty   td| |Y n0 n| }t|dd}t|dkr| |  }}t|rdnddft|dd }|D ]~}|| }|jdkr4|||}|r|| |j!7 }n|d  |dd 7  < n&t"||#||D ]\}}||7 }qFq|j!dd | |_!t|d tj$d	d}|rt|d tj$tj d	d}|r||fn|W |s|dur|j%j&'  S n|s|dur|j%j&'  0 dS )a  Calculate the barycentric position (and velocity) of a solar system body.

    Parameters
    ----------
    body : str or other
        The solar system body for which to calculate positions.  Can also be a
        kernel specifier (list of 2-tuples) if the ``ephemeris`` is a JPL
        kernel.
    time : `~astropy.time.Time`
        Time of observation.
    ephemeris : str, optional
        Ephemeris to use.  By default, use the one set with
        ``astropy.coordinates.solar_system_ephemeris.set``
    get_velocity : bool, optional
        Whether or not to calculate the velocity as well as the position.

    Returns
    -------
    position : `~astropy.coordinates.CartesianRepresentation` or tuple
        Barycentric (ICRS) position or tuple of position and velocity.

    Notes
    -----
    Whether or not velocities are calculated makes little difference for the
    built-in ephemerides, but for most JPL ephemeris files, the execution time
    roughly doubles.
    NZtdbr'   r(   r#   zH{}'s position and velocity cannot be calculated with the '{}' ephemeris.pr.   F)unitZxyz_axiscopyvz9{}'s position cannot be calculated with the {} ephemeris.shaper5   r   r   r   r   r   )rW   rX   )(r   r1   getrU   _EPHEMERIS_NOTEr>   r=   r   r@   erfaZepv00Zmoon98ZpvppvZpvmpvrB   KeyErrorrO   Zplan94r   uZauZday
isinstancestrrD   getattrlenZravelnpZzerosZ	data_typeZcomputeZreshaperZ   zipZgenerateZkmr:   r;   r<   )bodytime	ephemerisget_velocityZdefault_kernelr>   Zjd1Zjd2Zearth_pv_helioZearth_pv_baryZbody_pv_baryZmoon_pv_geoZsun_pv_baryZ
body_indexZbody_pv_helioZbody_pos_baryZbody_vel_baryZkernel_specZ	jd1_shapeZbody_posvel_baryZpairZspkZposvelZbody_p_or_vZp_or_vr5   r5   r6   _get_body_barycentric_posvel   s     



 rj   c                 C   s   t | ||S )a  Calculate the barycentric position and velocity of a solar system body.

    Parameters
    ----------
    body : str or list of tuple
        The solar system body for which to calculate positions.  Can also be a
        kernel specifier (list of 2-tuples) if the ``ephemeris`` is a JPL
        kernel.
    time : `~astropy.time.Time`
        Time of observation.
    ephemeris : str, optional
        Ephemeris to use.  By default, use the one set with
        ``astropy.coordinates.solar_system_ephemeris.set``

    Returns
    -------
    position, velocity : tuple of `~astropy.coordinates.CartesianRepresentation`
        Tuple of barycentric (ICRS) position and velocity.

    See Also
    --------
    get_body_barycentric : to calculate position only.
        This is faster by about a factor two for JPL kernels, but has no
        speed advantage for the built-in ephemeris.

    Notes
    -----
    {_EPHEMERIS_NOTE}
    rj   rf   rg   rh   r5   r5   r6   r   7  s    r   c                 C   s   t | ||ddS )a*  Calculate the barycentric position of a solar system body.

    Parameters
    ----------
    body : str or list of tuple
        The solar system body for which to calculate positions.  Can also be a
        kernel specifier (list of 2-tuples) if the ``ephemeris`` is a JPL
        kernel.
    time : `~astropy.time.Time`
        Time of observation.
    ephemeris : str, optional
        Ephemeris to use.  By default, use the one set with
        ``astropy.coordinates.solar_system_ephemeris.set``

    Returns
    -------
    position : `~astropy.coordinates.CartesianRepresentation`
        Barycentric (ICRS) position of the body in cartesian coordinates

    See Also
    --------
    get_body_barycentric_posvel : to calculate both position and velocity.

    Notes
    -----
    {_EPHEMERIS_NOTE}
    F)ri   rk   rl   r5   r5   r6   r   X  s    r   c           
      C   s   |du rt  }dtj }|}dtj }td||}|durD||7 }tt|dtj krt| ||}||  }	||	t	  }|	t	 }|| }qDt| ||S )a  Calculate the apparent position of body ``body`` relative to Earth.

    This corrects for the light-travel time to the object.

    Parameters
    ----------
    body : str or other
        The solar system body for which to calculate positions.  Can also be a
        kernel specifier (list of 2-tuples) if the ``ephemeris`` is a JPL
        kernel.
    time : `~astropy.time.Time`
        Time of observation.
    ephemeris : str, optional
        Ephemeris to use.  By default, use the one set with
        ``~astropy.coordinates.solar_system_ephemeris.set``
    obsgeoloc : `~astropy.coordinates.CartesianRepresentation`, optional
        The GCRS position of the observer

    Returns
    -------
    cartesian_position : `~astropy.coordinates.CartesianRepresentation`
        Barycentric (ICRS) apparent position of the body in cartesian coordinates

    Notes
    -----
    {_EPHEMERIS_NOTE}
    Ng      4@g        r'   g:0yE>)
r   r[   r_   sr   rd   anyZfabsZnormspeed_of_light)
rf   rg   rh   	obsgeolocZdelta_light_travel_timeZemitted_timeZlight_travel_timeZ	earth_locZbody_locZearth_distancer5   r5   r6   _get_apparent_body_positionx  s"    


rq   c           	      C   s`   |du r|j }|dur&||\}}nd\}}t| |||}t|}|t|||d}t|S )a  
    Get a `~astropy.coordinates.SkyCoord` for a solar system body as observed
    from a location on Earth in the `~astropy.coordinates.GCRS` reference
    system.

    Parameters
    ----------
    body : str or list of tuple
        The solar system body for which to calculate positions.  Can also be a
        kernel specifier (list of 2-tuples) if the ``ephemeris`` is a JPL
        kernel.
    time : `~astropy.time.Time`
        Time of observation.
    location : `~astropy.coordinates.EarthLocation`, optional
        Location of observer on the Earth.  If not given, will be taken from
        ``time`` (if not present, a geocentric observer will be assumed).
    ephemeris : str, optional
        Ephemeris to use.  If not given, use the one set with
        ``astropy.coordinates.solar_system_ephemeris.set`` (which is
        set to 'builtin' by default).

    Returns
    -------
    skycoord : `~astropy.coordinates.SkyCoord`
        GCRS Coordinate for the body

    Notes
    -----
    The coordinate returned is the apparent position, which is the position of
    the body at time *t* minus the light travel time from the *body* to the
    observing *location*.

    {_EPHEMERIS_NOTE}
    N)NN)obstimerp   	obsgeovel)locationZget_gcrs_posvelrq   r   transform_tor   r   )	rf   rg   rt   rh   rp   rs   ZcartrepZicrsZgcrsr5   r5   r6   r     s    #r   c                 C   s   t d| ||dS )a  
    Get a `~astropy.coordinates.SkyCoord` for the Earth's Moon as observed
    from a location on Earth in the `~astropy.coordinates.GCRS` reference
    system.

    Parameters
    ----------
    time : `~astropy.time.Time`
        Time of observation
    location : `~astropy.coordinates.EarthLocation`
        Location of observer on the Earth. If none is supplied, taken from
        ``time`` (if not present, a geocentric observer will be assumed).
    ephemeris : str, optional
        Ephemeris to use.  If not given, use the one set with
        ``astropy.coordinates.solar_system_ephemeris.set`` (which is
        set to 'builtin' by default).

    Returns
    -------
    skycoord : `~astropy.coordinates.SkyCoord`
        GCRS Coordinate for the Moon

    Notes
    -----
    The coordinate returned is the apparent position, which is the position of
    the moon at time *t* minus the light travel time from the moon to the
    observing *location*.

    {_EPHEMERIS_NOTE}
    r(   )rt   rh   )r   )rg   rt   rh   r5   r5   r6   r     s     r   c                 C   s,   g | ]$}t |r|jd urd|jv r|qS )Nz{_EPHEMERIS_NOTE})callablerI   ).0fr5   r5   r6   
<listcomp>  s   
ry   )r\   z
The use of _apparent_position_in_true_coordinates is deprecated because
astropy now implements a True Equator True Equinox Frame (TETE), which
should be used instead.
z4.2c                 C   sb   t | dd}|du rJ| jdt| ji}t|| jdt	| jdj
}t| j|d}| |S )z
    Convert Skycoord in GCRS frame into one in which RA and Dec
    are defined w.r.t to the true equinox and poles of the Earth
    rt   Nrm   )rr   )rr   rt   )rb   rp   Zwith_differentialsr   Zfrom_cartesianrs   r   rr   ru   r   Zearth_locationr   )Zskycoordrt   Zgcrs_repZ
tete_framer5   r5   r6   &_apparent_position_in_true_coordinates  s    
rz   )NT)N)N)N)NN)NN)6rI   Zurllib.parser   os.pathrP   Znumpyrd   r]   Zsky_coordinater   Zastropy.utils.datar   Zastropy.utils.decoratorsr   r   Zastropy.utils.stater   Zastropy.utilsr	   Zastropyr
   r_   Zastropy.constantsr   ro   Zrepresentationr   r   Zbuiltin_framesr   r   r   r   Zbuiltin_frames.utilsr   __all__rN   rD   rB   r\   r   r=   rj   r   r   rq   r   r   localsvaluesrx   rO   Zdeprecation_msgrz   r5   r5   r5   r6   <module>   sr   F#  
 
!
 
1
4
% 