B
    |d                 @   s|   d Z ddlZddlmZ ddlmZ ddlmZ ddgZ	dd	 Z
d
d Zdd Zdd Zdd Zdd Zdd Zdd ZdS )z
WCS-related utilities
    N)SkyCoord)WCS)
as_stridedefficient_pixel_to_pixelhas_celestialc             C   s6   | j dkr| S tt| jdkd| j}t| |dS )a  
    Given an array, return a new array that is the smallest subset of the
    original array that can be re-broadcasted back to the original array.

    See https://stackoverflow.com/questions/40845769/un-broadcasting-numpy-arrays
    for more details.
    r      )shape)ndimnpwherearraystridesr   r   )r   Z	new_shape r   `/work/yifan.wang/ringdown/master-ringdown-env/lib/python3.7/site-packages/reproject/wcs_utils.pyunbroadcast   s    	
r   c             C   s(   g }x| D ]}||kr
| | q
W |S )zo
    Return a list of unique items in the list provided, preserving the order
    in which they are found.
    )append)itemsZ	new_itemsitemr   r   r   unique_with_order_preserved   s
    
r   c                s   | j j}| j j | j j}tdd |D }tjt|| jft	d}x8t
| jD ]*}||| d }||  || O  < qNW  fdd|D }||fS )a(  
    Return a correlation matrix between the pixel coordinates and the
    high level world coordinates, along with the list of high level world
    coordinate classes.

    The shape of the matrix is ``(n_world, n_pix)``, where ``n_world`` is the
    number of high level world coordinates.
    c             S   s   g | ]}|d  qS )r   r   ).0cr   r   r   
<listcomp>=   s    z5pixel_to_world_correlation_matrix.<locals>.<listcomp>)dtyper   c                s   g | ]} | d  qS )r   r   )r   	component)all_classesr   r   r   E   s    )low_level_wcsZworld_axis_object_componentsworld_axis_object_classesaxis_correlation_matrixr   r
   zeroslenpixel_n_dimboolrangeZworld_n_dimindex)wcsZall_componentsr   
componentsmatrixZiworldZiworld_uniqueclassesr   )r   r   !pixel_to_world_correlation_matrix+   s    r(   c             C   s   t | \}}t |\}}t|t|kr0tdd}g }xH|D ]@}||}	|	dkr^tdq>|	dkrnd}P q>||| q>W |r|| }n||krtdt|j|}
|
S )a  
    Correlation matrix between the input and output pixel coordinates for a
    pixel -> world -> pixel transformation specified by two WCS instances.

    The first WCS specified is the one used for the pixel -> world
    transformation and the second WCS specified is the one used for the world ->
    pixel transformation. The shape of the matrix is
    ``(n_pixel_out, n_pixel_in)``.
    z:The two WCS return a different number of world coordinatesTr   z5The world coordinate types of the two WCS don't matchr   FzHWorld coordinate order doesn't match and automatic matching is ambiguous)	r(   r   
ValueErrorcountr   r#   r
   matmulT)wcs1wcs2Zmatrix1Zclasses1Zmatrix2Zclasses2unique_matchmappingZclass1matchesr&   r   r   r   !pixel_to_pixel_correlation_matrixJ   s(    



r2   c       
      C   s   g }g }xt | jd D ]}||kr&qtj| jd td}d||< d\}}xL||kr| dd|f jdd}| |ddf jdd}|t| }}qLW tt|d }tt|d }	|	| |
||	f qW |S )a  
    Given an axis correlation matrix from a WCS object, return information about
    the individual WCS that can be split out.

    The output is a list of tuples, where each tuple contains a list of
    pixel dimensions and a list of world dimensions that can be extracted to
    form a new WCS. For example, in the case of a spectral cube with the first
    two world coordinates being the celestial coordinates and the third
    coordinate being an uncorrelated spectral axis, the matrix would look like::

        array([[ True,  True, False],
               [ True,  True, False],
               [False, False,  True]])

    and this function will return ``[([0, 1], [0, 1]), ([2], [2])]``.
    r   )r   T)r   r   N)Zaxisr   )r"   r   r
   r   r!   anysumlistZnonzeroextendr   )
r&   Z
pixel_used
split_infoipixZpixel_includeZ
n_pix_prevZn_pixZworld_includeZpixel_indicesZworld_indicesr   r   r   split_matrixw   s"    

r9   c             G   s  t |d r6| j| }t|ttfs,|f}|j| S |d j}t| |}t	|}dg|j
 }x|D ]\}}	g }
xBt| j
D ]4}||kr|
t||  q||
|| jd  q|W t j|
 }
| j|
 }t|ttfs|f}|j| }x.t|j
D ] }||	krt || |||< qW qdW |S )z
    Wrapper that performs a pixel -> world -> pixel transformation with two
    WCS instances, and un-broadcasting arrays whenever possible for efficiency.
    r   N)r
   ZisscalarZpixel_to_world
isinstancetupler5   Zworld_to_pixelr   r2   r9   r    r"   r   r   ZflatZbroadcast_arraysZbroadcast_to)r-   r.   inputsZworld_outputsZoriginal_shaper&   r7   outputsZpixel_in_indicesZpixel_out_indicesZpixel_inputsr8   Zpixel_outputsr   r   r   r      s0    






c             C   s@   t | tr| jS x&| jj D ]}t|d trdS qW dS dS )zG
    Returns `True` if there are celestial coordinates in the WCS.
    r   TFN)r:   r   r   r   r   values
issubclassr   )r$   Zworld_axis_classr   r   r   r      s    
c             G   s   t | |f| }t || f| }tj|d jtd}x2tt|D ]"}|t|| ||  dkO }qBW t|rx2tt|D ]"}|| 	 ||< tj
|| |< qW |S )Nr   )r   r   )r   r
   r   r   r!   r"   r   absr3   copynan)r-   r.   r<   r=   Zinputs_checkresetr8   r   r   r   'efficient_pixel_to_pixel_with_roundtrip   s    "
rD   )__doc__numpyr
   Zastropy.coordinatesr   Zastropy.wcsr   Znumpy.lib.stride_tricksr   __all__r   r   r(   r2   r9   r   r   rD   r   r   r   r   <module>   s   -(,