B
    zd                 @   s  d dl Zd dlZed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 d	d
ddZed\ZZZdZeeeee dddj  jZeeeee dddj  jZG dd deZedkrd dlZej deed G dd de!Z"d9ddZ#d:ddZ$d;d d!Z%d<d"d#Z&d=d$d%Z'd&d' Z(d(d) Z)d*d+ Z*d>d,d-Z+d?d/d0Z,d1d2 Z-d@d3d4Z.dAd5d6Z/d7d8 Z0dS )B    NZhealpy)SkyCoord)deprecated_renamed_argument   )	pixelfunc)sphtfunc)
rotate_almZGalacticZEcliptic
Equatorial)GEC   ZBarycentricMeanEclipticZ	cartesian)xyzframeZrepresentation_typeZgalacticZfk5c               @   s   e Zd ZdZdS )ConsistencyWarningz.Warns for a problem in the consistency of dataN)__name__
__module____qualname____doc__ r   r   [/work/yifan.wang/ringdown/master-ringdown-env/lib/python3.7/site-packages/healpy/rotator.pyr   ?   s   r   __main__always)categorymodulec               @   s
  e Zd ZdZdZd9ddZdd	 Zd
d ZeeddZ	dd Z
dd Zdd Zdd Zdd Zdd Zdd Zedd Zedd Zed d! Zed"d# Zed$d% Zed&d' Zed(d) Zd*d+ Zd,d- Zd:d/d0Zed1dd2d;d3d4Zd5d6 Zd7d8 ZeZdS )<Rotatora&  Rotation operator, including astronomical coordinate systems.

    This class provides tools for spherical rotations. It is meant to be used
    in the healpy library for plotting, and for this reason reflects the
    convention used in the Healpix IDL library.

    Parameters
    ----------
    rot : None or sequence
      Describe the rotation by its euler angle. See :func:`euler_matrix_new`.
    coord : None or sequence of str
      Describe the coordinate system transform. If *rot* is also given, the
      coordinate transform is applied first, and then the rotation.
    inv : bool
      If True, the inverse rotation is defined. (Default: False)
    deg : bool
      If True, angles are assumed to be in degree. (Default: True)
    eulertype : str
      The Euler angle convention used. See :func:`euler_matrix_new`.

    Attributes
    ----------
    mat
    coordin
    coordout
    coordinstr
    coordoutstr
    rots
    coords

    Examples
    --------
    >>> r = Rotator(coord=['G','E'])  # Transforms galactic to ecliptic coordinates
    >>> theta_gal, phi_gal = np.pi/2., 0.
    >>> theta_ecl, phi_ecl = r(theta_gal, phi_gal)  # Apply the conversion
    >>> print(theta_ecl)
    1.66742347999
    >>> print(phi_ecl)
    -1.6259571125
    >>> theta_ecl, phi_ecl = Rotator(coord='ge')(theta_gal, phi_gal) # In one line
    >>> print(theta_ecl)
    1.66742347999
    >>> print(phi_ecl)
    -1.6259571125
    >>> vec_gal = np.array([1, 0, 0]) #Using vectors
    >>> vec_ecl = r(vec_gal)
    >>> print(vec_ecl)
    [-0.05487563 -0.99382135 -0.09647686]
    z?rot and coord must be single elements or sequence of same size.NTZYXc             C   sx  t |dot |d d}t |do>t |d do>t|d tk	}|rn|rnt|t|krdttjq|}|}	n0|sv|r|dk	r|dk	rttjn|g}|g}	t |d}
|
rt|t|krtd|}n|gt| }|dkr|| _nd| _g | _g | _	g | _
xXt||	|D ]H\}}}t||d}t|}| j| | j	| | j
t| qW | jsltd |   dS )	a|  Create a rotator with given parameters.
        - rot: a float, a tuple of 1,2 or 3 floats or a sequence of tuples.
               If it is a sequence of tuple, it must have the same length as coord.
        - coord: a string or a tuple of 1 or 2 strings or a sequence of tuple
                 If it is a sequence of tuple, it must have same length as rot.
        - inv: whether to use inverse rotation or not
        - deg: if True, angles in rot are assumed in degree (default: True)
        - eulertype: the convention for Euler angles in rot.
        Note: the coord system conversion is applied first, then the rotation.
        __len__r   Nz-inv must have same length as rot and/or coord)r   XYr   )degz5The chain of coord system rotations is not consistent)hasattrtypestrlen
