U
    e»{joQ  ã                   @   s~   d Z ddlZddlmZ ddlmZ ddlm	Z	 ddl
mZ dd	d
dgZddd„Zddd	„Zddd
„Zddd„Zddd„ZdS )zB
This module contains functions for matching coordinate catalogs.
é    N)Úunitsé   )ÚAngle)ÚUnitSphericalRepresentation)ÚSkyCoordÚmatch_coordinates_3dÚmatch_coordinates_skyÚsearch_around_3dÚsearch_around_skyÚ	kdtree_3dc                 C   s  |j st|ƒdk rtdƒ‚t||ƒ}t| tƒr>| j|dd�} n
|  |¡} |jjj	}| jj
 |¡}| dt |j¡d f¡}t |j¡ ¡ r’tdƒ‚| |j|¡\}}	|dkrÌ|dd…df }|	dd…df }	||	  | ¡}
|	 |jdd… ¡|
| |jdd… ¡| fS )	a?  
    Finds the nearest 3-dimensional matches of a coordinate or coordinates in
    a set of catalog coordinates.

    This finds the 3-dimensional closest neighbor, which is only different
    from the on-sky distance if ``distance`` is set in either ``matchcoord``
    or ``catalogcoord``.

    Parameters
    ----------
    matchcoord : `~astropy.coordinates.BaseCoordinateFrame` or `~astropy.coordinates.SkyCoord`
        The coordinate(s) to match to the catalog.
    catalogcoord : `~astropy.coordinates.BaseCoordinateFrame` or `~astropy.coordinates.SkyCoord`
        The base catalog in which to search for matches. Typically this will
        be a coordinate object that is an array (i.e.,
        ``catalogcoord.isscalar == False``)
    nthneighbor : int, optional
        Which closest neighbor to search for.  Typically ``1`` is desired here,
        as that is correct for matching one set of coordinates to another.
        The next likely use case is ``2``, for matching a coordinate catalog
        against *itself* (``1`` is inappropriate because each point will find
        itself as the closest match).
    storekdtree : bool or str, optional
        If a string, will store the KD-Tree used for the computation
        in the ``catalogcoord``, as in ``catalogcoord.cache`` with the
        provided name.  This dramatically speeds up subsequent calls with the
        same catalog. If False, the KD-Tree is discarded after use.

    Returns
    -------
    idx : int array
        Indices into ``catalogcoord`` to get the matched points for each
        ``matchcoord``. Shape matches ``matchcoord``.
    sep2d : `~astropy.coordinates.Angle`
        The on-sky separation between the closest match for each ``matchcoord``
        and the ``matchcoord``. Shape matches ``matchcoord``.
    dist3d : `~astropy.units.Quantity` ['length']
        The 3D distance between the closest match for each ``matchcoord`` and
        the ``matchcoord``. Shape matches ``matchcoord``.

    Notes
    -----
    This function requires `SciPy <https://www.scipy.org/>`_ to be installed
    or it will fail.
    r   úCThe catalog for coordinate matching cannot be a scalar or length-0.F©Zmerge_attributesé   z0Matching coordinates cannot contain NaN entries.Néÿÿÿÿ)ÚisscalarÚlenÚ