ValueErrorr   ErrMessWrongPar_eultype_rots_coords_invszipnormalise_rotnormalise_coordappendbool
consistentlogwarning_update_matrix)selfrotcoordinvr!   	eulertypeZ
rot_is_seqZcoord_is_seqrotscoordsZ
inv_is_seqinvsrciZrnZcnr   r   r   __init__   sD    


zRotator.__init__c       
      C   s   t d| _d| _xxt| j| j| jD ]b\}}}t|| j	d\}}}t
|\}}}	t ||}|rh|j}t | j|| _| jp|p|| _q&W d S )Nr   F)r9   )npidentity_matrix_do_rotationr,   r)   r*   r+   get_rotation_matrixr(   get_coordconv_matrixdotT)
r5   r=   r>   r?   rotmatdo_rotZrotnormZconvmatdo_convZ	coordnormr   r   r   r4      s    zRotator._update_matrixc             C   sn   xt | j| jD ]
\}}P qW xJt | jdd  | jdd  D ](\}}|| ||  kr\dS || }}q>W dS )Nr   FT)r,   r*   r+   )r5   r>   r?   ZcnextZinextr   r   r   _is_coords_consistent   s    (zRotator._is_coords_consistentz)consistency of the coords transform chain)docc             C   sR   t |t | k	rdS dd t| j|jD }t| oP| j|jkoP| j|jkS )NFc             S   s"   g | ]\}}t j||d ddqS )r   gV瞯<)rtolatol)rA   allclose).0r   r   r   r   r   
<listcomp>   s    z"Rotator.__eq__.<locals>.<listcomp>)r#   r,   r)   rA   arrayallr*   r+   )r5   avr   r   r   __eq__   s    zRotator.__eq__c             O   s  | ddr| jj}n| j}| dd}t|dkr|d }t|dr^t|dk s^t|dkrftd	t|dkrt||d |d | j|d
S t||d |d |d | jS n\t|dkrt||d |d | j|d
S t|dkrt||d |d |d | jS tddS )a  Use the rotator to rotate either spherical coordinates (theta, phi)
        or a vector (x,y,z). You can use lonla keyword to use longitude, latitude
        (in degree) instead of theta, phi (in radian). In this case, returns
        longitude, latitude in degree.

        Accepted forms:

        r(x,y,z)  # x,y,z either scalars or arrays
        r(theta,phi) # theta, phi scalars or arrays
        r(lon,lat,lonlat=True)  # lon, lat scalars or arrays
        r(vec) # vec 1-D array with 3 elements, or 2-D array 3xN
        r(direction) # direction 1-D array with 2 elements, or 2xN array

        Parameters
        ----------
        vec_or_dir : array or multiple arrays
          The direction to rotate. See above for accepted formats.
        lonlat : bool, optional
          If True, assumes the input direction is longitude/latitude in degrees.
          Otherwise, assumes co-latitude/longitude in radians. Default: False
        inv : bool, optional
          If True, applies the inverse rotation. Default: False.
        r8   Flonlatr   r   r      r   z.Argument must be a sequence of 2 or 3 elements)rX   z#Either 1, 2 or 3 arguments acceptedN)	poprC   rH   r%   r"   	TypeErrorrotateDirectionrD   rotateVector)r5   argskwdsmrX   argr   r   r   __call__   s$    
" zRotator.__call__c             C   sF   t |tstd| j|j }| j|j }| j|j }t|||ddS )zComposition of rotation.zFA Rotator can only multiply another Rotator (composition of rotations)F)r6   r7   r8   r!   )
isinstancer   r[   r)   r*   r+   )r5   rU   r:   r;   r<   r   r   r   __mul__  s    
zRotator.__mul__c             C   sF   t |tstd|j| j }|j| j }| j|j }t|||ddS )NzNA Rotator can only be multiplied by another Rotator (composition of rotations)F)r6   r7   r8   r!   )rc   r   r[   r)   r*   r+   )r5   br:   r;   r<   r   r   r   __rmul__  s    
zRotator.__rmul__c             C   s   | j S )N)rD   )r5   r   r   r   __nonzero__#  s    zRotator.__nonzero__c             C   sJ   | j d d d }| jd d d }dd | jd d d D }t|||ddS )Nc             S   s   g | ]
}| qS r   r   )rQ   r?   r   r   r   rR   )  s    z'Rotator.get_inverse.<locals>.<listcomp>F)r6   r7   r8   r!   )r)   r*   r+   r   )r5   r:   r;   r<   r   r   r   get_inverse&  s    zRotator.get_inversec             O   s   d|d< | j ||S )zqRotate the given vector or direction using the inverse matrix.
        rot.I(vec) <==> rot(vec,inv=True)
        Tr8   )rb   )r5   r^   r_   r   r   r   I/  s    z	Rotator.Ic             C   s   t | jS )z%The matrix representing the rotation.)rA   asarrayrC   )r5   r   r   r   mat6  s    zRotator.matc             C   s.   | j s
dS xt| j| jD ]\}}qW || S )zThe input coordinate system.N)r1   r,   r*   r+   )r5   r>   r?   r   r   r   coordin;  s
    zRotator.coordinc             C   s0   | j s
dS xt| j| jD ]\}}qW ||  S )zThe output coordinate system.N)r1   r,   r*   r+   )r5   r>   r?   r   r   r   coordoutD  s
    zRotator.coordoutc             C   s   t | jdS )z#The input coordinate system in str. )	coordnamegetrm   )r5   r   r   r   
coordinstrM  s    zRotator.coordinstrc             C   s   t | jdS )z$The output coordinate system in str.ro   )rp   rq   rn   )r5   r   r   r   coordoutstrR  s    zRotator.coordoutstrc             C   s   | j S )z+The sequence of rots defining the rotation.)r)   )r5   r   r   r   r:   W  s    zRotator.rotsc             C   s   | j S )z-The sequence of coords defining the rotation.)r*   )r5   r   r   r   r;   \  s    zRotator.coordsc             C   s    t j| j| t dddd S )z4Returns True if rotation is not (close to) identity.r   g        gV瞯<)rN   rO   )rA   rP   r:   zeros)r5   r?   r   r   r   rJ   a  s    zRotator.do_rotc             O   s(  | }| dd}| dd}t|dkr|d }t|drRt|dk sRt|dkrZtd	t|dkr~t|d |d |d
}q|}n>t|dkrt|d |d |d
}nt|dkr|}ntd|||d}|dddg|d}	|	d |d  |	d |d   }
|	d |d t|	|  }t|
|S )a  Compute the angle between transverse reference direction of initial and final frames

        For example, if angle of polarisation is psi in initial frame, it will be psi+angle_ref in final
        frame.

        Parameters
        ----------
        dir_or_vec : array
          Direction or vector (see Rotator.__call__)
        lonlat: bool, optional
          If True, assume input is longitude,latitude in degrees. Otherwise,
          theta,phi in radian. Default: False
        inv : bool, optional
          If True, use the inverse transforms. Default: False

        Returns
        -------
        angle : float, scalar or array
          Angle in radian (a scalar or an array if input is a sequence of direction/vector)
        rX   Fr8   r   r   r   rY   r   z.Argument must be a sequence of 2 or 3 elements)rX   z#Either 1, 2 or 3 arguments accepted)r8   g        g      ?)rq   r%   r"   r[   dir2vecrA   rG   arctan2)r5   r^   r_   RrX   r8   ra   rV   ZvpZ