ValueErrorÚ_get_cartesian_kdtreeÚ
isinstancer   Útransform_toÚ	cartesianÚxÚunitÚxyzÚtoÚreshapeÚnpÚprodÚshapeÚisnanÚvalueÚanyÚqueryÚTÚ
separation)Ú
matchcoordÚcatalogcoordÚnthneighborÚstorekdtreeÚkdtZcatunitZmatchxyzZmatchflatxyzÚdistÚidxÚsep2d© r-   ú[/var/www/html/bwave/python/venv/lib/python3.8/site-packages/astropy/coordinates/matching.pyr      s,    0ÿ



ýÚ
kdtree_skyc                 C   sð   |j st|ƒdk rtdƒ‚t| tƒr4| j|dd�}n
|  |¡}|j t¡}| 	|¡}|j t¡}| 	|¡}|j
 ||¡}t||||ƒ\}	}
}t|jtƒs²t|jtƒs²||	  |¡}t|tƒrÎ|j
| |j
|< n|dkræ|j
d |j
d< |	|
|fS )aÏ  
    Finds the nearest on-sky matches of a coordinate or coordinates in
    a set of catalog coordinates.

    This finds the on-sky closest neighbor, which is only different from the
    3-dimensional match if ``distance`` is set in either ``matchcoord``
    or ``catalogcoord``.

    Parameters
    ----------
    matchcoord : `~astropy.coordinates.BaseCoordinateFrame` or `~astropy.coordinates.SkyCoord`
        The coordinate(s) to match to the catalog.
    catalogcoord : `~astropy.coordinates.BaseCoordinateFrame` or `~astropy.coordinates.SkyCoord`
        The base catalog in which to search for matches. Typically this will
        be a coordinate object that is an array (i.e.,
        ``catalogcoord.isscalar == False``)
    nthneighbor : int, optional
        Which closest neighbor to search for.  Typically ``1`` is desired here,
        as that is correct for matching one set of coordinates to another.
        The next likely use case is ``2``, for matching a coordinate catalog
        against *itself* (``1`` is inappropriate because each point will find
        itself as the closest match).
    storekdtree : bool or str, optional
        If a string, will store the KD-Tree used for the computation
        in the ``catalogcoord`` in ``catalogcoord.cache`` with the
        provided name.  This dramatically speeds up subsequent calls with the
        same catalog. If False, the KD-Tree is discarded after use.

    Returns
    -------
    idx : int array
        Indices into ``catalogcoord`` to get the matched points for each
        ``matchcoord``. Shape matches ``matchcoord``.
    sep2d : `~astropy.coordinates.Angle`
        The on-sky separation between the closest match for each
        ``matchcoord`` and the ``matchcoord``. Shape matches ``matchcoord``.
    dist3d : `~astropy.units.Quantity` ['length']
        The 3D distance between the closest match for each ``matchcoord`` and
        the ``matchcoord``. Shape matches ``matchcoord``.  If either
        ``matchcoord`` or ``catalogcoord`` don't have a distance, this is the 3D
        distance on the unit sphere, rather than a true distance.

    Notes
    -----
    This function requires `SciPy <https://www.scipy.org/>`_ to be installed
    or it will fail.
    r   r   Fr   TÚkdtree)r   r   r   r   r   r   ÚdataÚrepresent_asr   Úrealize_frameÚcacheÚgetr   Úseparation_3dÚstr)r%   r&   r'   r(   ZnewmatchZmatch_ureprZ
newmatch_uZ	cat_ureprZnewcat_ur+   r,   Zsep3dr-   r-   r.   r   j   s8    2ÿ



   ÿ