north_poleZsinalphaZcosalphar   r   r   	angle_refe  s(    " zRotator.angle_refFc             C   s0   |s|  }n|}t|| j||d |s,|S dS )zRotate Alms with the transform defined in the Rotator object

        see the docstring of the rotate_alm function defined
        in the healpy package, this function **returns** the rotated alms,
        does not rotate in place)matrixlmaxmmaxN)copyr   rl   )r5   almrz   r{   Zinplacerotated_almr   r   r   r     s    
zRotator.rotate_almverbosez1.15.0c       	      C   s<   t j|||||d}| j|||d}t j|||t|dS )a  Rotate a HEALPix map to a new reference frame in spherical harmonics space

        This is generally the best strategy to rotate/change reference frame of maps.
        If the input map is band-limited, i.e. it can be represented exactly by
        a spherical harmonics transform under a specific lmax, the map rotation
        will be invertible.


        Parameters
        ----------
        m : np.ndarray
            Input map, single array is considered I, array with 3 rows:[I,Q,U]
        other arguments : see map2alm

        Returns
        -------
        m_rotated : np.ndarray
            Map in the new reference frame
        )use_pixel_weightsrz   r{   datapath)rz   r{   )rz   r{   nside)r   Zmap2almr   Zalm2mapr   Z	get_nside)	r5   r`   r   rz   r{   r   r   r}   r~   r   r   r   rotate_map_alms  s    zRotator.rotate_map_almsc                s   t |dkr|g}t|d }t |}t j|t|d\}}| ||\  fdd|D }t|dkr|d |d d  td	| 	   }t
||d< t||d< n|d }|S )
a  Rotate a HEALPix map to a new reference frame in pixel space

        It is generally better to rotate in spherical harmonics space, see
        the rotate_map_alms method. A case where pixel space rotation is
        better is for heavily masked maps where the spherical harmonics
        transform is not well defined.
        This function first rotates the pixels centers of the new reference
        frame to the original reference frame, then uses hp.get_interp_val
        to interpolate bilinearly the pixel values, finally fixes Q and U
        polarization by the modification to the psi angle caused by
        the Rotator using Rotator.angle_ref.
        Due to interpolation, this function generally suppresses the signal at
        high angular scales.

        Parameters
        ----------
        m : np.ndarray
            Input map, 1 map is considered I, 2 maps:[Q,U], 3 maps:[I,Q,U]

        Returns
        -------
        m_rotated : np.ndarray
            Map in the new reference frame

        r   )r   Zipixc                s   g | ]}t | qS r   )r   Zget_interp_val)rQ   Zeach)phi_pix_center_rottheta_pix_center_rotr   r   rR     s   z,Rotator.rotate_map_pixel.<locals>.<listcomp>r   rh   y              ?y               @)r   Zmaptyper%   Z
npix2nsideZpix2angrA   Zarangerj   exprx   realimag)r5   r`   Znpixr   Ztheta_pix_centerZphi_pix_centerZ	m_rotatedZL_mapr   )r   r   r   rotate_map_pixel  s"    
zRotator.rotate_map_pixelc             C   s*   dd t| jt| jt| jg d S )Nz[ z, z ])joinr$   r*   r)   r+   )r5   r   r   r   __repr__	  s    zRotator.__repr__)NNNTr   )NNF)TNNNN) r   r   r   r   r'   r@   r4   rL   propertyr1   rW   rb   rd   rf   rg   ri   rj   rl   rm   rn   rr   rs   r:   r;   rJ   rx   r   r   r   r   r   __str__r   r   r   r   r   J   sB   1
7	
0			,

    $=r   Tc             C   sr   |dkr*|dkr*|r$t j| |ddS |S nD|dk	rf|dk	rf|rZt j| t |||gddS |||fS ntddS )a  Rotate a vector (or a list of vectors) using the rotation matrix
    given as first argument.

    Parameters
    ----------
    rotmat : float, array-like shape (3,3)
      The rotation matrix
    vec : float, scalar or array-like
      The vector to transform (shape (3,) or (3,N)),
      or x component (scalar or shape (N,)) if vy and vz are given
    vy : float, scalar or array-like, optional
      The y component of the vector (scalar or shape (N,))
    vz : float, scalar or array-like, optional
      The z component of the vector (scalar or shape (N,))
    do_rot : bool, optional
      if True, really perform the operation, if False do nothing.

    Returns
    -------
    vec : float, array
      The component of the rotated vector(s).

    See Also
    --------
    Rotator
    N)r   r   )Zaxesz:You must give either vec only or vec, vy and vz parameters)rA   Z	tensordotrS   r[   )rI   vecvyvzrJ   r   r   r   r]     s    r]   Fc             C   s.   t | t|||d|d\}}}t||||dS )aT  Rotate the vector described by angles theta,phi using the rotation matrix
    given as first argument.

    Parameters
    ----------
    rotmat : float, array-like shape (3,3)
      The rotation matrix
    theta : float, scalar or array-like
      The angle theta (scalar or shape (N,))
      or both angles (scalar or shape (2, N)) if phi is not given.
    phi : float, scalar or array-like, optionnal
      The angle phi (scalar or shape (N,)).
    do_rot : bool, optional
      if True, really perform the operation, if False do nothing.
    lonlat : bool
      If True, input angles are assumed to be longitude and latitude in degree,
      otherwise, they are co-latitude and longitude in radians.

    Returns
    -------
    angles : float, array
      The angles of describing the rotated vector(s).

    See Also
    --------
    Rotator
    )rX   )rJ   )r]   ru   vec2dir)rI   thetaphirJ   rX   vxr   r   r   r   r   r\   B  s    r\   c             C   s(  t t | rt jt jfS |dkr8|dkr8| \}}}n|dk	rN|dk	rN| }ntdt |d |d  |d  }t d|jf}t || |dddf< t 	|||dddf< |rt 
|}t |dddf |dddf  |dddf  d7  < |dddddf  S | S dS )ay  Transform a vector to angle given by theta,phi.

    Parameters
    ----------
    vec : float, scalar or array-like
      The vector to transform (shape (3,) or (3,N)),
      or x component (scalar or shape (N,)) if vy and vz are given
    vy : float, scalar or array-like, optional
      The y component of the vector (scalar or shape (N,))
    vz : float, scalar or array-like, optional
      The z component of the vector (scalar or shape (N,))
    lonlat : bool, optional
      If True, return angles will be longitude and latitude in degree,
      otherwise, angles will be longitude and co-latitude in radians (default)

    Returns
    -------
    angles : float, array
      The angles (unit depending on *lonlat*) in an array of
      shape (2,) (if scalar input) or (2, N)

    See Also
    --------
    :func:`dir2vec`, :func:`pixelfunc.ang2vec`, :func:`pixelfunc.vec2ang`
    Nz3You must either give both vy and vz or none of themrY   r   r   g     V@rh   )rA   anyisnannanr[   sqrtemptysizearccosrv   degreesnegativesqueeze)r   r   r   rX   r   r=   angr   r   r   r   b  s"    
$r   c       
      C   s   |dkr| \} }|r>| | }}t jd t | t | } }t | t | t |t |f\}}}}t d|jft j}	|| |	dddf< || |	dddf< ||	dddf< |	 S )a  Transform a direction theta,phi to a unit vector.

    Parameters
    ----------
    theta : float, scalar or array-like
      The angle theta (scalar or shape (N,))
      or both angles (scalar or shape (2, N)) if phi is not given.
    phi : float, scalar or array-like, optionnal
      The angle phi (scalar or shape (N,)).
    lonlat : bool
      If True, input angles are assumed to be longitude and latitude in degree,
      otherwise, they are co-latitude and longitude in radians.

    Returns
    -------
    vec : array
      The vector(s) corresponding to given angles, shape is (3,) or (3, N).

    See Also
    --------
    :func:`vec2dir`, :func:`pixelfunc.ang2vec`, :func:`pixelfunc.vec2ang`
    Ng       @r   r   r   rY   )	rA   piradianscossinr   r   float64r   )
r   r   rX   ZlonZlatctstcpspr   r   r   r   ru     s    
 ,ru   c       	      C   sz  t |dr t|dkr |\}}n| }}t| } t|}| jdkrx| jd dkrbt| |d}qt| d}t|}nB| jdkr| jd dkrtt| |dd}nt| d}t|}|jdkr|jd dkrt||d}nt|d}t|}nF|jdkr<|jd dkr(tt||dd}nt|d}t|}t	t