ÿ
þ
c                 C   sZ  |j stdƒ‚| j s|j r"tdƒ‚t| ƒdks:t|ƒdkrntjg td�tjg td�tg tjƒt 	g | j
j¡fS t||ƒ}|jjj}|  |¡} t| ||d�}| |¡}g }g }	t| ||¡ƒD ]&\}
}|D ]}| |
¡ |	 |¡ qÈq¼tj|td�}tj|	td�}	|jdk�r*tg tjƒ}t 	g | j
j¡}n$| |  ||	 ¡}| |  ||	 ¡}||	||fS )aè	  
    Searches for pairs of points that are at least as close as a specified
    distance in 3D space.

    This is intended for use on coordinate objects with arrays of coordinates,
    not scalars.  For scalar coordinates, it is better to use the
    ``separation_3d`` methods.

    Parameters
    ----------
    coords1 : `~astropy.coordinates.BaseCoordinateFrame` or `~astropy.coordinates.SkyCoord`
        The first set of coordinates, which will be searched for matches from
        ``coords2`` within ``seplimit``.  Cannot be a scalar coordinate.
    coords2 : `~astropy.coordinates.BaseCoordinateFrame` or `~astropy.coordinates.SkyCoord`
        The second set of coordinates, which will be searched for matches from
        ``coords1`` within ``seplimit``.  Cannot be a scalar coordinate.
    distlimit : `~astropy.units.Quantity` ['length']
        The physical radius to search within.
    storekdtree : bool or str, optional
        If a string, will store the KD-Tree used in the search with the name
        ``storekdtree`` in ``coords2.cache``. This speeds up subsequent calls
        to this function. If False, the KD-Trees are not saved.

    Returns
    -------
    idx1 : int array
        Indices into ``coords1`` that matches to the corresponding element of
        ``idx2``. Shape matches ``idx2``.
    idx2 : int array
        Indices into ``coords2`` that matches to the corresponding element of
        ``idx1``. Shape matches ``idx1``.
    sep2d : `~astropy.coordinates.Angle`
        The on-sky separation between the coordinates. Shape matches ``idx1``
        and ``idx2``.
    dist3d : `~astropy.units.Quantity` ['length']
        The 3D distance between the coordinates. Shape matches ``idx1`` and
        ``idx2``. The unit is that of ``coords1``.

    Notes
    -----
    This function requires `SciPy <https://www.scipy.org/>`_
    to be installed or it will fail.

    If you are using this function to search in a catalog for matches around
    specific points, the convention is for ``coords2`` to be the catalog, and
    ``coords1`` are the points to search around.  While these operations are
    mathematically the same if ``coords1`` and ``coords2`` are flipped, some of
    the optimizations may work better if this convention is obeyed.

    In the current implementation, the return values are always sorted in the
    same order as the ``coords1`` (so ``idx1`` is in ascending order).  This is
    considered an implementation detail, though, so it could change in a future
    release.
    z.distlimit must be a scalar in search_around_3dzéOne of the inputs to search_around_3d is a scalar. search_around_3d is intended for use with array coordinates, not scalars.  Instead, use ``coord1.separation_3d(coord2) < distlimit`` to find the coordinates near a scalar coordinate.r   ©Zdtype)Ú	forceunit)r   r   r   r   ÚarrayÚintr   ÚuÚdegÚQuantityÚdistancer   r   r   r   r   Zto_valueÚ	enumerateÚquery_ball_treeÚappendÚsizer$   r6   )Úcoords1Úcoords2Z	distlimitr(   Úkdt2ZcunitÚkdt1ÚdÚidxs1Úidxs2ÚiÚmatchesÚmatchÚd2dsÚd3dsr-   r-   r.   r	   È   s>    7ÿ
ü




c                 C   s(  |j stdƒ‚| j s|j r"tdƒ‚t| ƒdks:t|ƒdkrˆ|jjtjkrPtj}n| jj}tjg t	d�tjg t	d�t
g tjƒt g |¡fS |  |¡} | j t¡}|  |¡}t||ƒ}|rÎ|j |¡rÎ|j| }n>|j t¡}	| |	¡}
t|
|ƒ}|�r||j|dk�rdn|< dt t
|ƒd ¡ j}g }g }t| ||¡ƒD ]*\}}|D ]}| |¡ | |¡ �qH�q<tj|t	d�}tj|t	d�}|jdk�rÊ|jjtjk�r¨tj}n| jj}t
g tjƒ}t g |¡}nR| |  || ¡}z| |  || ¡}W n( tk
�r   dt |d ¡ }Y nX ||||fS )	a“  
    Searches for pairs of points that have an angular separation at least as
    close as a specified angle.

    This is intended for use on coordinate objects with arrays of coordinates,
    not scalars.  For scalar coordinates, it is better to use the ``separation``
    methods.

    Parameters
    ----------
    coords1 : coordinate-like
        The first set of coordinates, which will be searched for matches from
        ``coords2`` within ``seplimit``. Cannot be a scalar coordinate.
    coords2 : coordinate-like
        The second set of coordinates, which will be searched for matches from
        ``coords1`` within ``seplimit``. Cannot be a scalar coordinate.
    seplimit : `~astropy.units.Quantity` ['angle']
        The on-sky separation to search within.
    storekdtree : bool or str, optional
        If a string, will store the KD-Tree used in the search with the name
        ``storekdtree`` in ``coords2.cache``. This speeds up subsequent calls
        to this function. If False, the KD-Trees are not saved.

    Returns
    -------
    idx1 : int array
        Indices into ``coords1`` that matches to the corresponding element of
        ``idx2``. Shape matches ``idx2``.
    idx2 : int array
        Indices into ``coords2`` that matches to the corresponding element of
        ``idx1``. Shape matches ``idx1``.
    sep2d : `~astropy.coordinates.Angle`
        The on-sky separation between the coordinates. Shape matches ``idx1``
        and ``idx2``.
    dist3d : `~astropy.units.Quantity` ['length']
        The 3D distance between the coordinates. Shape matches ``idx1``
        and ``idx2``; the unit is that of ``coords1``.
        If either ``coords1`` or ``coords2`` don't have a distance,
        this is the 3D distance on the unit sphere, rather than a
        physical distance.

    Notes
    -----
    This function requires `SciPy <https://www.scipy.org/>`_
    to be installed or it will fail.

    In the current implementation, the return values are always sorted in the
    same order as the ``coords1`` (so ``idx1`` is in ascending order).  This is
    considered an implementation detail, though, so it could change in a future
    release.
    z.seplimit must be a scalar in search_around_skyzçOne of the inputs to search_around_sky is a scalar. search_around_sky is intended for use with array coordinates, not scalars.  Instead, use ``coord1.separation(coord2) < seplimit`` to find the coordinates near a scalar coordinate.r   r8   Tr0   é   g       @)r   r   r   r?   r   r<   Zdimensionless_unscaledr   r:   r;   r   r=   r>   r   r1   r2   r   r3   r   r4   r5   Úsinr    r@   rA   rB   rC   r$   r6   )rD   rE   Zseplimitr(   ZdistunitZurepr1Zucoords1rG   rF   Zurepr2Zucoords2ÚrrI   rJ   rK   rL   rM   rN   rO   r-   r-   r.   r
   3  s^    4ÿ

ü






r0   c           	      C   sh  ddl m} ddlm} z
|j}W n" tk
rD   |dƒ |j}Y nX |dkrRd}t|tƒrŽ| j	 
|d¡}|dk	r¼t||ƒs¼td|› d	�ƒ‚n.t||ƒr¢|}d}n|s¬d}ntd
t|ƒ ƒ‚|dk�rT|dkrØ| jj}n| jj |¡}| dt |j¡d f¡}t |j¡ ¡ �rtdƒ‚z||jjddd�}W n" tk
�rR   ||jjƒ}Y nX |�rd|| j	|< |S )aÀ  
    This is a utility function to retrieve (and build/cache, if necessary)
    a 3D cartesian KD-Tree from various sorts of astropy coordinate objects.

    Parameters
    ----------
    coord : `~astropy.coordinates.BaseCoordinateFrame` or `~astropy.coordinates.SkyCoord`
        The coordinates to build the KD-Tree for.
    attrname_or_kdt : bool or str or KDTree
        If a string, will store the KD-Tree used for the computation in the
        ``coord``, in ``coord.cache`` with the provided name. If given as a
        KD-Tree, it will just be used directly.
    forceunit : unit or None
        If a unit, the cartesian coordinates will convert to that unit before
        being put in the KD-Tree.  If None, whatever unit it's already in
        will be used

    Returns
    -------
    kdt : `~scipy.spatial.cKDTree` or `~scipy.spatial.KDTree`
        The KD-Tree representing the 3D cartesian representation of the input
        coordinates.
    r   )Úwarn)ÚspatialzNC-based KD tree not found, falling back on (much slower) python implementationTr0   NzThe `attrname_or_kdt` "z" is not a scipy KD tree!z/Invalid `attrname_or_kdt` argument for KD-Tree:r   z/Catalog coordinates cannot contain NaN entries.F)Zcompact_nodesZbalanced_tree)ÚwarningsrS   ZscipyrT   ZcKDTreeÚ	ExceptionÚKDTreer   r7   r4   r5   Ú	TypeErrorr   r   r   r   r   r   r   r   r    r!   r   r#   )	ZcoordZattrname_or_kdtr9   rS   rT   rW   r)   ZcartxyzZflatxyzr-   r-   r.   r   ¶  sN    
ÿ

ÿ

ÿ


r   )r   r   )r   r/   )r   )r/   )r0   N)Ú__doc__Únumpyr   Zastropyr   r<   Ú r   Zrepresentationr   Zsky_coordinater   Ú__all__r   r   r	   r
   r   r-   r-   r-   r.   Ú<module>   s(   ü	   ÿ
T   ÿ
^
k
 