|j|jd jdd}|| jdd}t||S )	a  Returns the angular distance between dir1 and dir2.

    Parameters
    ----------
    dir1, dir2 : float, array-like
      The directions between which computing the angular distance.
      Angular if len(dir) == 2 or vector if len(dir) == 3.
      See *lonlat* for unit
    lonlat : bool, scalar or sequence
      If True, angles are assumed to be longitude and latitude in degree,
      otherwise they are interpreted as colatitude and longitude in radian.
      If a sequence, lonlat[0] applies to dir1 and lonlat[1] applies to dir2.

    Returns
    -------
    angles : float, scalar or array-like
      The angle(s) between dir1 and dir2 in radian.

    Examples
    --------
    >>> import healpy as hp
    >>> hp.rotator.angdist([.2,0], [.2, 1e-6])
    array([  1.98669331e-07])
    r   rY   r   )rX   )r   rh   r   )r   r   )axis)r"   r%   rA   rk   ndimshaperu   Zreshapenormalize_vecr   crossrH   sumrv   )	Zdir1Zdir2rX   Zlonlat1Zlonlat2Zvec1Zvec2Zvec_prodZ	scal_prodr   r   r   angdist  s8    







"r   c             C   s2   t | t j} t t j| d dd}| | } | S )a  Normalize the vector(s) *vec* (in-place if it is a ndarray).

    Parameters
    ----------
    vec : float, array-like of shape (D,) or (D, N)
      The D-vector(s) to normalize.

    Returns
    -------
    vec_normed : float, array
      Normalized vec, shape (D,) or (D, N)
    rY   r   )r   )rA   rS   r   r   r   )r   r=   r   r   r   r     s    r   c             C   s|   | dkr| S t | tstd| d  dkr4d}nD| d  dkrR| dkrRd}n&| d  dksj| dkrpd}ntd|S )	zCheck if parameter is a valid coord system.
    Raise a TypeError exception if it is not, otherwise returns the normalized
    coordinate system name.
    NzYCoordinate must be a string (G[alactic], E[cliptic], C[elestial] or Equatorial=Celestial)r   r	   r
   r   r   zUWrong coordinate (either G[alactic], E[cliptic], C[elestial] or Equatorial=Celestial))rc   r$   r[   upperr&   )r>   r   r   r   r   check_coord  s    
r   c             C   sj   g }| dkrd} t | } t| dkr,tdx| D ]}|t| q2W t|dk rb||d  t |S )aH  Normalise the coord argument.
    Coord sys are either 'E','G', 'C' or 'X' if undefined.

    Input: either a string or a sequence of string.

    Output: a tuple of two strings, each being one of the norm coord sys name
            above.

    eg, 'E' -> ['E','E'], ['Ecliptic','G'] -> ['E','G']
    None -> ['X','X'] etc.
    N)NNrY   z^Coordinate must be a string (G[alactic], E[cliptic] or C[elestial]) or a sequence of 2 stringsr   )tupler%   r[   r/   r   )r7   
coord_normr   r   r   r   r.   )  s    
r.   c             C   sP   |rt jd }nd}| dkr(t d} n$t | t j | } | jddd | S )zReturn rot possibly completed with zeroes to reach size 3.
    If rot is None, return a vector of 0.
    If deg is True, convert from degree to radian, otherwise assume input
    is in radian.
    g     f@g      ?Nr   F)Zrefcheck)rA   r   rt   rS   r   flattenresize)r6   r!   convertr   r   r   r-   F  s    r-   r   c             C   s   t | |d} tj| tdddds*d}nd}|dkrVt| d	 | d
  | d dd}nF|dkr~t| d	 | d
  | d dd}nt| d	 | d
  | d dd}||| fS )a  Return the rotation matrix corresponding to angles given in rot.

    Usage: matrot,do_rot,normrot = get_rotation_matrix(rot)

    Input:
       - rot: either None, an angle or a tuple of 1,2 or 3 angles
              corresponding to Euler angles.
    Output:
       - matrot: 3x3 rotation matrix
       - do_rot: True if rotation is not identity, False otherwise
       - normrot: the normalized version of the input rot.
    )r!   r   g        gV瞯<)rN   rO   TFr   r   r   rY   )r   r    )r    )r   )r-   rA   rP   rt   euler_matrix_new)r6   r!   r9   rJ   Zmatrotr   r   r   rE   X  s      rE   c             C   s   t | }|d |d kr(td}d}ntjt}tt|}tjt}tt|}|dkrft}nP|dkrt|}nB|dkrt}n4|dkr|}n&|d	kr|}n|d
kr|}n
td|d}|||fS )a  Return the rotation matrix corresponding to coord systems given
    in coord.

    Usage: matconv,do_conv,normcoord = get_coordconv_matrix(coord)

    Input:
       - coord: a tuple with initial and final coord systems.
                See normalise_coord.
    Output:
       - matconv: the euler matrix for coord sys conversion
       - do_conv: True if matconv is not identity, False otherwise
       - normcoord: the tuple of initial and final coord sys.

    History: adapted from CGIS IDL library.
    r   r   r   F)r
   r	   )r	   r
   )r
   r   )r   r
   )r   r	   )r	   r   zWrong coord transform :T)	r.   rA   rB   Zlinalgr8   e2grG   e2qr&   )r7   r   ZmatconvrK   Zg2eZg2qZq2eZq2gr   r   r   rF   t  s.    

rF   c             C   sh  t j}d| }d| }d| }|dkrld}ddddd	d
g}	ddddddg}
ddddddg}ddddd
d	g}nDd}ddddddg}	ddddddg}
ddd d d!d!g}ddddddg}|d }| | ||  }|| }t |}t |}|t | }|
|  | || |  }t || }t || | |
| |  |t | }t ||	|  | || }||fS )"a  
    NAME:
        euler
    PURPOSE:
        Transform between Galactic, celestial, and ecliptic coordinates.
    EXPLANATION:
        Use the procedure ASTRO to use this routine interactively

    CALLING SEQUENCE:
         EULER, AI, BI, AO, BO, [ SELECT, /FK4, SELECT = ]

    INPUTS:
          AI - Input Longitude in DEGREES, scalar or vector.  If only two
                  parameters are supplied, then  AI and BI will be modified
                  to contain the output longitude and latitude.
          BI - Input Latitude in DEGREES

    OPTIONAL INPUT:
          SELECT - Integer (1-6) specifying type of coordinate
                   transformation.

         SELECT   From          To        |   SELECT      From         To
          1     RA-Dec (2000)  Galactic   |     4       Ecliptic     RA-Dec
          2     Galactic       RA-DEC     |     5       Ecliptic    Galactic
          3     RA-Dec         Ecliptic   |     6       Galactic    Ecliptic

         If not supplied as a parameter or keyword, then EULER will prompt
         for the value of SELECT
         Celestial coordinates (RA, Dec) should be given in equinox J2000
         unless the /FK4 keyword is set.
    OUTPUTS:
          AO - Output Longitude in DEGREES
          BO - Output Latitude in DEGREES

    INPUT KEYWORD:
          /FK4 - If this keyword is set and non-zero, then input and output
                celestial and ecliptic coordinates should be given in
                equinox B1950.
          /SELECT  - The coordinate conversion integer (1-6) may
                     alternatively be specified as a keyword
    NOTES:
          EULER was changed in December 1998 to use J2000 coordinates as the
          default, ** and may be incompatible with earlier versions***.
    REVISION HISTORY:
          Written W. Landsman,  February 1987
          Adapted from Fortran by Daryl Yentis NRL
          Converted to IDL V5.0   W. Landsman   September 1997
          Made J2000 the default, added /FK4 keyword
           W. Landsman December 1998
          Add option to specify SELECT as a keyword W. Landsman March 2003
          Converted to python by K. Ganga December 2007
    g       @g      @g     f@r   z(B1950)g"d@n?gtk@g        gݤĉ}?gSGY@gsh?gshgXv?gXvٿgk?gkggPs?gF[?g/2c?z(J2000)g+d?g~*P@gG8h?gt@gI1Lz?gI1Lzg,P.u?g,P.uٿgu*?gu*gǌ.?g;hW\?gotB?)rA   r   r   r   Zarcsinrv   fmod)ZaiZbiselectZFK4ZPIZtwopiZfourpiZ
deg_to_radZequinoxpsiZsthetaZcthetar   r?   rU   re   sbcbZcbsaZboZaor   r   r   euler  s    ?

*r   c             C   s  d}|r|d }|r|d }|dkr,t dd}|r>tjd }t| | }	t| | }
t|| }t|| }t|| }t|| }|rt|	|
 dg|
|	dgdddgg}t|d|gdddg| d|gg}tdddgd|| gd||gg}n|rzt|	|
 dg|
|	dgdddgg}t|d|gdddg| d|gg}t|| dg||dgdddgg}nlt|	|
 dg|
|	dgdddgg}tdddgd|| gd||gg}t|| dg||dgdddgg}t|jt|j|j}|S )aG  
    NAME:
      euler_matrix_new

    PURPOSE:
      computes the Euler matrix of an arbitrary rotation described
      by 3 Euler angles
      correct bugs present in Euler_Matrix

    CALLING SEQUENCE:
      result = euler_matrix_new (a1, a2, a3 [,X, Y, ZYX, DEG ])

    INPUTS:
      a1, a2, a3 = Euler angles, scalar
                   (in radian by default, in degree if DEG is set)
                   all the angles are measured counterclockwise
                   correspond to x, y, zyx-conventions (see Goldstein)
                   the default is x

    KEYWORD PARAMETERS:
       DEG : if set the angle are measured in degree

       X :       rotation a1 around original Z
                 rotation a2 around interm   X
                 rotation a3 around final    Z
                 DEFAULT,  classical mechanics convention

       Y :       rotation a1 around original Z
                 rotation a2 around interm   Y
                 rotation a3 around final    Z
                 quantum mechanics convention (override X)

       ZYX :     rotation a1 around original Z
                 rotation a2 around interm   Y
                 rotation a3 around final    X
                 aeronautics convention (override X)

       * these last three keywords are obviously mutually exclusive *

    OUTPUTS:
       result is a 3x3 matrix

    USAGE:
      if vec is an Nx3 array containing N 3D vectors,
      vec # euler_matrix_new(a1,a2,a3,/Y) will be the rotated vectors


    MODIFICATION HISTORY:
       March 2002, EH, Caltech, rewritting of euler_matrix

       convention   euler_matrix_new           euler_matrix
      X:       M_new(a,b,c,/X)  =  M_old(-a,-b,-c,/X) = Transpose( M_old(c, b, a,/X))
      Y:       M_new(a,b,c,/Y)  =  M_old(-a, b,-c,/Y) = Transpose( M_old(c,-b, a,/Y))
    ZYX:       M_new(a,b,c,/Z)  =  M_old(-a, b,-c,/Z)
    r   r   z$Choose either X, Y or ZYX conventiong      ?g     f@)r&   rA   r   r   r   rS   rG   rH   )Za1Za2a3r   r    r   r!   Zt_kr   c1s1c2s2c3Zs3m1m2Zm3Mr   r   r   r   j  s:    9
$$&$$&$$$r   c             C   s   t | }|d |d kr*td\}}}ntd\}}}t|d}||||gj\}	}
}|	tt|	|	 }	|
tt|
|
 }
|tt|| }t|
d |	d  }t	t||}t|d |d }|||fS )a  Return the ZYZ Euler angles corresponding to a rotation between
    the two coordinate systems.  The angles can be used in rotate_alm.

    Parameters
    ----------
    coord : a tuple with initial and final coord systems.
      See normalise_coord.

    Returns
    -------
    psi, theta, phi :  floats
       The Euler angles defining a ZYZ rotation between the coordinate
        systems.

    Examples
    --------
    >>> np.array(coordsys2euler_zyz('GE'))
    array([ 1.4593747 ,  1.05048844, -3.14118737])
    >>> np.array(coordsys2euler_zyz('CG'))
    array([-0.22444029,  1.09731902,  2.14556673])
    >>> np.array(coordsys2euler_zyz('E'))
    array([ 0.,  0.,  0.])
    r   r   r   )r7   rY   )
r.   rA   rt   eyer   rH   r   rG   rv   r   )r7   r   r   r   r   ZxinZyinZzinr6   ZxoutZyoutZzoutr   r   r   coordsys2euler_zyz  s    
r   )NNT)NTF)NNF)NF)F)F)Fr   )r   )TFFF)1numpyrA   logging	getLoggerr2   Zastropy.coordinatesr   Zastropy.utils.decoratorsr   ro   r   r   Z	_sphtoolsr   rp   r   r   r   r   Zastropy_ecliptic_framelowerZtransform_todataZto_cartesianZget_xyzvaluer   r   Warningr   r   warningsfilterwarningsobjectr   r]   r\   r   ru   r   r   r   r.   r-   rE   rF   r   r   r   r   r   r   r   <module>   s^   
   R
)
 
/
$
?

R
 %
g