a
    ߙfb+                    @   s@  d Z ddlZddlZddl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m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 g dZi Zi Ze  Z!da"dd Z#dd Z$dd Z%dCddZ&G dd deZ'G dd deZ(dd Z)G dd de'Z*G dd de(Z+G dd  d e+Z,G d!d" d"e+Z-G d#d$ d$e+Z.d%d& Z/G d'd( d(e+Z0G d)d* d*e+Z1G d+d, d,e+Z2G d-d. d.e(Z3G d/d0 d0e3Z4G d1d2 d2e3Z5G d3d4 d4e5Z6G d5d6 d6e5Z7G d7d8 d8e3Z8G d9d: d:e8Z9G d;d< d<e8Z:G d=d> d>e3Z;G d?d@ d@e3Z<G dAdB dBe3Z=dS )Dz
In this module, we define the coordinate representation classes, which are
used to represent low-level cartesian, spherical, cylindrical, and other
coordinates.
    N)ufunc   )Angle	LongitudeLatitude)Distance)is_O3)ShapedLikeNDArrayclassproperty)	MixinInfo)DuplicateRepresentationWarning) BaseRepresentationOrDifferentialBaseRepresentationCartesianRepresentationSphericalRepresentationUnitSphericalRepresentationRadialRepresentationPhysicsSphericalRepresentationCylindricalRepresentationBaseDifferentialCartesianDifferentialBaseSphericalDifferentialBaseSphericalCosLatDifferentialSphericalDifferentialSphericalCosLatDifferentialUnitSphericalDifferentialUnitSphericalCosLatDifferentialRadialDifferentialCylindricalDifferentialPhysicsSphericalDifferentialc                 C   s   | j d | j S )z) Get the fully qualified name of a class .)
__module____qualname__cls r%   Alib/python3.9/site-packages/astropy/coordinates/representation.py
_fqn_class0   s    r'   c                   C   s,   t du r(ttt ttt  a t S )z
    Returns a hash value that should be invariable if the
    `REPRESENTATION_CLASSES` and `DIFFERENTIAL_CLASSES` dictionaries have not
    changed.
    N)_REPRDIFF_HASHhashtupleREPRESENTATION_CLASSESitemsDIFFERENTIAL_CLASSESr%   r%   r%   r&   get_reprdiff_cls_hash5   s
    r.   c                   C   s   d a d S N)r(   r%   r%   r%   r&   _invalidate_reprdiff_cls_hashB   s    r0    c                 C   s$   d|d}i |d< t j| fi |S )N, )Z	separatorprefixZ	formatter)npZarray2string)valuesr3   kwargsr%   r%   r&   _array2stringG   s    
r7   c                   @   sH   e Zd ZdZdhZdZedd Zedd Z	edd	 Z
dddZdS )$BaseRepresentationOrDifferentialInfoz
    Container for meta information like name, description, format.  This is
    required when the object is used as a mixin column within a table, but can
    be used as a general way to store meta information.
    unitFc                    sd    j }t fdd|D }tt dddd t||D }t||D ]\}}|||< qJt|S )Nc                 3   s   | ]}t  |jV  qd S r/   )getattrvalue.0	componentvalr%   r&   	<genexpr>\       zFBaseRepresentationOrDifferentialInfo.default_format.<locals>.<genexpr>shaper%   c                 S   s   g | ]\}}||j fqS r%   dtype)r=   r>   r;   r%   r%   r&   
<listcomp>^   rB   zGBaseRepresentationOrDifferentialInfo.default_format.<locals>.<listcomp>)
componentsr*   r4   emptyr:   zipstr)r@   rG   r5   ar>   r;   r%   r?   r&   default_formatX   s    
z3BaseRepresentationOrDifferentialInfo.default_formatc                 C   s   | j jS r/   )_parentrG   selfr%   r%   r&   _represent_as_dict_attrsd   s    z=BaseRepresentationOrDifferentialInfo._represent_as_dict_attrsc                 C   s0   | j d u rd S | j j}|dr,|dd S |S )N(r   )rM   _unitstr
startswith)rO   r9   r%   r%   r&   r9   h   s    
z)BaseRepresentationOrDifferentialInfo.unitwarnNc                 C   s   |  |||d}tj|tjd}|d | }|dd D ]D}z|d |d< W q8 tyz }	 ztd|	W Y d}	~	q8d}	~	0 0 q8dD ]}
|
|v rt|j|
||
  q|S )a  
        Return a new instance like ``reps`` with ``length`` rows.

        This is intended for creating an empty column object whose elements can
        be set in-place for table operations like join or vstack.

        Parameters
        ----------
        reps : list
            List of input representations or differentials.
        length : int
            Length of the output column object
        metadata_conflicts : str ('warn'|'error'|'silent')
            How to handle metadata conflicts
        name : str
            Output column name

        Returns
        -------
        col : `BaseRepresentation` or `BaseDifferential` subclass instance
            Empty instance of this class consistent with ``cols``

        )metadescriptionrD   r   r   Nz'input representations are inconsistent.)namerV   rW   )Zmerge_cols_attributesr4   ZzerosZint64	Exception
ValueErrorsetattrinfo)rO   ZrepslengthZmetadata_conflictsrX   attrsZindexesoutreperrattrr%   r%   r&   new_likep   s    
"z-BaseRepresentationOrDifferentialInfo.new_like)rU   N)__name__r!   r"   __doc__Zattrs_from_parentZ_supports_indexingstaticmethodrL   propertyrP   r9   rc   r%   r%   r%   r&   r8   O   s   


r8   c                       s>  e Zd ZdZdZe Zdd Zedd Z	ee
jdd Ze
jd	d
 Zedd Zdd Zdd Z fddZdd Zedd Zejdd Ze
jdd Zdd Zdd Zdd Zd d! Zd"d# Zd$d% Ze
jd;d'd(Zd)d* Zd+d, Zd-d. Z d/d0 Z!ed1d2 Z"ed3d4 Z#ed5d6 Z$d7d8 Z%d9d: Z&  Z'S )<r   a  3D coordinate representations and differentials.

    Parameters
    ----------
    comp1, comp2, comp3 : `~astropy.units.Quantity` or subclass
        The components of the 3D point or differential.  The names are the
        keys and the subclasses the values of the ``attr_classes`` attribute.
    copy : bool, optional
        If `True` (default), arrays will be copied; if `False`, they will be
        broadcast together but not use new memory.
    iP  c           
   
      sL  t |}j}|rt|d jrtdd |dd  D r|d |dd fdd|D }d	jv rtj_|rtd
| ng }|D ]p}z|r|dn||}W n" t	y   td|d Y n0 |d u rtd|djj
 d|| q|r|dn
|dd |r2td| |rj|D ]}||v r<td|q<td|  fddt||D }ztj|ddi}W np ty } zVt|dkrd|}	nd|d d d |d  }	td|	 d|W Y d }~n
d }~0 0  fddt||D }t||D ]\}}td| | q,d S )Nr   c                 s   s   | ]}|d u V  qd S r/   r%   )r=   argr%   r%   r&   rA      rB   z<BaseRepresentationOrDifferential.__init__.<locals>.<genexpr>r   copyTc                    s   g | ]}t  |qS r%   r:   r<   )rep_or_diffr%   r&   rF      s   z=BaseRepresentationOrDifferential.__init__.<locals>.<listcomp>r\   zIunexpected keyword arguments for case where class instance is passed in: z3__init__() missing 1 required positional argument: z- (or first argument should be an instance of z).zunexpected arguments: z,__init__() got multiple values for argument zunexpected keyword arguments: c                    s$   g | ]\}}j | | d dqS )Tri   subok)attr_classes)r=   r>   rb   )ri   rO   r%   r&   rF      s   rm      z and r2   z, and zInput parameters z cannot be broadcastc                    s0   g | ](\}}|j |j kr( r$| q*|n|qS r%   )rC   ri   )r=   rb   Zbc_attrri   r%   r&   rF      s   _)listrG   
isinstance	__class__allpop__dict__r\   	TypeErrorKeyErrorrd   appendrI   r4   Zbroadcast_arraysrZ   lenjoinr[   )
rO   argsr6   rG   r^   r>   rb   Zbc_attrsra   Zc_strr%   )ri   rk   rO   r&   __init__   st    




(
z)BaseRepresentationOrDifferential.__init__c                 C   s<   | j  }|dr"|dd }n|dr8|dd }|S )a  Name of the representation or differential.

        In lower case, with any trailing 'representation' or 'differential'
        removed. (E.g., 'spherical' for
        `~astropy.coordinates.SphericalRepresentation` or
        `~astropy.coordinates.SphericalDifferential`.)
        representationNidifferentiali)rd   lowerendswith)r$   rX   r%   r%   r&   get_name  s    	


z)BaseRepresentationOrDifferential.get_namec                 C   s
   t  dS )am  Create a representation of this class from a supplied Cartesian one.

        Parameters
        ----------
        other : `CartesianRepresentation`
            The representation to turn into this class

        Returns
        -------
        representation : `BaseRepresentation` subclass instance
            A new representation of this class's type.
        NNotImplementedErrorr$   otherr%   r%   r&   from_cartesian  s    z/BaseRepresentationOrDifferential.from_cartesianc                 C   s
   t  dS )a  Convert the representation to its Cartesian form.

        Note that any differentials get dropped.
        Also note that orientation information at the origin is *not* preserved by
        conversions through Cartesian coordinates. For example, transforming
        an angular position defined at distance=0 through cartesian coordinates
        and back will lose the original angular coordinates::

            >>> import astropy.units as u
            >>> import astropy.coordinates as coord
            >>> rep = coord.SphericalRepresentation(
            ...     lon=15*u.deg,
            ...     lat=-11*u.deg,
            ...     distance=0*u.pc)
            >>> rep.to_cartesian().represent_as(coord.SphericalRepresentation)
            <SphericalRepresentation (lon, lat, distance) in (rad, rad, pc)
                (0., 0., 0.)>

        Returns
        -------
        cartrepr : `CartesianRepresentation`
            The representation in Cartesian form.
        Nr   rN   r%   r%   r&   to_cartesian*  s    z-BaseRepresentationOrDifferential.to_cartesianc                 C   s
   t | jS )z=A tuple with the in-order names of the coordinate components.)r*   rn   rN   r%   r%   r&   rG   F  s    z+BaseRepresentationOrDifferential.componentsc              
   C   s   | j |j ur(td| j j d|j j zt| | W n4 tyl } ztd| |W Y d}~n
d}~0 0 d}| jD ]$}|t| d| t|d| kM }qx|S )zEquality operator

        This implements strict equality and requires that the representation
        classes are identical and that the representation data are exactly equal.
        z.cannot compare: objects must have same class:  vs. zcannot compare: NTrq   )rt   rx   rd   r4   Z	broadcastrZ   rG   r:   )rO   r;   excr_   compr%   r%   r&   __eq__K  s    &
"z'BaseRepresentationOrDifferential.__eq__c                 C   s   t | |kS r/   r4   Zlogical_notrO   r;   r%   r%   r&   __ne__a  s    z'BaseRepresentationOrDifferential.__ne__c                    s|   t r fdd}ntjg R i }t | j}| jD ]}t|d| |t| | qFd| j	v rx| j
|_
|S )aJ  Create a new representation or differential with ``method`` applied
        to the component data.

        In typical usage, the method is any of the shape-changing methods for
        `~numpy.ndarray` (``reshape``, ``swapaxes``, etc.), as well as those
        picking particular elements (``__getitem__``, ``take``, etc.), which
        are all defined in `~astropy.utils.shapes.ShapedLikeNDArray`. It will be
        applied to the underlying arrays (e.g., ``x``, ``y``, and ``z`` for
        `~astropy.coordinates.CartesianRepresentation`), with the results used
        to create a new instance.

        Internally, it is also used to apply functions to the components
        (in particular, `~numpy.broadcast_to`).

        Parameters
        ----------
        method : str or callable
            If str, it is the name of a method that is applied to the internal
            ``components``. If callable, the function is applied.
        *args : tuple
            Any positional arguments for ``method``.
        **kwargs : dict
            Any keyword arguments for ``method``.
        c                    s   | g R i S r/   r%   )Zarrayr}   r6   methodr%   r&   <lambda>~  rB   z9BaseRepresentationOrDifferential._apply.<locals>.<lambda>rq   r\   )callableoperatormethodcallersuper__new__rt   rG   r[   r:   rw   r\   )rO   r   r}   r6   Zapply_methodnewr>   rt   r   r&   _applyd  s    


z'BaseRepresentationOrDifferential._applyc                 C   sT   |j | j ur(td| j j d|j j | jD ] }t|d| t| d| |< q.d S )Nz(can only set from object of same class: r   rq   )rt   rx   rd   rG   r:   )rO   itemr;   r>   r%   r%   r&   __setitem__  s    
z,BaseRepresentationOrDifferential.__setitem__c                 C   s   t | | jd jS )a  The shape of the instance and underlying arrays.

        Like `~numpy.ndarray.shape`, can be set to a new shape by assigning a
        tuple.  Note that if different instances share some but not all
        underlying data, setting the shape of one instance can make the other
        instance unusable.  Hence, it is strongly recommended to get new,
        reshaped instances with the ``reshape`` method.

        Raises
        ------
        ValueError
            If the new shape has the wrong total number of elements.
        AttributeError
            If the shape of any of the components cannot be changed without the
            arrays being copied.  For these cases, use the ``reshape`` method
            (which copies any arrays that cannot be reshaped in-place).
        r   )r:   rG   rC   rN   r%   r%   r&   rC     s    z&BaseRepresentationOrDifferential.shapec              	   C   sh   g }| j }| jD ]R}t| |}|jdkrz
||_ W n$ tyV   |D ]
}||_ qD Y q0 || qd S )Nr   )rC   rG   r:   sizerY   rz   )rO   rC   ZreshapedZoldshaper>   r@   Zval2r%   r%   r&   rC     s    



c                 G   s
   t  d S r/   r   rO   opr}   r%   r%   r&   _scale_operation  s    z1BaseRepresentationOrDifferential._scale_operationc                 C   s   |  tj|S r/   )r   r   mulrO   r   r%   r%   r&   __mul__  s    z(BaseRepresentationOrDifferential.__mul__c                 C   s
   |  |S r/   )r   r   r%   r%   r&   __rmul__  s    z)BaseRepresentationOrDifferential.__rmul__c                 C   s   |  tj|S r/   r   r   truedivr   r%   r%   r&   __truediv__  s    z,BaseRepresentationOrDifferential.__truediv__c                 C   s   |  tj|S r/   r   r   r%   r%   r&   __div__  s    z(BaseRepresentationOrDifferential.__div__c                 C   s   |  tjS r/   )r   r   negrN   r%   r%   r&   __neg__  s    z(BaseRepresentationOrDifferential.__neg__c                 C   s   |   S r/   rp   rN   r%   r%   r&   __pos__  s    z(BaseRepresentationOrDifferential.__pos__Fc                 C   s
   t  d S r/   r   rO   r   r   reverser%   r%   r&   _combine_operation  s    z3BaseRepresentationOrDifferential._combine_operationc                 C   s   |  tj|S r/   r   r   addr   r%   r%   r&   __add__  s    z(BaseRepresentationOrDifferential.__add__c                 C   s   | j tj|ddS NT)r   r   r   r%   r%   r&   __radd__  s    z)BaseRepresentationOrDifferential.__radd__c                 C   s   |  tj|S r/   r   r   subr   r%   r%   r&   __sub__  s    z(BaseRepresentationOrDifferential.__sub__c                 C   s   | j tj|ddS r   r   r   r%   r%   r&   __rsub__  s    z)BaseRepresentationOrDifferential.__rsub__c                    sH    fdd j D }t jdd |D }|D ]\}}|j||< q0|S )zTurn the coordinates into a record array with the coordinate values.

        The record array fields will have the component names.
        c                    s   g | ]}|t  |fqS r%   rj   r=   crN   r%   r&   rF     rB   z<BaseRepresentationOrDifferential._values.<locals>.<listcomp>c                 S   s   g | ]\}}||j fqS r%   rD   )r=   r   coor%   r%   r&   rF     rB   )rG   r4   rH   rC   r;   )rO   Z	coo_itemsresultr   r   r%   rN   r&   _values  s
    z(BaseRepresentationOrDifferential._valuesc                    s   t  fdd jD S )z@Return a dictionary with the units of the coordinate components.c                    s   g | ]}|t  |jfqS r%   )r:   r9   r<   rN   r%   r&   rF     s   z;BaseRepresentationOrDifferential._units.<locals>.<listcomp>)dictrG   rN   r%   rN   r&   _units  s    z'BaseRepresentationOrDifferential._unitsc                    sL   t  j }t|dkr(|  }n dd fdd jD }|S )Nr   z({})r2   c                    s   g | ]} j |  qS r%   )r   	to_stringr<   rN   r%   r&   rF     s   z=BaseRepresentationOrDifferential._unitstr.<locals>.<listcomp>)	setr   r5   r{   rv   r   formatr|   rG   )rO   Z	units_setunitstrr%   rN   r&   rS     s    z)BaseRepresentationOrDifferential._unitstrc                 C   s   t | j d| jdS )N s)r7   r   rS   rN   r%   r%   r&   __str__	  s    z(BaseRepresentationOrDifferential.__str__c                 C   sv   d}t | j|d}d}t| dd rBdddd | j D }| jrRd	| j nd
}d| jj	d| j
||||S )Nz    )r3   r1   differentialsz 
 (has differentials w.r.t.: {})r2   c                 S   s   g | ]}t |qS r%   )repr)r=   keyr%   r%   r&   rF     rB   z=BaseRepresentationOrDifferential.__repr__.<locals>.<listcomp>zin z[dimensionless]z<{} ({}) {:s}
{}{}{}>)r7   r   r:   r   r|   r   keysrS   rt   rd   rG   )rO   Z	prefixstrZarrstrZdiffstrr   r%   r%   r&   __repr__  s    z)BaseRepresentationOrDifferential.__repr__)F)(rd   r!   r"   re   Z__array_priority__r8   r\   r~   classmethodr   abcabstractmethodr   r   rg   rG   r   r   r   r   rC   setterr   r   r   r   r   r   r   r   r   r   r   r   r   r   rS   r   r   __classcell__r%   r%   r   r&   r      sV   O


+	






r   c                    s   d    fdd}|S )a  Make an attribute getter for use in a property.

    Parameters
    ----------
    component : str
        The name of the component that should be accessed.  This assumes the
        actual value is stored in an attribute of that name prefixed by '_'.
    rq   c                    s
   t |  S r/   rj   rN   r>   r%   r&   get_component(  s    z#_make_getter.<locals>.get_componentr%   )r>   r   r%   r   r&   _make_getter  s    r   c                       s:   e Zd Ze fddZd fdd	Z fddZ  ZS )	RepresentationInfoc                    s   t  j}| jjr|d7 }|S )Nr   )r   rP   rM   _differentials)rO   r^   r   r%   r&   rP   /  s    z+RepresentationInfo._represent_as_dict_attrsNc                    s8   t  |}|di  D ]\}}||d| < q|S )Nr   differentials.)r   _represent_as_dictrv   r,   )rO   r^   r_   r   r;   r   r%   r&   r   6  s    z%RepresentationInfo._represent_as_dictc                    sJ   i }t | D ]$}|dr||||dd  < q||d< t |S )Nr      r   )rr   r   rT   rv   r   _construct_from_dict)rO   mapr   r   r   r%   r&   r   <  s    
z'RepresentationInfo._construct_from_dict)N)rd   r!   r"   rg   rP   r   r   r   r%   r%   r   r&   r   -  s   r   c                       s  e Zd ZdZe Z fddZdd fdd
Zdd	 Zd
d Z	e
dd Zedd Zdd Zdd Zdd Zd9ddZdd Zdd Zdd Zedd Z fd d!Zd"d# Z fd$d%Z fd&d'Zd(d) Zd:d+d,Zejjd-d. Zd/d0 Z d1d2 Z!d3d4 Z"d5d6 Z#d7d8 Z$  Z%S );r   a  Base for representing a point in a 3D coordinate system.

    Parameters
    ----------
    comp1, comp2, comp3 : `~astropy.units.Quantity` or subclass
        The components of the 3D points.  The names are the keys and the
        subclasses the values of the ``attr_classes`` attribute.
    differentials : dict, `~astropy.coordinates.BaseDifferential`, optional
        Any differential classes that should be associated with this
        representation. The input must either be a single `~astropy.coordinates.BaseDifferential`
        subclass instance, or a dictionary with keys set to a string
        representation of the SI unit with which the differential (derivative)
        is taken. For example, for a velocity differential on a positional
        representation, the key would be ``'s'`` for seconds, indicating that
        the derivative is a time derivative.
    copy : bool, optional
        If `True` (default), arrays will be copied. If `False`, arrays will
        be references, though possibly broadcast to ensure matching shapes.

    Notes
    -----
    All representation classes should subclass this base representation class,
    and define an ``attr_classes`` attribute, a `dict`
    which maps component names to the class that creates them. They must also
    define a ``to_cartesian`` method and a ``from_cartesian`` class method. By
    default, transformations are done via the cartesian system, but classes
    that want to define a smarter transformation path can overload the
    ``represent_as`` method. If one wants to use an associated differential
    class, one should also define ``unit_vectors`` and ``scale_factors``
    methods (see those methods for details).
    c              	      s@  | j dkrd S t| ds td|  }|tv rt| t| }t| }t|}||krjtd| dd| d| d| d}t	
|t t|= |t|< |}nD|tv rt| }t	
d| d	| d
 |}|tv rtd| d| t|< t  | jD ].}t| |st| |tt|d| dd qt jf i | d S )Nr   rn   z<Representations must have an "attr_classes" class attribute.zRepresentation "z" already definedzA" already defined, removing it to avoid confusion.Use qualnames "z" and "z" or class instances directlyz#" already defined, using qualname "z".zThe 'z' component of the points(s).doc)rd   hasattrr   r   r+   DUPLICATE_REPRESENTATIONSr   r'   rZ   warningsrU   r   r0   rn   r[   rg   r   r   __init_subclass__)r$   r6   	repr_nameZfqn_clsexistingZfqn_existingmsgr>   r   r%   r&   r   h  sT    







z$BaseRepresentation.__init_subclass__Nr   c                   sH   t  j|i | |d u r8|r8t|d | jr8|d j}| || _d S )Nr   )r   r~   rs   rt   r   _validate_differentials)rO   r   r}   r6   r   r%   r&   r~     s    
zBaseRepresentation.__init__c                 C   s   |du rt  }n8t|trHt|tr6t| tr6td|| }||i}|D ]}z|| }W n. ty } ztd|W Y d}~n
d}~0 0 ||  t|trt| trn(|| }||krtd	t
||||j| jkrLtd	|j| jqL|S )a  
        Validate that the provided differentials are appropriate for this
        representation and recast/reshape as necessary and then return.

        Note that this does *not* set the differentials on
        ``self._differentials``, but rather leaves that for the caller.
        NzvTo attach a RadialDifferential to a UnitSphericalRepresentation, you must supply a dictionary with an appropriate key.z9'differentials' argument must be a dictionary-like objectzNFor differential object '{}', expected unit key = '{}' but received key = '{}'zUShape of differentials must be the same as the shape of the representation ({} vs {}))r   rs   r   r   r   rZ   _get_deriv_keyrx   _check_baser   r   rC   )rO   r   r   diffra   Zexpected_keyr%   r%   r&   r     s>    







z*BaseRepresentation._validate_differentialsc                 C   s   | j rtd|| jjdS )z
        Used to raise a consistent exception for any operation that is not
        supported when a representation has differentials attached.
        zHOperation '{}' is not supported when differentials are attached to a {}.N)r   rx   r   rt   rd   )rO   Zop_namer%   r%   r&   _raise_if_has_differentials  s    z.BaseRepresentation._raise_if_has_differentialsc                 C   s   t |   gS r/   )r-   r   r#   r%   r%   r&   _compatible_differentials  s    z,BaseRepresentation._compatible_differentialsc                 C   s   | j S )a  A dictionary of differential class instances.

        The keys of this dictionary must be a string representation of the SI
        unit with which the differential (derivative) is taken. For example, for
        a velocity differential on a positional representation, the key would be
        ``'s'`` for seconds, indicating that the derivative is a time
        derivative.
        )r   rN   r%   r%   r&   r     s    
z BaseRepresentation.differentialsc                 C   s   t t|  ddS )a  Cartesian unit vectors in the direction of each component.

        Given unit vectors :math:`\hat{e}_c` and scale factors :math:`f_c`,
        a change in one component of :math:`\delta c` corresponds to a change
        in representation of :math:`\delta c \times f_c \times \hat{e}_c`.

        Returns
        -------
        unit_vectors : dict of `CartesianRepresentation`
            The keys are the component names.
        z! has not implemented unit vectorsNr   typerN   r%   r%   r&   unit_vectors  s    zBaseRepresentation.unit_vectorsc                 C   s   t t|  ddS )a  Scale factors for each component's direction.

        Given unit vectors :math:`\hat{e}_c` and scale factors :math:`f_c`,
        a change in one component of :math:`\delta c` corresponds to a change
        in representation of :math:`\delta c \times f_c \times \hat{e}_c`.

        Returns
        -------
        scale_factors : dict of `~astropy.units.Quantity`
            The keys are the component names.
        z# has not implemented scale factors.Nr   rN   r%   r%   r&   scale_factors  s    z BaseRepresentation.scale_factorsc                 C   s
  |du rt  S | js"|r"tdn\t| jdkr\t|r\t|tr\t| j	 d |i}n"|	 | j	 kr~td
| jt  }| jD ]z}| j| }z|j|| | d||< W q ty } z6|| |jvrtd
|| |j|n W Y d}~qd}~0 0 q|S )zRe-represent the differentials to the specified classes.

        This returns a new dictionary with the same keys but with the
        attached differentials converted to the new differential classes.
        Nz5No differentials associated with this representation!r   r   zDesired differential classes must be passed in as a dictionary with keys equal to a string representation of the unit of the derivative for each differential stored with this representation object ({0})basezXDesired differential class {} is not compatible with the desired representation class {})r   r   rZ   r{   inspectisclass
issubclassr   rr   r   r   represent_asrY   r   rx   rt   )rO   new_repdifferential_class	new_diffskr   ra   r%   r%   r&   _re_represent_differentials  sD    




z.BaseRepresentation._re_represent_differentialsc                 C   s\   || j u r|s|  S t|tr(td|| j urB||  }n| }| |||_|S dS )a  Convert coordinates to another representation.

        If the instance is of the requested class, it is returned unmodified.
        By default, conversion is done via Cartesian coordinates.
        Also note that orientation information at the origin is *not* preserved by
        conversions through Cartesian coordinates. See the docstring for
        :meth:`~astropy.coordinates.BaseRepresentationOrDifferential.to_cartesian`
        for an example.

        Parameters
        ----------
        other_class : `~astropy.coordinates.BaseRepresentation` subclass
            The type of representation to turn the coordinates into.
        differential_class : dict of `~astropy.coordinates.BaseDifferential`, optional
            Classes in which the differentials should be represented.
            Can be a single class if only a single differential is attached,
            otherwise it should be a `dict` keyed by the same keys as the
            differentials.
        zfInput to a representation's represent_as must be a class, not a string. For strings, use frame objectsN)	rt   without_differentialsrs   rJ   rZ   r   r   r   r   )rO   other_classr   r   r%   r%   r&   r   M  s    

zBaseRepresentation.represent_asc                 C   sN   dd | j  D }| jt|d|}dd | j  D }|| j|}|S )a  Transform coordinates using a 3x3 matrix in a Cartesian basis.

        This returns a new representation and does not modify the original one.
        Any differentials attached to this representation will also be
        transformed.

        Parameters
        ----------
        matrix : (3,3) array-like
            A 3x3 (or stack thereof) matrix, such as a rotation matrix.

        c                 S   s   i | ]
}|t qS r%   )r   )r=   r   r%   r%   r&   
<dictcomp>  rB   z0BaseRepresentation.transform.<locals>.<dictcomp>)r   c                 S   s   i | ]\}}||j qS r%   r   r=   r   r   r%   r%   r&   r     rB   )r   r   r   r   	transformr,   rt   )rO   matrixZdifs_clsZcrepr`   r%   r%   r&   r   u  s    zBaseRepresentation.transformc                    sJ   |s S  fdd j D } j| j dd}|j|| |S )a  
        Create a new representation with the same positions as this
        representation, but with these new differentials.

        Differential keys that already exist in this object's differential dict
        are overwritten.

        Parameters
        ----------
        differentials : sequence of `~astropy.coordinates.BaseDifferential` subclass instance
            The differentials for the new representation to have.

        Returns
        -------
        `~astropy.coordinates.BaseRepresentation` subclass instance
            A copy of this representation, but with the ``differentials`` as
            its differentials.
        c                    s   g | ]}t  |qS r%   rj   r<   rN   r%   r&   rF     rB   z9BaseRepresentation.with_differentials.<locals>.<listcomp>Fr   ri   )rG   rt   r   ri   r   updater   )rO   r   r}   r   r%   rN   r&   with_differentials  s    z%BaseRepresentation.with_differentialsc                    s.    j s
 S  fdd jD } j|ddiS )a>  Return a copy of the representation without attached differentials.

        Returns
        -------
        `~astropy.coordinates.BaseRepresentation` subclass instance
            A shallow copy of this representation, without any differentials.
            If no differentials were present, no copy is made.
        c                    s   g | ]}t  |qS r%   rj   r<   rN   r%   r&   rF     rB   z<BaseRepresentation.without_differentials.<locals>.<listcomp>ri   F)r   rG   rt   )rO   r}   r%   rN   r&   r     s    
z(BaseRepresentation.without_differentialsc                 C   s
   | | S )zCreate a new instance of this representation from another one.

        Parameters
        ----------
        representation : `~astropy.coordinates.BaseRepresentation` instance
            The presentation that should be converted to this class.
        )r   )r$   r   r%   r%   r&   from_representation  s    	z&BaseRepresentation.from_representationc                    sX   t  |}| j |j kr(tdt| j |j D ]\}}|||kM }q>|S )zEquality operator for BaseRepresentation

        This implements strict equality and requires that the representation
        classes are identical, the differentials are identical, and that the
        representation data are exactly equal.
        z4cannot compare: objects must have same differentials)r   r   r   r   rZ   rI   r5   )rO   r;   r_   	self_diffZ
value_diffr   r%   r&   r     s    
zBaseRepresentation.__eq__c                 C   s   t | |kS r/   r   r   r%   r%   r&   r     s    zBaseRepresentation.__ne__c                    s@   t  jg R i }t fdd| j D |_|S )a  Create a new representation with ``method`` applied to the component
        data.

        This is not a simple inherit from ``BaseRepresentationOrDifferential``
        because we need to call ``._apply()`` on any associated differential
        classes.

        See docstring for `BaseRepresentationOrDifferential._apply`.

        Parameters
        ----------
        method : str or callable
            If str, it is the name of a method that is applied to the internal
            ``components``. If callable, the function is applied.
        *args : tuple
            Any positional arguments for ``method``.
        **kwargs : dict
            Any keyword arguments for ``method``.

        c                    s,   g | ]$\}}||j g R i fqS r%   )r   r   r   r%   r&   rF     s   z-BaseRepresentation._apply.<locals>.<listcomp>)r   r   r   r   r,   )rO   r   r}   r6   r`   r   r   r&   r     s    zBaseRepresentation._applyc           	         s"  t |tstdt| dt || jsRt|jt| jksRtd| jj di }| j	r| j	
 |j	
 krxtd| j	 D ]Z\}}|j ||< }|j	| j}t ||st|jt|jkstd|d|jj dq|| j|}t || | j	 D ]\}}|j	| ||< qd S )Nz-value must be a representation instance, not r    zvalue must be representable as z without loss of information.z'value must have the same differentials.zvalue differential z must be representable as )rs   r   rx   r   rt   r{   rn   rZ   rd   r   r   r,   r   r   r   )	rO   r   r;   Zdiff_classesr   r  Zself_diff_clsZvalue_diff_clsr   r   r%   r&   r     s>    


zBaseRepresentation.__setitem__c                 G   s   g }| j  D ]>\}}t| |}t|tr6|| q|||g|R   qz| j| }W n tyr   t Y S 0 | j	 D ]*\}}	|	j
|g|R ddi}
|
|j	|< q~|S )ae  Scale all non-angular components, leaving angular ones unchanged.

        Parameters
        ----------
        op : `~operator` callable
            Operator to apply (e.g., `~operator.mul`, `~operator.neg`, etc.
        *args
            Any arguments required for the operator (typically, what is to
            be multiplied with, divided by).
        scaled_baseT)rn   r,   r:   r   r   rz   rt   rY   NotImplementedr   r   )rO   r   r}   Zresultsr>   r$   r;   r   r   r   Zdiff_resultr%   r%   r&   r     s    


z#BaseRepresentation._scale_operationFc                 C   s8   |  |j |  |||}|tu r*tS | |S dS )a#  Combine two representation.

        By default, operate on the cartesian representations of both.

        Parameters
        ----------
        op : `~operator` callable
            Operator to apply (e.g., `~operator.add`, `~operator.sub`, etc.
        other : `~astropy.coordinates.BaseRepresentation` subclass instance
            The other representation.
        reverse : bool
            Whether the operands should be reversed (e.g., as we got here via
            ``self.__rsub__`` because ``self`` is a subclass of ``other``).
        N)r   rd   r   r   r  r   rO   r   r   r   r   r%   r%   r&   r   =  s
    z%BaseRepresentation._combine_operationc                 C   sp   | j }tj | | z| jD ]}|| j| _ qW n: tyj   tj | | | jD ]}|| j| _ qR Y n0 d S r/   )rC   r   fsetr   rY   )rO   rC   Z
orig_shaper   r%   r%   r&   rC   U  s    

zBaseRepresentation.shapec                    s(   t ttj fdd j D S )  Vector norm.

        The norm is the standard Frobenius norm, i.e., the square root of the
        sum of the squares of all components with non-angular units.

        Note that any associated differentials will be dropped during this
        operation.

        Returns
        -------
        norm : `astropy.units.Quantity`
            Vector norm, with the same shape as the representation.
        c                 3   s*   | ]"\}}t |tst |d  V  qdS )ro   N)r   r   r:   )r=   r>   r$   rN   r%   r&   rA   v  s   
z*BaseRepresentation.norm.<locals>.<genexpr>)r4   Zsqrt	functoolsreducer   r   rn   r,   rN   r%   rN   r&   normg  s
    zBaseRepresentation.normc                 O   s$   |  d | |  j|i |S )ao  Vector mean.

        Averaging is done by converting the representation to cartesian, and
        taking the mean of the x, y, and z components. The result is converted
        back to the same representation as the input.

        Refer to `~numpy.mean` for full documentation of the arguments, noting
        that ``axis`` is the entry in the ``shape`` of the representation, and
        that the ``out`` argument cannot be used.

        Returns
        -------
        mean : `~astropy.coordinates.BaseRepresentation` subclass instance
            Vector mean, in the same representation as that of the input.
        mean)r   r   r   r  rO   r}   r6   r%   r%   r&   r  z  s    
zBaseRepresentation.meanc                 O   s$   |  d | |  j|i |S )a]  Vector sum.

        Adding is done by converting the representation to cartesian, and
        summing the x, y, and z components. The result is converted back to the
        same representation as the input.

        Refer to `~numpy.sum` for full documentation of the arguments, noting
        that ``axis`` is the entry in the ``shape`` of the representation, and
        that the ``out`` argument cannot be used.

        Returns
        -------
        sum : `~astropy.coordinates.BaseRepresentation` subclass instance
            Vector sum, in the same representation as that of the input.
        sum)r   r   r   r  r  r%   r%   r&   r    s    
zBaseRepresentation.sumc                 C   s   |   |S )a  Dot product of two representations.

        The calculation is done by converting both ``self`` and ``other``
        to `~astropy.coordinates.CartesianRepresentation`.

        Note that any associated differentials will be dropped during this
        operation.

        Parameters
        ----------
        other : `~astropy.coordinates.BaseRepresentation`
            The representation to take the dot product with.

        Returns
        -------
        dot_product : `~astropy.units.Quantity`
            The sum of the product of the x, y, and z components of the
            cartesian representations of ``self`` and ``other``.
        )r   dotr   r%   r%   r&   r    s    zBaseRepresentation.dotc                 C   s   |  d | |  |S )a  Vector cross product of two representations.

        The calculation is done by converting both ``self`` and ``other``
        to `~astropy.coordinates.CartesianRepresentation`, and converting the
        result back to the type of representation of ``self``.

        Parameters
        ----------
        other : `~astropy.coordinates.BaseRepresentation` subclass instance
            The representation to take the cross product with.

        Returns
        -------
        cross_product : `~astropy.coordinates.BaseRepresentation` subclass instance
            With vectors perpendicular to both ``self`` and ``other``, in the
            same type of representation as ``self``.
        cross)r   r   r   r  r   r%   r%   r&   r    s    
zBaseRepresentation.cross)N)F)&rd   r!   r"   re   r   r\   r   r~   r   r   r
   r   rg   r   r   r   r   r   r   r  r   r   r  r   r   r   r   r   r   r   rC   r   r  r  r  r  r  r   r%   r%   r   r&   r   E  s@    7=


0
(!

!

r   c                       s   e Zd ZdZejejejdZdZd! fdd	Zdd Z	d	d
 Z
d"ddZeeZedd Zdd Zdd Zd#ddZdd Zdd Zdd Zdd Zdd  Z  ZS )$r   a  
    Representation of points in 3D cartesian coordinates.

    Parameters
    ----------
    x, y, z : `~astropy.units.Quantity` or array
        The x, y, and z coordinates of the point(s). If ``x``, ``y``, and ``z``
        have different shapes, they should be broadcastable. If not quantity,
        ``unit`` should be set.  If only ``x`` is given, it is assumed that it
        contains an array with the 3 coordinates stored along ``xyz_axis``.
    unit : unit-like
        If given, the coordinates will be converted to this unit (or taken to
        be in this unit if not given.
    xyz_axis : int, optional
        The axis along which the coordinates are stored when a single array is
        provided rather than distinct ``x``, ``y``, and ``z`` (default: 0).

    differentials : dict, `CartesianDifferential`, optional
        Any differential classes that should be associated with this
        representation. The input must either be a single
        `CartesianDifferential` instance, or a dictionary of
        `CartesianDifferential` s with keys set to a string representation of
        the SI unit with which the differential (derivative) is taken. For
        example, for a velocity differential on a positional representation, the
        key would be ``'s'`` for seconds, indicating that the derivative is a
        time derivative.

    copy : bool, optional
        If `True` (default), arrays will be copied. If `False`, arrays will
        be references, though possibly broadcast to ensure matching shapes.
    xyzNTc                    s  |d u r|d u rt |tjr|jjdvrtj|||dd}|| _|rZt||d}|| _	nd| _	|\| _
| _| _| || _d S t |tr|d u r|d u r|d u r|j}t j|||dS |\}}}|d urtd|d u s|d u rtd| jj|d ur:tj|||dd}tj|||dd}tj|||dd}d}t j|||||d	 | j
j| jjrx| j
j| jjstd
d S )NOVTrl   r   r   z|xyz_axis should only be set if x, y, and z are in a single array passed in through x, i.e., y and z should not be not given.z*x, y, and z are required to instantiate {}Fri   r   z/x, y, and z should have matching physical types)rs   r4   ndarrayrE   kinduQuantity_xyzmoveaxis	_xyz_axis_x_y_zr   r   r   r   r~   rZ   r   rt   rd   r9   is_equivalent
UnitsError)rO   r  r  r  r9   xyz_axisr   ri   r   r%   r&   r~     sL    



z CartesianRepresentation.__init__c                 C   s`   t jdtj | jdd}t jdtj | jdd}t|||ddt|||ddt|||dddS )N      ?Trm           Frp   r  )r4   broadcast_tor  onerC   r   )rO   lor%   r%   r&   r   &  s    z$CartesianRepresentation.unit_vectorsc                 C   s$   t jdtj | jdd}|||dS )Nr%  Tr&  r  r4   r(  r  r)  rC   rO   r*  r%   r%   r&   r   .  s    z%CartesianRepresentation.scale_factorsr   c                 C   sF   | j dur,| j|kr| j S t| j | j|S tj| j| j| jg|dS )a  Return a vector array of the x, y, and z coordinates.

        Parameters
        ----------
        xyz_axis : int, optional
            The axis in the final array along which the x, y, z components
            should be stored (default: 0).

        Returns
        -------
        xyz : `~astropy.units.Quantity`
            With dimension 3 along ``xyz_axis``.  Note that, if possible,
            this will be a view.
        NZaxis)r  r  r4   r  stackr  r   r!  rO   r$  r%   r%   r&   get_xyz2  s
    

zCartesianRepresentation.get_xyzc                 C   s   |S r/   r%   r   r%   r%   r&   r   N  s    z&CartesianRepresentation.from_cartesianc                 C   s   | S r/   r%   rN   r%   r%   r&   r   R  s    z$CartesianRepresentation.to_cartesianc                    sN   t  jdd}j|dddt fddj D }|S )a  
        Transform the cartesian coordinates using a 3x3 matrix.

        This returns a new representation and does not modify the original one.
        Any differentials attached to this representation will also be
        transformed.

        Parameters
        ----------
        matrix : ndarray
            A 3x3 transformation matrix, such as a rotation matrix.

        Examples
        --------
        We can start off by creating a cartesian representation object:

            >>> from astropy import units as u
            >>> from astropy.coordinates import CartesianRepresentation
            >>> rep = CartesianRepresentation([1, 2] * u.pc,
            ...                               [2, 3] * u.pc,
            ...                               [3, 4] * u.pc)

        We now create a rotation matrix around the z axis:

            >>> from astropy.coordinates.matrix_utilities import rotation_matrix
            >>> rotation = rotation_matrix(30 * u.deg, axis='z')

        Finally, we can apply this transformation:

            >>> rep_new = rep.transform(rotation)
            >>> rep_new.xyz  # doctest: +FLOAT_CMP
            <Quantity [[ 1.8660254 , 3.23205081],
                       [ 1.23205081, 1.59807621],
                       [ 3.        , 4.        ]] pc>
        rR   r$  Fr$  ri   c                 3   s$   | ]\}}||  fV  qd S r/   r   r=   r   dr   r`   rO   r%   r&   rA   ~  s   z4CartesianRepresentation.transform.<locals>.<genexpr>)
erfa_ufuncrxpr1  rt   r   r   r,   r  )rO   r   pr   r%   r7  r&   r   U  s    %z!CartesianRepresentation.transformFc                    sf   |  j z| }W n ty.   t Y S 0 |s<| |fn|| f\ | j fdd jD  S )Nc                 3   s$   | ]}t  |t |V  qd S r/   rj   r<   firstr   secondr%   r&   rA     s   
z=CartesianRepresentation._combine_operation.<locals>.<genexpr>)r   rd   r   rY   r  rt   rG   )rO   r   r   r   other_cr%   r;  r&   r     s    
z*CartesianRepresentation._combine_operationc                 C   s   t | jddS )r	  rR   r2  )r8  Zpmr1  rN   r%   r%   r&   r    s    zCartesianRepresentation.normc                 O   s"   |  d | jdg|R i |S )aT  Vector mean.

        Returns a new CartesianRepresentation instance with the means of the
        x, y, and z components.

        Refer to `~numpy.mean` for full documentation of the arguments, noting
        that ``axis`` is the entry in the ``shape`` of the representation, and
        that the ``out`` argument cannot be used.
        r  r   r   r  r%   r%   r&   r    s    

zCartesianRepresentation.meanc                 O   s"   |  d | jdg|R i |S )aQ  Vector sum.

        Returns a new CartesianRepresentation instance with the sums of the
        x, y, and z components.

        Refer to `~numpy.sum` for full documentation of the arguments, noting
        that ``axis`` is the entry in the ``shape`` of the representation, and
        that the ``out`` argument cannot be used.
        r  r?  r  r%   r%   r&   r    s    

zCartesianRepresentation.sumc              
   C   sb   z|  }W n8 tyD } z tdt||W Y d}~n
d}~0 0 t| jdd|jddS )a  Dot product of two representations.

        Note that any associated differentials will be dropped during this
        operation.

        Parameters
        ----------
        other : `~astropy.coordinates.BaseRepresentation` subclass instance
            If not already cartesian, it is converted.

        Returns
        -------
        dot_product : `~astropy.units.Quantity`
            The sum of the product of the x, y, and z components of ``self``
            and ``other``.
        zLcannot only take dot product with another representation, not a {} instance.NrR   r2  )r   rY   rx   r   r   r8  Zpdpr1  )rO   r   r>  ra   r%   r%   r&   r    s    
zCartesianRepresentation.dotc              
   C   sz   |  d z| }W n8 tyN } z tdt||W Y d}~n
d}~0 0 t| jdd|jdd}| j	|ddS )a  Cross product of two representations.

        Parameters
        ----------
        other : `~astropy.coordinates.BaseRepresentation` subclass instance
            If not already cartesian, it is converted.

        Returns
        -------
        cross_product : `~astropy.coordinates.CartesianRepresentation`
            With vectors perpendicular to both ``self`` and ``other``.
        r  zNcannot only take cross product with another representation, not a {} instance.NrR   r2  )
r   r   rY   rx   r   r   r8  Zpxpr1  rt   )rO   r   r>  ra   Zsxor%   r%   r&   r    s    

zCartesianRepresentation.cross)NNNNNT)r   )F)rd   r!   r"   re   r  r  rn   r  r~   r   r   r1  rg   xyzr   r   r   r   r   r  r  r  r  r  r   r%   r%   r   r&   r     s.      3

-
r   c                       s   e Zd ZdZeedZedd Zd* fdd	Z	ed	d
 Z
edd Zedd Zdd Zd+ddZdd Zedd Zd, fdd	Zdd Zdd Z fddZd d! Zd-d"d#Zd$d% Zd&d' Zd(d) Z  ZS ).r   aB  
    Representation of points on a unit sphere.

    Parameters
    ----------
    lon, lat : `~astropy.units.Quantity` ['angle'] or str
        The longitude and latitude of the point(s), in angular units. The
        latitude should be between -90 and 90 degrees, and the longitude will
        be wrapped to an angle between 0 and 360 degrees. These can also be
        instances of `~astropy.coordinates.Angle`,
        `~astropy.coordinates.Longitude`, or `~astropy.coordinates.Latitude`.

    differentials : dict, `~astropy.coordinates.BaseDifferential`, optional
        Any differential classes that should be associated with this
        representation. The input must either be a single `~astropy.coordinates.BaseDifferential`
        instance (see `._compatible_differentials` for valid types), or a
        dictionary of of differential instances with keys set to a string
        representation of the SI unit with which the differential (derivative)
        is taken. For example, for a velocity differential on a positional
        representation, the key would be ``'s'`` for seconds, indicating that
        the derivative is a time derivative.

    copy : bool, optional
        If `True` (default), arrays will be copied. If `False`, arrays will
        be references, though possibly broadcast to ensure matching shapes.
    lonlatc                 C   s   t S r/   )r   r#   r%   r%   r&   _dimensional_representation  s    z7UnitSphericalRepresentation._dimensional_representationNTc                    s   t  j||||d d S Nr   r   r~   )rO   rB  rC  r   ri   r   r%   r&   r~     s    z$UnitSphericalRepresentation.__init__c                 C   s   t ttttgS r/   r   r   r   r   r   r#   r%   r%   r&   r     s    z5UnitSphericalRepresentation._compatible_differentialsc                 C   s   | j S z0
        The longitude of the point(s).
        Z_lonrN   r%   r%   r&   rB    s    zUnitSphericalRepresentation.lonc                 C   s   | j S z/
        The latitude of the point(s).
        Z_latrN   r%   r%   r&   rC  %  s    zUnitSphericalRepresentation.latc                 C   sd   t | jt | j }}t | jt | j }}t| |dddt| | | | |dddS )Nr'  Frp   rA  r4   sinrB  cosrC  r   rO   ZsinlonZcoslonZsinlatZcoslatr%   r%   r&   r   ,  s    z(UnitSphericalRepresentation.unit_vectorsFc                 C   s<   t jdtj | jdd}|r |nt | jtj }||dS )Nr%  Tr&  rA  )r4   r(  r  radianrC   rN  rC  )rO   omit_coslatsf_latsf_lonr%   r%   r&   r   4  s
    z)UnitSphericalRepresentation.scale_factorsc                 C   s   t | j| j}t|dddS g
        Converts spherical polar coordinates to 3D rectangular cartesian
        coordinates.
        rR   Fr3  )r8  s2crB  rC  r   )rO   r:  r%   r%   r&   r   :  s    z(UnitSphericalRepresentation.to_cartesianc                 C   s    |j dd}| t|ddiS g
        Converts 3D rectangular cartesian coordinates to spherical polar
        coordinates.
        rR   r2  ri   F)r1  r8  c2sr$   cartr:  r%   r%   r&   r   C  s    z*UnitSphericalRepresentation.from_cartesianc                    sb   t |rT|sTt|tr6|| jdtj | j dddS t|trT|| j| jdddS t	 
||S )NZ   r%  Fphithetarri   )rB  rC  distanceri   )r   r   r   r   rB  r  degrC  r   r   r   )rO   r   r   r   r%   r&   r   M  s    

z(UnitSphericalRepresentation.represent_asc                    s   t t rrtjj}t |}t|\}}j	||dt
 fddj D }|njjjdjd S )a  Transform the unit-spherical coordinates using a 3x3 matrix.

        This returns a new representation and does not modify the original one.
        Any differentials attached to this representation will also be
        transformed.

        Parameters
        ----------
        matrix : (3,3) array-like
            A 3x3 matrix, such as a rotation matrix (or a stack of matrices).

        Returns
        -------
        `UnitSphericalRepresentation` or `SphericalRepresentation`
            If ``matrix`` is O(3) -- :math:`M \dot M^T = I` -- like a rotation,
            then the result is a `UnitSphericalRepresentation`.
            All other matrices will change the distance, so the dimensional
            representation is used instead.

        rA  c                 3   s$   | ]\}}||  fV  qd S r/   r4  r5  r7  r%   r&   rA   |  s   z8UnitSphericalRepresentation.transform.<locals>.<genexpr>r   rB  rC  ra  r   )r4   ru   r   r8  rV  rB  rC  r9  rY  rt   r   r   r,   r  rD  r   )rO   r   r@  r:  rB  rC  r   r%   r7  r&   r   ^  s     
z%UnitSphericalRepresentation.transformc                 G   s&   | j | j| jd| jdj|g|R  S )Nr%  rc  )rD  rB  rC  r   r   r   r%   r%   r&   r     s    
z,UnitSphericalRepresentation._scale_operationc                    s   t fddj D r&t  S jjdtj  j	 dd}j
 D ]@\}  fddttjtjf jD } j|ddi|j|< qP|S )Nc                 3   s   | ]}|j  juV  qd S r/   base_representationrt   r=   r   rN   r%   r&   rA     s   z6UnitSphericalRepresentation.__neg__.<locals>.<genexpr>     f@Frp   c                 3   s    | ]\}}|t  |V  qd S r/   rj   r=   r   r   r   r%   r&   rA     s   ri   )anyr   r5   r   r   rt   rB  r  rb  rC  r,   rI   r   posr   rG   )rO   r   r   	new_compsr   r   rO   r&   r     s    
 
z#UnitSphericalRepresentation.__neg__c                 C   s   t jt| jt jddS )a  Vector norm.

        The norm is the standard Frobenius norm, i.e., the square root of the
        sum of the squares of all components with non-angular units, which is
        always unity for vectors on the unit sphere.

        Returns
        -------
        norm : `~astropy.units.Quantity` ['dimensionless']
            Dimensionless ones, with the same shape as the representation.
        Frp   )r  r  r4   ZonesrC   Zdimensionless_unscaledrN   r%   r%   r&   r    s    z UnitSphericalRepresentation.normc                 C   s:   |  |j |  |||}|tu r*tS | j|S d S r/   )r   rd   r   r   r  rD  r   r  r%   r%   r&   r     s
    z.UnitSphericalRepresentation._combine_operationc                 O   s&   |  d | j|  j|i |S )a  Vector mean.

        The representation is converted to cartesian, the means of the x, y,
        and z components are calculated, and the result is converted to a
        `~astropy.coordinates.SphericalRepresentation`.

        Refer to `~numpy.mean` for full documentation of the arguments, noting
        that ``axis`` is the entry in the ``shape`` of the representation, and
        that the ``out`` argument cannot be used.
        r  )r   rD  r   r   r  r  r%   r%   r&   r    s    
z UnitSphericalRepresentation.meanc                 O   s&   |  d | j|  j|i |S )a  Vector sum.

        The representation is converted to cartesian, the sums of the x, y,
        and z components are calculated, and the result is converted to a
        `~astropy.coordinates.SphericalRepresentation`.

        Refer to `~numpy.sum` for full documentation of the arguments, noting
        that ``axis`` is the entry in the ``shape`` of the representation, and
        that the ``out`` argument cannot be used.
        r  )r   rD  r   r   r  r  r%   r%   r&   r    s    
zUnitSphericalRepresentation.sumc                 C   s    |  d | j|  |S )ao  Cross product of two representations.

        The calculation is done by converting both ``self`` and ``other``
        to `~astropy.coordinates.CartesianRepresentation`, and converting the
        result back to `~astropy.coordinates.SphericalRepresentation`.

        Parameters
        ----------
        other : `~astropy.coordinates.BaseRepresentation` subclass instance
            The representation to take the cross product with.

        Returns
        -------
        cross_product : `~astropy.coordinates.SphericalRepresentation`
            With vectors perpendicular to both ``self`` and ``other``.
        r  )r   rD  r   r   r  r   r%   r%   r&   r    s    
z!UnitSphericalRepresentation.cross)NNT)F)N)F)rd   r!   r"   re   r   r   rn   r
   rD  r~   r   rg   rB  rC  r   r   r   r   r   r   r   r   r   r  r   r  r  r  r   r%   r%   r   r&   r     s6   




	
	*
	r   c                       s   e Zd ZdZdejiZd fdd	Zedd Z	d	d
 Z
dd Zdd Zedd Z fddZdd ZdddZdd Z  ZS )r   a  
    Representation of the distance of points from the origin.

    Note that this is mostly intended as an internal helper representation.
    It can do little else but being used as a scale in multiplication.

    Parameters
    ----------
    distance : `~astropy.units.Quantity` ['length']
        The distance of the point(s) from the origin.

    differentials : dict, `~astropy.coordinates.BaseDifferential`, optional
        Any differential classes that should be associated with this
        representation. The input must either be a single `~astropy.coordinates.BaseDifferential`
        instance (see `._compatible_differentials` for valid types), or a
        dictionary of of differential instances with keys set to a string
        representation of the SI unit with which the differential (derivative)
        is taken. For example, for a velocity differential on a positional
        representation, the key would be ``'s'`` for seconds, indicating that
        the derivative is a time derivative.

    copy : bool, optional
        If `True` (default), arrays will be copied. If `False`, arrays will
        be references, though possibly broadcast to ensure matching shapes.
    ra  NTc                    s   t  j|||d d S rE  rF  )rO   ra  r   ri   r   r%   r&   r~     s    zRadialRepresentation.__init__c                 C   s   | j S z?
        The distance from the origin to the point(s).
        	_distancerN   r%   r%   r&   ra    s    zRadialRepresentation.distancec                 C   s   t d| jdS )z?Cartesian unit vectors are undefined for radial representation.z5Cartesian unit vectors are undefined for {} instancesNr   r   rt   rN   r%   r%   r&   r     s    z!RadialRepresentation.unit_vectorsc                 C   s    t jdtj | jdd}d|iS )Nr%  Tr&  ra  r,  r-  r%   r%   r&   r     s    z"RadialRepresentation.scale_factorsc                 C   s   t d| jdS )z2Cannot convert radial representation to cartesian.z(cannot convert {} instance to cartesian.Nrq  rN   r%   r%   r&   r     s    z!RadialRepresentation.to_cartesianc                 C   s   | |  ddS )zU
        Converts 3D rectangular cartesian coordinates to radial coordinate.
        F)ra  ri   )r  )r$   r[  r%   r%   r&   r     s    z#RadialRepresentation.from_cartesianc                    s$   t |tr| j| S t |S d S r/   )rs   r   ra  r   r   r   r   r%   r&   r   "  s    

zRadialRepresentation.__mul__c                 C   s   | j S )zVector norm.

        Just the distance itself.

        Returns
        -------
        norm : `~astropy.units.Quantity` ['dimensionless']
            Dimensionless ones, with the same shape as the representation.
        )ra  rN   r%   r%   r&   r  (  s    
zRadialRepresentation.normFc                 C   s   t S r/   )r  r   r%   r%   r&   r   4  s    z'RadialRepresentation._combine_operationc                 C   s>   |d }t ||dt jt jf t d kr6td| | S )aX  Radial representations cannot be transformed by a Cartesian matrix.

        Parameters
        ----------
        matrix : array-like
            The transformation matrix in a Cartesian basis.
            Must be a multiplication: a diagonal matrix with identical elements.
            Must have shape (..., 3, 3), where the last 2 indices are for the
            matrix on each other axis. Make sure that the matrix shape is
            compatible with the shape of this representation.

        Raises
        ------
        ValueError
            If the matrix is not a multiplication.

        ).r   r   .   zJRadial representations can only be transformed by a scaled identity matrix)r4   rj  ZnewaxisZidentityrZ   )rO   r   Zsclr%   r%   r&   r   7  s    &zRadialRepresentation.transform)NT)F)rd   r!   r"   re   r  r  rn   r~   rg   ra  r   r   r   r   r   r   r  r   r   r   r%   r%   r   r&   r     s   



r   c                    s   t ju rdd t jt jfS zt d W n* tyX   t jt j fddf Y S 0 t d fddfddfddfS )zDFor given operator, return functions that adjust lon, lat, distance.c                 S   s   | dt j  S N   )r  rb  r  r%   r%   r&   r   U  rB   z%_spherical_op_funcs.<locals>.<lambda>r   c                    s   | g R  S r/   r%   ru  r}   r   r%   r&   r   [  rB   c                    s   | dt j t   S rs  )r  rb  r4   Zsignbitru  
scale_signr%   r&   r   ^  rB   c                    s   |   S r/   r%   ru  rw  r%   r&   r   _  rB   c                    s
    | S r/   r%   ru  )r   scaler%   r&   r   `  rB   )r   r   rk  r4   ZsignrY   abs)r   r}   r%   )r}   r   ry  rx  r&   _spherical_op_funcsR  s    


r{  c                       s   e Zd ZdZeeejdZe	Z
d  fdd	Zedd Zed	d
 Zedd Zedd Zdd Zd!ddZd" fdd	Zdd Zedd Zdd Zdd Z fddZ  ZS )#r   aV  
    Representation of points in 3D spherical coordinates.

    Parameters
    ----------
    lon, lat : `~astropy.units.Quantity` ['angle']
        The longitude and latitude of the point(s), in angular units. The
        latitude should be between -90 and 90 degrees, and the longitude will
        be wrapped to an angle between 0 and 360 degrees. These can also be
        instances of `~astropy.coordinates.Angle`,
        `~astropy.coordinates.Longitude`, or `~astropy.coordinates.Latitude`.

    distance : `~astropy.units.Quantity` ['length']
        The distance to the point(s). If the distance is a length, it is
        passed to the :class:`~astropy.coordinates.Distance` class, otherwise
        it is passed to the :class:`~astropy.units.Quantity` class.

    differentials : dict, `~astropy.coordinates.BaseDifferential`, optional
        Any differential classes that should be associated with this
        representation. The input must either be a single `~astropy.coordinates.BaseDifferential`
        instance (see `._compatible_differentials` for valid types), or a
        dictionary of of differential instances with keys set to a string
        representation of the SI unit with which the differential (derivative)
        is taken. For example, for a velocity differential on a positional
        representation, the key would be ``'s'`` for seconds, indicating that
        the derivative is a time derivative.

    copy : bool, optional
        If `True` (default), arrays will be copied. If `False`, arrays will
        be references, though possibly broadcast to ensure matching shapes.
    rB  rC  ra  NTc              
      s   t  j|||||d t| jts| jjjdkrzt| jdd| _W nB ty } z*|jd 	drptd|n W Y d }~n
d }~0 0 d S )Nr  r]   Frp   r   zDistance must be >= 0zDistance must be >= 0. To allow negative distance values, you must explicitly pass in a `Distance` object with the the argument 'allow_negative=True'.)
r   r~   rs   rp  r   r9   physical_typerZ   r}   rT   )rO   rB  rC  ra  r   ri   er   r%   r&   r~     s    z SphericalRepresentation.__init__c                 C   s   t ttttgS r/   rG  r#   r%   r%   r&   r     s    z1SphericalRepresentation._compatible_differentialsc                 C   s   | j S rH  rI  rN   r%   r%   r&   rB    s    zSphericalRepresentation.lonc                 C   s   | j S rJ  rK  rN   r%   r%   r&   rC    s    zSphericalRepresentation.latc                 C   s   | j S rn  ro  rN   r%   r%   r&   ra    s    z SphericalRepresentation.distancec                 C   sz   t | jt | j }}t | jt | j }}t| |dddt| | | | |ddt|| || |dddS )Nr'  Frp   r|  rL  rO  r%   r%   r&   r     s    z$SphericalRepresentation.unit_vectorsFc                 C   sH   | j tj }|r|n|t| j }tjdtj | jdd}|||dS )Nr%  Tr&  r|  )	ra  r  rP  r4   rN  rC  r(  r)  rC   )rO   rQ  rR  rS  Zsf_distancer%   r%   r&   r     s    z%SphericalRepresentation.scale_factorsc                    sz   t |rlt|trB| ||}|| jdtj | j | j	|ddS t|t
rl| ||}|| j| j|ddS t ||S )Nr\  F)r^  r_  r`  r   ri   rB  rC  r   ri   )r   r   r   r   r   rB  r  rb  rC  ra  r   r   r   rO   r   r   Zdiffsr   r%   r&   r     s"    



z$SphericalRepresentation.represent_asc                 C   sB   t | jtr| jtj}n| j}t| j| j	|}t
|dddS rT  )rs   ra  r   viewr  r  r8  Zs2prB  rC  r   )rO   r6  r:  r%   r%   r&   r     s
    z$SphericalRepresentation.to_cartesianc                 C   s    |j dd}| t|ddiS rW  )r1  r8  p2srZ  r%   r%   r&   r     s    z&SphericalRepresentation.from_cartesianc                    sl   t jj}t  |}t |\}}}j||j| dt fddj	
 D }|S )  Transform the spherical coordinates using a 3x3 matrix.

        This returns a new representation and does not modify the original one.
        Any differentials attached to this representation will also be
        transformed.

        Parameters
        ----------
        matrix : (3,3) array-like
            A 3x3 matrix, such as a rotation matrix (or a stack of matrices).

        r|  c                 3   s$   | ]\}}||  fV  qd S r/   r4  r5  r7  r%   r&   rA     s   z4SphericalRepresentation.transform.<locals>.<genexpr>)r8  rV  rB  rC  r9  r  rt   ra  r   r   r,   r  rO   r   r@  r:  rB  rC  Zurr   r%   r7  r&   r     s    z!SphericalRepresentation.transformc                 C   s   t | jS )a  Vector norm.

        The norm is the standard Frobenius norm, i.e., the square root of the
        sum of the squares of all components with non-angular units.  For
        spherical coordinates, this is just the absolute value of the distance.

        Returns
        -------
        norm : `astropy.units.Quantity`
            Vector norm, with the same shape as the representation.
        )r4   rz  ra  rN   r%   r%   r&   r    s    zSphericalRepresentation.normc           	         s   t fddj D r0t j|g|R  S t|g|R  \}}}j|j|j|j	dd}j
 D ]@\}  fddttj||f jD } j|ddi|j|< qt|S )Nc                 3   s   | ]}|j  juV  qd S r/   rd  rf  rN   r%   r&   rA     s   z;SphericalRepresentation._scale_operation.<locals>.<genexpr>Frp   c                 3   s    | ]\}}|t  |V  qd S r/   rj   rh  ri  r%   r&   rA   %  rB   ri   )rj  r   r5   r   r   r{  rt   rB  rC  ra  r,   rI   r   rk  rG   )	rO   r   r}   Zlon_opZlat_opZdistance_opr   r   rl  r   rm  r&   r     s    

z(SphericalRepresentation._scale_operation)NNNT)F)N)rd   r!   r"   re   r   r   r  r  rn   r   Z_unit_representationr~   r
   r   rg   rB  rC  ra  r   r   r   r   r   r   r   r  r   r   r%   r%   r   r&   r   c  s4      






	r   c                       s   e Zd ZdZeeejdZd fdd	Ze	dd Z
e	d	d
 Ze	dd Zdd Zdd Zd fdd	Zdd Zedd Zdd Zdd Z fddZ  ZS )r   a  
    Representation of points in 3D spherical coordinates (using the physics
    convention of using ``phi`` and ``theta`` for azimuth and inclination
    from the pole).

    Parameters
    ----------
    phi, theta : `~astropy.units.Quantity` or str
        The azimuth and inclination of the point(s), in angular units. The
        inclination should be between 0 and 180 degrees, and the azimuth will
        be wrapped to an angle between 0 and 360 degrees. These can also be
        instances of `~astropy.coordinates.Angle`.  If ``copy`` is False, `phi`
        will be changed inplace if it is not between 0 and 360 degrees.

    r : `~astropy.units.Quantity`
        The distance to the point(s). If the distance is a length, it is
        passed to the :class:`~astropy.coordinates.Distance` class, otherwise
        it is passed to the :class:`~astropy.units.Quantity` class.

    differentials : dict, `PhysicsSphericalDifferential`, optional
        Any differential classes that should be associated with this
        representation. The input must either be a single
        `PhysicsSphericalDifferential` instance, or a dictionary of of
        differential instances with keys set to a string representation of the
        SI unit with which the differential (derivative) is taken. For example,
        for a velocity differential on a positional representation, the key
        would be ``'s'`` for seconds, indicating that the derivative is a time
        derivative.

    copy : bool, optional
        If `True` (default), arrays will be copied. If `False`, arrays will
        be references, though possibly broadcast to ensure matching shapes.
    r^  r_  r`  NTc                    s   t  j|||||d | jjdtj dd tjddR t| j	dtj k sft| j	dtj kr|t
d	|tjW d    n1 s0    Y  | jjjd
kr| jt| _d S )Nr  ih  T)Zinplaceignore)Zinvalidr'  rg  zEInclination angle(s) must be within 0 deg <= angle <= 180 deg, got {}r]   )r   r~   _phiZwrap_atr  rb  r4   Zerrstaterj  _thetarZ   r   toZdegree_rr9   r}  r  r   )rO   r^  r_  r`  r   ri   r   r%   r&   r~   S  s    ,
$z'PhysicsSphericalRepresentation.__init__c                 C   s   | j S z.
        The azimuth of the point(s).
        r  rN   r%   r%   r&   r^  e  s    z"PhysicsSphericalRepresentation.phic                 C   s   | j S )z0
        The elevation of the point(s).
        )r  rN   r%   r%   r&   r_  l  s    z$PhysicsSphericalRepresentation.thetac                 C   s   | j S rn  )r  rN   r%   r%   r&   r`  s  s    z PhysicsSphericalRepresentation.rc                 C   sx   t | jt | j }}t | jt | j }}t| |dddt|| || | ddt|| || |dddS )Nr'  Frp   r  )r4   rM  r^  rN  r_  r   )rO   sinphicosphisinthetaZcosthetar%   r%   r&   r   z  s    z+PhysicsSphericalRepresentation.unit_vectorsc                 C   s@   | j tj }t| j}tjdtj | jdd}|| ||dS )Nr%  Tr&  r  )	r`  r  rP  r4   rM  r_  r(  r)  rC   )rO   r`  r  r*  r%   r%   r&   r     s    z,PhysicsSphericalRepresentation.scale_factorsc                    s   t |rvt|trB| ||}|| jdtj | j | j	|ddS t|t
rv| ||}|| jdtj | j |ddS t ||S )Nr\  F)rB  rC  ra  r   ri   r  )r   r   r   r   r   r^  r  rb  r_  r`  r   r   r   r  r   r%   r&   r     s"    


z+PhysicsSphericalRepresentation.represent_asc                 C   sz   t | jtr| jtj}n| j}|t| j t	| j
 }|t| j t| j
 }|t	| j }t|||ddS )rU  Fr  r  r  ri   )rs   r`  r   r  r  r  r4   rM  r_  rN  r^  r   )rO   r6  r  r  r  r%   r%   r&   r     s    z+PhysicsSphericalRepresentation.to_cartesianc                 C   sL   t |j|j}t ||j}t |j|j}t ||j}| |||ddS )rX  Fr]  )r4   hypotr  r  r  arctan2)r$   r[  r   r`  r^  r_  r%   r%   r&   r     s
    z-PhysicsSphericalRepresentation.from_cartesianc                    s   t jdtj j }t  |}t |\}}}j|dtj | j	| dt
 fddj D }|S )r  r\  r  c                 3   s$   | ]\}}||  fV  qd S r/   r4  r5  r7  r%   r&   rA     s   z;PhysicsSphericalRepresentation.transform.<locals>.<genexpr>)r8  rV  r^  r  rb  r_  r9  r  rt   r`  r   r   r,   r  r  r%   r7  r&   r     s     z(PhysicsSphericalRepresentation.transformc                 C   s   t | jS )a  Vector norm.

        The norm is the standard Frobenius norm, i.e., the square root of the
        sum of the squares of all components with non-angular units.  For
        spherical coordinates, this is just the absolute value of the radius.

        Returns
        -------
        norm : `astropy.units.Quantity`
            Vector norm, with the same shape as the representation.
        )r4   rz  r`  rN   r%   r%   r&   r    s    z#PhysicsSphericalRepresentation.normc           	         s   t fddj D r0t j|g|R  S t|g|R  \}}}j|j||j|j	dd}j
 D ]@\}  fddttj||f jD } j|ddi|j|< qx|S )Nc                 3   s   | ]}|j  juV  qd S r/   rd  rf  rN   r%   r&   rA     s   zBPhysicsSphericalRepresentation._scale_operation.<locals>.<genexpr>Frp   c                 3   s    | ]\}}|t  |V  qd S r/   rj   rh  ri  r%   r&   rA     rB   ri   )rj  r   r5   r   r   r{  rt   r^  r_  r`  r,   rI   r   rk  rG   )	rO   r   r}   phi_opZadjust_theta_signZr_opr   r   rl  r   rm  r&   r     s     

z/PhysicsSphericalRepresentation._scale_operation)NNNT)N)rd   r!   r"   re   r   r  r  rn   r~   rg   r^  r_  r`  r   r   r   r   r   r   r   r  r   r   r%   r%   r   r&   r   ,  s*   "



r   c                       s   e Zd ZdZejeejdZd fdd	Ze	dd Z
e	d	d
 Ze	dd Zdd Zdd Zedd Zdd Z fddZ  ZS )r   a  
    Representation of points in 3D cylindrical coordinates.

    Parameters
    ----------
    rho : `~astropy.units.Quantity`
        The distance from the z axis to the point(s).

    phi : `~astropy.units.Quantity` or str
        The azimuth of the point(s), in angular units, which will be wrapped
        to an angle between 0 and 360 degrees. This can also be instances of
        `~astropy.coordinates.Angle`,

    z : `~astropy.units.Quantity`
        The z coordinate(s) of the point(s)

    differentials : dict, `CylindricalDifferential`, optional
        Any differential classes that should be associated with this
        representation. The input must either be a single
        `CylindricalDifferential` instance, or a dictionary of of differential
        instances with keys set to a string representation of the SI unit with
        which the differential (derivative) is taken. For example, for a
        velocity differential on a positional representation, the key would be
        ``'s'`` for seconds, indicating that the derivative is a time
        derivative.

    copy : bool, optional
        If `True` (default), arrays will be copied. If `False`, arrays will
        be references, though possibly broadcast to ensure matching shapes.
    rhor^  r  NTc                    s6   t  j|||||d | jj| jjs2tdd S )Nr  z-rho and z should have matching physical types)r   r~   _rhor9   r"  r!  r  r#  )rO   r  r^  r  r   ri   r   r%   r&   r~   	  s    z"CylindricalRepresentation.__init__c                 C   s   | j S )z?
        The distance of the point(s) from the z-axis.
        )r  rN   r%   r%   r&   r  $	  s    zCylindricalRepresentation.rhoc                 C   s   | j S r  r  rN   r%   r%   r&   r^  +	  s    zCylindricalRepresentation.phic                 C   s   | j S )z-
        The height of the point(s).
        )r!  rN   r%   r%   r&   r  2	  s    zCylindricalRepresentation.zc              	   C   s^   t | jt | j }}t d| j}t||dddt| |dddtdd|tjdddS )Nr%  r   Frp   )r9   ri   r  )	r4   rM  r^  rN  r(  rC   r   r  r)  )rO   r  r  r*  r%   r%   r&   r   9	  s    z&CylindricalRepresentation.unit_vectorsc                 C   s0   | j tj }tjdtj | jdd}|||dS )Nr%  Tr&  r  )r  r  rP  r4   r(  r)  rC   )rO   r  r*  r%   r%   r&   r   A	  s    z'CylindricalRepresentation.scale_factorsc                 C   s6   t |j|j}t |j|j}|j}| |||ddS )zi
        Converts 3D rectangular cartesian coordinates to cylindrical polar
        coordinates.
        F)r  r^  r  ri   )r4   r  r  r  r  r  )r$   r[  r  r^  r  r%   r%   r&   r   H	  s    z(CylindricalRepresentation.from_cartesianc                 C   s:   | j t| j }| j t| j }| j}t|||ddS )zi
        Converts cylindrical polar coordinates to 3D rectangular cartesian
        coordinates.
        Fr  )r  r4   rN  r^  rM  r  r   )rO   r  r  r  r%   r%   r&   r   U	  s    z&CylindricalRepresentation.to_cartesianc           
         s   t fddj D r0t jg R  S tg R  \}}} fdd}j|j|j|j	dd}j
 D ]@\}fddt|tj|fjD }	j|	ddi|j|< q|S )	Nc                 3   s   | ]}|j  juV  qd S r/   rd  rf  rN   r%   r&   rA   a	  s   z=CylindricalRepresentation._scale_operation.<locals>.<genexpr>c                    s   | g R  S r/   r%   ru  rv  r%   r&   r   f	  rB   z<CylindricalRepresentation._scale_operation.<locals>.<lambda>Frp   c                 3   s    | ]\}}|t  |V  qd S r/   rj   rh  ri  r%   r&   rA   k	  rB   ri   )rj  r   r5   r   r   r{  rt   r  r^  r  r,   rI   r   rk  rG   )
rO   r   r}   r  rq   Zrho_opZz_opr   r   rl  r   )r}   r   r   rO   r&   r   `	  s    
z*CylindricalRepresentation._scale_operation)NNNT)rd   r!   r"   re   r  r  r   rn   r~   rg   r  r^  r  r   r   r   r   r   r   r   r%   r%   r   r&   r     s$   



r   c                       s   e Zd ZdZ fddZedd Zdd Zedd	 Zd
d Z	edd Z
dd Zedd Zdd ZddddZdddZ fddZd ddZ  ZS )!r   a  A base class representing differentials of representations.

    These represent differences or derivatives along each component.
    E.g., for physics spherical coordinates, these would be
    :math:`\delta r, \delta \theta, \delta \phi`.

    Parameters
    ----------
    d_comp1, d_comp2, d_comp3 : `~astropy.units.Quantity` or subclass
        The components of the 3D differentials.  The names are the keys and the
        subclasses the values of the ``attr_classes`` attribute.
    copy : bool, optional
        If `True` (default), arrays will be copied. If `False`, arrays will
        be references, though possibly broadcast to ensure matching shapes.

    Notes
    -----
    All differential representation classes should subclass this base class,
    and define an ``base_representation`` attribute with the class of the
    regular `~astropy.coordinates.BaseRepresentation` for which differential
    coordinates are provided. This will set up a default ``attr_classes``
    instance with names equal to the base component names prefixed by ``d_``,
    and all classes set to `~astropy.units.Quantity`, plus properties to access
    those, and a default ``__init__`` for initialization.
    c              	      s   | j dv rdS t| ds tdt| dsB| jj}dd |D | _|  }|tv rbtd| d	| t|< t  | jD ].}t| |svt	| |t
t|d
| dd qvt jf i | dS )a  Set default ``attr_classes`` and component getters on a Differential.
        class BaseDifferential(BaseRepresentationOrDifferential):

        For these, the components are those of the base representation prefixed
        by 'd_', and the class is `~astropy.units.Quantity`.
        )r   r   r   Nre  zNDifferential representations must have a"base_representation" class attribute.rn   c                 S   s   i | ]}d | t jqS )d_)r  r  r   r%   r%   r&   r   	  s   z6BaseDifferential.__init_subclass__.<locals>.<dictcomp>Differential class z already definedzComponent 'z' of the Differential.r   )rd   r   r   re  rn   r   r-   rZ   r0   r[   rg   r   r   r   )r$   r6   Zbase_attr_classesr   r>   r   r%   r&   r   	  s,    	





z"BaseDifferential.__init_subclass__c                 C   s$   | |j vr td|  d|j d S )Nr  z8 is not compatible with the base (representation) class )r   rx   rt   r$   r   r%   r%   r&   r   	  s    

zBaseDifferential._check_basec                 C   sr   |  | |jD ]T}t||}t| d| d}|dur|j|j }|tjj}d|_t	|  S qt
ddS )zGiven a base (representation instance), determine the unit of the
        derivative by removing the representation unit from the component units
        of this differential.
        r  Nr   a!  Invalid representation-differential units! This likely happened because either the representation or the associated differential have non-standard units. Check that the input positional data have positional units, and the input velocity data have velocity units, or are both dimensionless.)r   rG   r:   r9   Z	decomposer  ZsibasesZ_scalerJ   RuntimeError)rO   r   rX   r   Zd_compZd_unitZ	d_unit_sir%   r%   r&   r   	  s    


zBaseDifferential._get_deriv_keyc                 C   s   |  | | | fS )aX  Get unit vectors and scale factors from base.

        Parameters
        ----------
        base : instance of ``self.base_representation``
            The points for which the unit vectors and scale factors should be
            retrieved.

        Returns
        -------
        unit_vectors : dict of `CartesianRepresentation`
            In the directions of the coordinates of base.
        scale_factors : dict of `~astropy.units.Quantity`
            Scale factors for each of the coordinates

        Raises
        ------
        TypeError : if the base is not of the correct type
        r   r   r   r  r%   r%   r&   _get_base_vectors	  s    
z"BaseDifferential._get_base_vectorsc                    s8    |\ ttj fddtj|jD S )a  Convert the differential to 3D rectangular cartesian coordinates.

        Parameters
        ----------
        base : instance of ``self.base_representation``
            The points for which the differentials are to be converted: each of
            the components is multiplied by its unit vectors and scale factors.

        Returns
        -------
        `CartesianDifferential`
            This object, converted.

        c                 3   s,   | ]$\}}t ||   |  V  qd S r/   rj   )r=   Zd_cr   base_ebase_sfrO   r%   r&   rA   
  s   z0BaseDifferential.to_cartesian.<locals>.<genexpr>)r  r
  r  r   r   rI   rG   rO   r   r%   r  r&   r   	  s    zBaseDifferential.to_cartesianc                    s<   | | j}| |\} |  fdd| D ddiS )ar  Convert the differential from 3D rectangular cartesian coordinates to
        the desired class.

        Parameters
        ----------
        other
            The object to convert into this differential.
        base : `BaseRepresentation`
            The points for which the differentials are to be converted: each of
            the components is multiplied by its unit vectors and scale factors.
            Will be converted to ``cls.base_representation`` if needed.

        Returns
        -------
        `BaseDifferential` subclass instance
            A new differential object that is this class' type.
        c                 3   s$   | ]\}} | |  V  qd S r/   )r  )r=   r>   r~  r  r   r%   r&   rA   
  s   z2BaseDifferential.from_cartesian.<locals>.<genexpr>ri   F)r   re  r  r,   )r$   r   r   r  r%   r  r&   r   
  s    zBaseDifferential.from_cartesianc                 C   s<   || j u r| S | |}t|tr.|||S ||S dS )a  Convert coordinates to another representation.

        If the instance is of the requested class, it is returned unmodified.
        By default, conversion is done via cartesian coordinates.

        Parameters
        ----------
        other_class : `~astropy.coordinates.BaseRepresentation` subclass
            The type of representation to turn the coordinates into.
        base : instance of ``self.base_representation``
            Base relative to which the differentials are defined.  If the other
            class is a differential representation, the base will be converted
            to its ``base_representation``.
        N)rt   r   r   r   r   )rO   r   r   self_cartesianr%   r%   r&   r   
  s    


zBaseDifferential.represent_asc                 C   s2   t |tr|||j}n| }| ||S )a  Create a new instance of this representation from another one.

        Parameters
        ----------
        representation : `~astropy.coordinates.BaseRepresentation` instance
            The presentation that should be converted to this class.
        base : instance of ``cls.base_representation``
            The base relative to which the differentials will be defined. If
            the representation is a differential itself, the base will be
            converted to its ``base_representation`` to help convert it.
        )rs   r   r   r   re  r   )r$   r   r   Z	cartesianr%   r%   r&   r  6
  s    

z$BaseDifferential.from_representationc                 C   s&   | j t|d|}| | j|}|S )C  Transform differential using a 3x3 matrix in a Cartesian basis.

        This returns a new differential and does not modify the original one.

        Parameters
        ----------
        matrix : (3,3) array-like
            A 3x3 (or stack thereof) matrix, such as a rotation matrix.
        base : instance of ``cls.base_representation``
            Base relative to which the differentials are defined.  If the other
            class is a differential representation, the base will be converted
            to its ``base_representation``.
        transformed_base : instance of ``cls.base_representation``
            Base relative to which the transformed differentials are defined.
            If the other class is a differential representation, the base will
            be converted to its ``base_representation``.
        r   )r   r   r   rt   )rO   r   r   transformed_baseZcdiffr   r%   r%   r&   r   K
  s
    zBaseDifferential.transformFr  c                   s(    fddj D }j|ddiS )aa  Scale all components.

        Parameters
        ----------
        op : `~operator` callable
            Operator to apply (e.g., `~operator.mul`, `~operator.neg`, etc.
        *args
            Any arguments required for the operator (typically, what is to
            be multiplied with, divided by).
        scaled_base : bool, optional
            Whether the base was scaled the same way. This affects whether
            differential components should be scaled. For instance, a differential
            in longitude should not be scaled if its spherical base is scaled
            in radius.
        c                    s"   g | ]}t |g R  qS r%   rj   r   r}   r   rO   r%   r&   rF   t
  rB   z5BaseDifferential._scale_operation.<locals>.<listcomp>ri   F)rG   rt   )rO   r   r  r}   Zscaled_attrsr%   r  r&   r   d
  s    z!BaseDifferential._scale_operationc                    s~   t | t|rD|s| |fn|| f\ | j fdd| jD  S z| |}W n tyh   t Y S 0 ||| S dS )a%  Combine two differentials, or a differential with a representation.

        If ``other`` is of the same differential type as ``self``, the
        components will simply be combined.  If ``other`` is a representation,
        it will be used as a base for which to evaluate the differential,
        and the result is a new representation.

        Parameters
        ----------
        op : `~operator` callable
            Operator to apply (e.g., `~operator.add`, `~operator.sub`, etc.
        other : `~astropy.coordinates.BaseRepresentation` subclass instance
            The other differential or representation.
        reverse : bool
            Whether the operands should be reversed (e.g., as we got here via
            ``self.__rsub__`` because ``self`` is a subclass of ``other``).
        c                    s"   g | ]}t  |t |qS r%   rj   r   r;  r%   r&   rF   
  s   z7BaseDifferential._combine_operation.<locals>.<listcomp>N)rs   r   rt   rG   r   rx   r  r   )rO   r   r   r   r  r%   r;  r&   r   w
  s    
z#BaseDifferential._combine_operationc                    s   t |trtS t |S r/   )rs   r   r  r   r   r   r   r%   r&   r   
  s    
zBaseDifferential.__sub__Nc                 C   s4   t | ts&|du r&tdt| j | | S )ap  Vector norm.

        The norm is the standard Frobenius norm, i.e., the square root of the
        sum of the squares of all components with non-angular units.

        Parameters
        ----------
        base : instance of ``self.base_representation``
            Base relative to which the differentials are defined. This is
            required to calculate the physical size of the differential for
            all but Cartesian differentials or radial differentials.

        Returns
        -------
        norm : `astropy.units.Quantity`
            Vector norm, with the same shape as the representation.
        Nz3`base` must be provided to calculate the norm of a )rs   r   rZ   r   rd   r   r  r  r%   r%   r&   r  
  s
    zBaseDifferential.norm)F)N)rd   r!   r"   re   r   r   r   r   r  r   r   r   r  r   r   r   r   r  r   r%   r%   r   r&   r   q	  s$   '
 



r   c                       s^   e Zd ZdZeZdZd fdd	ZdddZe	ddd	Z
dd
dZdddZeeZ  ZS )r   a  Differentials in of points in 3D cartesian coordinates.

    Parameters
    ----------
    d_x, d_y, d_z : `~astropy.units.Quantity` or array
        The x, y, and z coordinates of the differentials. If ``d_x``, ``d_y``,
        and ``d_z`` have different shapes, they should be broadcastable. If not
        quantities, ``unit`` should be set.  If only ``d_x`` is given, it is
        assumed that it contains an array with the 3 coordinates stored along
        ``xyz_axis``.
    unit : `~astropy.units.Unit` or str
        If given, the differentials will be converted to this unit (or taken to
        be in this unit if not given.
    xyz_axis : int, optional
        The axis along which the coordinates are stored when a single array is
        provided instead of distinct ``d_x``, ``d_y``, and ``d_z`` (default: 0).
    copy : bool, optional
        If `True` (default), arrays will be copied. If `False`, arrays will
        be references, though possibly broadcast to ensure matching shapes.
    NTc                    s<  |d u r~|d u r~t |tjrt|jjdvrttj|||dd}|| _|rZt||d}|| _	nd| _	|\| _
| _| _d S |\}}}|d urtd|d u s|d u rtd| jj|d urtj|||dd}tj|||dd}tj|||dd}d}t j||||d | j
j| jjr.| j
j| jjs8td	d S )
Nr  Trl   r   zxyz_axis should only be set if d_x, d_y, and d_z are in a single array passed in through d_x, i.e., d_y and d_z should not be not given.z0d_x, d_y, and d_z are required to instantiate {}Frp   z.d_x, d_y and d_z should have equivalent units.)rs   r4   r  rE   r  r  r  _d_xyzr  r  _d_x_d_y_d_zrZ   r   rt   rd   r   r~   r9   r"  r#  )rO   Zd_xZd_yd_zr9   r$  ri   r   r%   r&   r~   
  s6    
zCartesianDifferential.__init__c                    s   t  fdd jD  S )Nc                    s   g | ]}t  |qS r%   rj   r   rN   r%   r&   rF   
  rB   z6CartesianDifferential.to_cartesian.<locals>.<listcomp>)r   rG   r  r%   rN   r&   r   
  s    z"CartesianDifferential.to_cartesianc                    s   |  fdd j D  S )Nc                    s   g | ]}t  |qS r%   rj   r   r   r%   r&   rF   
  rB   z8CartesianDifferential.from_cartesian.<locals>.<listcomp>)rG   r$   r   r   r%   r  r&   r   
  s    z$CartesianDifferential.from_cartesianc                 C   s$   t || jdd}| j|dddS )a  Transform differentials using a 3x3 matrix in a Cartesian basis.

        This returns a new differential and does not modify the original one.

        Parameters
        ----------
        matrix : (3,3) array-like
            A 3x3 (or stack thereof) matrix, such as a rotation matrix.
        base, transformed_base : `~astropy.coordinates.CartesianRepresentation` or None, optional
            Not used in the Cartesian transformation.
        rR   r2  Fr3  )r8  r9  	get_d_xyzrt   )rO   r   r   r  r:  r%   r%   r&   r   
  s    zCartesianDifferential.transformr   c                 C   sF   | j dur,| j|kr| j S t| j | j|S tj| j| j| jg|dS )a  Return a vector array of the x, y, and z coordinates.

        Parameters
        ----------
        xyz_axis : int, optional
            The axis in the final array along which the x, y, z components
            should be stored (default: 0).

        Returns
        -------
        d_xyz : `~astropy.units.Quantity`
            With dimension 3 along ``xyz_axis``.  Note that, if possible,
            this will be a view.
        Nr.  )r  r  r4   r  r/  r  r  r  r0  r%   r%   r&   r    s
    

zCartesianDifferential.get_d_xyz)NNNNT)N)N)NN)r   )rd   r!   r"   re   r   re  r  r~   r   r   r   r   r  rg   Zd_xyzr   r%   r%   r   r&   r   
  s     *


r   c                       s2   e Zd Zdd Zedd Zd fdd	Z  ZS )	r   c                 C   s   |  | | jt|j S )zConvert longitude differential d_lon to d_lon_coslat.

        Parameters
        ----------
        base : instance of ``cls.base_representation``
            The base from which the latitude will be taken.
        )r   d_lonr4   rN  rC  r  r%   r%   r&   _d_lon_coslat-  s    
z'BaseSphericalDifferential._d_lon_coslatc                 C   s   |  | |t|j S )aH  Convert longitude differential d_lon_coslat to d_lon.

        Parameters
        ----------
        d_lon_coslat : `~astropy.units.Quantity`
            Longitude differential that includes ``cos(lat)``.
        base : instance of ``cls.base_representation``
            The base from which the latitude will be taken.
        r   r4   rN  rC  )r$   d_lon_coslatr   r%   r%   r&   
_get_d_lon8  s    
z$BaseSphericalDifferential._get_d_lonFc                    s   t |trt | t|r"t |trrt| jt|jB }|sB| |fn|| f\  fdd|D }tf i |S t ||S )"  Combine two differentials, or a differential with a representation.

        If ``other`` is of the same differential type as ``self``, the
        components will simply be combined.  If both are different parts of
        a `~astropy.coordinates.SphericalDifferential` (e.g., a
        `~astropy.coordinates.UnitSphericalDifferential` and a
        `~astropy.coordinates.RadialDifferential`), they will combined
        appropriately.

        If ``other`` is a representation, it will be used as a base for which
        to evaluate the differential, and the result is a new representation.

        Parameters
        ----------
        op : `~operator` callable
            Operator to apply (e.g., `~operator.add`, `~operator.sub`, etc.
        other : `~astropy.coordinates.BaseRepresentation` subclass instance
            The other differential or representation.
        reverse : bool
            Whether the operands should be reversed (e.g., as we got here via
            ``self.__rsub__`` because ``self`` is a subclass of ``other``).
        c              	      s(   i | ] }|t  |d t |d qS r'  rj   r   r;  r%   r&   r   b  s   z@BaseSphericalDifferential._combine_operation.<locals>.<dictcomp>)	rs   r   r   r   r   rG   r   r   r   rO   r   r   r   Zall_componentsZresult_argsr   r;  r&   r   F  s    
z,BaseSphericalDifferential._combine_operation)F)rd   r!   r"   r  r   r  r   r   r%   r%   r   r&   r   ,  s   
r   c                       s   e Zd ZdZeZedd Zd fdd	Ze	dd	 Z
 fd
dZd fdd	Ze	d fdd	Z fddZdd fdd
Z  ZS )r   ag  Differential(s) of points on a unit sphere.

    Parameters
    ----------
    d_lon, d_lat : `~astropy.units.Quantity`
        The longitude and latitude of the differentials.
    copy : bool, optional
        If `True` (default), arrays will be copied. If `False`, arrays will
        be references, though possibly broadcast to ensure matching shapes.
    c                 C   s   t S r/   )r   r#   r%   r%   r&   _dimensional_differentialv  s    z3UnitSphericalDifferential._dimensional_differentialNTc                    s2   t  j|||d | jj| jjs.tdd S Nrp   z-d_lon and d_lat should have equivalent units.r   r~   _d_lonr9   r"  _d_latr  r#  )rO   r  d_latri   r   r%   r&   r~   z  s    z"UnitSphericalDifferential.__init__c                 C   s   | j ||}|| S r/   r  r   r   r$   r   r   Zdimensionalr%   r%   r&   r     s    z(UnitSphericalDifferential.from_cartesianc                    sJ   t |tr|j}nt |tr$|j}nt |S |t}|t | S r/   	rs   r   ra  r   r`  r   r   r   r   rO   r   ry  r   r%   r&   r     s    


z&UnitSphericalDifferential.to_cartesianc                    s*   t |tr|| || jS t ||S r/   )r   r   r  r  r   r   rO   r   r   r   r%   r&   r     s    
z&UnitSphericalDifferential.represent_asc                    sh   t |tr| |j|jS t |ttfr@| |j|}| ||jS t |trZ| |j	|j
 S t ||S r/   )rs   r   r  r  r   r   r  r  r   d_phid_thetar   r  r$   r   r   r  r   r%   r&   r    s    

z-UnitSphericalDifferential.from_representationc                    sV   t t|r t |||}n2| jj|jj }| j| j| j	d| d|||}|S )r  r   )r  r  
d_distance)
r4   ru   r   r   r   r  r9   rB  r  r  rO   r   r   r  r   Zdur   r%   r&   r     s    z#UnitSphericalDifferential.transformFr  c                   s$   |r|   S t j|g|R  S d S r/   ri   r   r   rO   r   r  r}   r   r%   r&   r     s    z*UnitSphericalDifferential._scale_operation)NT)N)N)rd   r!   r"   re   r   re  r
   r  r~   r   r   r   r   r  r   r   r   r%   r%   r   r&   r   i  s   


"r   c                       s\   e Zd ZdZeZeZd fdd	Zd fdd	Z	e
d fdd		Zd
d fdd
Z  ZS )r   a  Differential(s) of points in 3D spherical coordinates.

    Parameters
    ----------
    d_lon, d_lat : `~astropy.units.Quantity`
        The differential longitude and latitude.
    d_distance : `~astropy.units.Quantity`
        The differential distance.
    copy : bool, optional
        If `True` (default), arrays will be copied. If `False`, arrays will
        be references, though possibly broadcast to ensure matching shapes.
    NTc                    s4   t  j||||d | jj| jjs0tdd S r  r  )rO   r  r  r  ri   r   r%   r&   r~     s    zSphericalDifferential.__init__c                    s   t |tr|| j| jS t |tr,|| jS t |trL|| || j| jS t |trh|| || jS t |t	r|| j| j | jS t
 ||S d S r/   )r   r   r  r  r   r  r   r  r   r   r   r   r  r   r%   r&   r     s    





z"SphericalDifferential.represent_asc                    sT   t |tr(| |j|}| ||j|jS t |trF| |j|j |j	S t
 ||S r/   )rs   r   r  r  r  r  r   r  r  d_rr   r  r  r   r%   r&   r    s    

z)SphericalDifferential.from_representationFr  c                   s<   |r$|  | j| j|| jg|R  S t j|g|R  S d S r/   )rt   r  r  r  r   r   r  r   r%   r&   r     s     z&SphericalDifferential._scale_operation)NNT)N)N)rd   r!   r"   re   r   re  r   _unit_differentialr~   r   r   r  r   r   r%   r%   r   r&   r     s   r   c                       sB   e Zd ZdZedd Zdd Zedd Zd fd	d
	Z  Z	S )r   zDifferentials from points on a spherical base representation.

    With cos(lat) assumed to be included in the longitude differential.
    c                 C   s   |  | | |jddfS )a  Get unit vectors and scale factors from (unit)spherical base.

        Parameters
        ----------
        base : instance of ``self.base_representation``
            The points for which the unit vectors and scale factors should be
            retrieved.

        Returns
        -------
        unit_vectors : dict of `CartesianRepresentation`
            In the directions of the coordinates of base.
        scale_factors : dict of `~astropy.units.Quantity`
            Scale factors for each of the coordinates.  The scale factor for
            longitude does not include the cos(lat) factor.

        Raises
        ------
        TypeError : if the base is not of the correct type
        T)rQ  r  r  r%   r%   r&   r    s    
z1BaseSphericalCosLatDifferential._get_base_vectorsc                 C   s   |  | | jt|j S )zConvert longitude differential with cos(lat) to one without.

        Parameters
        ----------
        base : instance of ``cls.base_representation``
            The base from which the latitude will be taken.
        )r   r  r4   rN  rC  r  r%   r%   r&   r  (  s    
z&BaseSphericalCosLatDifferential._d_lonc                 C   s   |  | |t|j S )aH  Convert longitude differential d_lon to d_lon_coslat.

        Parameters
        ----------
        d_lon : `~astropy.units.Quantity`
            Value of the longitude differential without ``cos(lat)``.
        base : instance of ``cls.base_representation``
            The base from which the latitude will be taken.
        r  )r$   r  r   r%   r%   r&   _get_d_lon_coslat3  s    
z1BaseSphericalCosLatDifferential._get_d_lon_coslatFc                    s   t |trt | t|r"t |trrt| jt|jB }|sB| |fn|| f\  fdd|D }tf i |S t ||S )r  c              	      s(   i | ] }|t  |d t |d qS r  rj   r   r;  r%   r&   r   ]  s   zFBaseSphericalCosLatDifferential._combine_operation.<locals>.<dictcomp>)	rs   r   r   r   r   rG   r   r   r   r  r   r;  r&   r   A  s    
z2BaseSphericalCosLatDifferential._combine_operation)F)
rd   r!   r"   re   r   r  r  r  r   r   r%   r%   r   r&   r   
  s   

r   c                       s   e Zd ZdZeZejejdZe	dd Z
d fdd	Zed	d
 Z fddZd fdd	Zed fdd	Z fddZdd fdd
Z  ZS )r   an  Differential(s) of points on a unit sphere.

    Parameters
    ----------
    d_lon_coslat, d_lat : `~astropy.units.Quantity`
        The longitude and latitude of the differentials.
    copy : bool, optional
        If `True` (default), arrays will be copied. If `False`, arrays will
        be references, though possibly broadcast to ensure matching shapes.
    )r  r  c                 C   s   t S r/   )r   r#   r%   r%   r&   r  s  s    z9UnitSphericalCosLatDifferential._dimensional_differentialNTc                    s2   t  j|||d | jj| jjs.tdd S Nrp   z4d_lon_coslat and d_lat should have equivalent units.r   r~   r  r9   r"  r  r  r#  )rO   r  r  ri   r   r%   r&   r~   w  s    z(UnitSphericalCosLatDifferential.__init__c                 C   s   | j ||}|| S r/   r  r  r%   r%   r&   r   }  s    z.UnitSphericalCosLatDifferential.from_cartesianc                    sJ   t |tr|j}nt |tr$|j}nt |S |t}|t | S r/   r  r  r   r%   r&   r     s    


z,UnitSphericalCosLatDifferential.to_cartesianc                    s*   t |tr|| || jS t ||S r/   )r   r   r  r  r   r   r  r   r%   r&   r     s    
z,UnitSphericalCosLatDifferential.represent_asc                    st   t |tr| |j|jS t |ttfr@| |j|}| ||jS t |trf| |j	|}| ||j
 S t ||S r/   )rs   r   r  r  r   r   r  r  r   r  r  r   r  r$   r   r   r  r   r%   r&   r    s    

z3UnitSphericalCosLatDifferential.from_representationc                    sV   t t|r t |||}n2| jj|jj }| j| j	| jd| d|||}|S )r  r   r  r  r  )
r4   ru   r   r   r   r  r9   rC  r  r  r  r   r%   r&   r     s    z)UnitSphericalCosLatDifferential.transformFr  c                   s$   |r|   S t j|g|R  S d S r/   r  r  r   r%   r&   r     s    z0UnitSphericalCosLatDifferential._scale_operation)NT)N)N)rd   r!   r"   re   r   re  r  r  rn   r
   r  r~   r   r   r   r   r  r   r   r   r%   r%   r   r&   r   d  s    


"r   c                       sn   e Zd ZdZeZeZej	ej	ej	dZ
d fdd	Zd fdd	Zed fd	d
	Zdd fdd
Z  ZS )r   a  Differential(s) of points in 3D spherical coordinates.

    Parameters
    ----------
    d_lon_coslat, d_lat : `~astropy.units.Quantity`
        The differential longitude (with cos(lat) included) and latitude.
    d_distance : `~astropy.units.Quantity`
        The differential distance.
    copy : bool, optional
        If `True` (default), arrays will be copied. If `False`, arrays will
        be references, though possibly broadcast to ensure matching shapes.
    r  NTc                    s4   t  j||||d | jj| jjs0tdd S r  r  )rO   r  r  r  ri   r   r%   r&   r~     s    z$SphericalCosLatDifferential.__init__c                    s   t |tr|| j| jS t |tr,|| jS t |trL|| || j| jS t |trh|| || jS t |t	r|| || j | jS t
 ||S r/   )r   r   r  r  r   r  r   r  r   r   r   r   r  r   r%   r&   r     s    





z(SphericalCosLatDifferential.represent_asc                    s`   t |tr(| |j|}| ||j|jS t |trR| |j|}| ||j |j	S t
 ||S r/   )rs   r   r  r  r  r  r   r  r  r  r   r  r  r   r%   r&   r    s    


z/SphericalCosLatDifferential.from_representationFr  c                   s<   |r$|  | j| j|| jg|R  S t j|g|R  S d S r/   )rt   r  r  r  r   r   r  r   r%   r&   r     s     z,SphericalCosLatDifferential._scale_operation)NNT)N)N)rd   r!   r"   re   r   re  r   r  r  r  rn   r~   r   r   r  r   r   r%   r%   r   r&   r     s   r   c                       sV   e Zd ZdZeZdd ZdddZedd Z	ed fd	d
	Z
d fdd	Z  ZS )r   aH  Differential(s) of radial distances.

    Parameters
    ----------
    d_distance : `~astropy.units.Quantity`
        The differential distance.
    copy : bool, optional
        If `True` (default), arrays will be copied. If `False`, arrays will
        be references, though possibly broadcast to ensure matching shapes.
    c                 C   s   | j |t  S r/   )r  r   r   r   r  r%   r%   r&   r     s    zRadialDifferential.to_cartesianNc                 C   s   | j S r/   )r  r  r%   r%   r&   r    s    zRadialDifferential.normc                 C   s   | | |tddS )NFrp   )r  r   r   r  r%   r%   r&   r   "  s    z!RadialDifferential.from_cartesianc                    s>   t |ttfr| |jS t |tr,| |jS t ||S d S r/   )rs   r   r   r  r   r  r   r  )r$   r   r   r   r%   r&   r  '  s    


z&RadialDifferential.from_representationFc                    s   t || jrB|r |j| j  n| j|j  |j ddS t |ttfrt| jt|jB }|sp| |fn|| f\  fdd|D }t	f i |S t
 ||S d S )NFrp   c              	      s(   i | ] }|t  |d t |d qS r  rj   r   r;  r%   r&   r   <  s   z9RadialDifferential._combine_operation.<locals>.<dictcomp>)rs   re  ra  r  rt   r   r   r   rG   r   r   r   r  r   r;  r&   r   1  s    z%RadialDifferential._combine_operation)N)N)F)rd   r!   r"   re   r   re  r   r  r   r   r  r   r   r%   r%   r   r&   r     s   


	r   c                       sX   e Zd ZdZeZd fdd	Zd fdd	Zed fdd		Z	d
d fdd
Z
  ZS )r   a  Differential(s) of 3D spherical coordinates using physics convention.

    Parameters
    ----------
    d_phi, d_theta : `~astropy.units.Quantity`
        The differential azimuth and inclination.
    d_r : `~astropy.units.Quantity`
        The differential radial distance.
    copy : bool, optional
        If `True` (default), arrays will be copied. If `False`, arrays will
        be references, though possibly broadcast to ensure matching shapes.
    NTc                    s4   t  j||||d | jj| jjs0tdd S )Nrp   z/d_phi and d_theta should have equivalent units.)r   r~   Z_d_phir9   r"  Z_d_thetar  r#  )rO   r  r  r  ri   r   r%   r&   r~   S  s    z%PhysicsSphericalDifferential.__init__c                    s   t |tr|| j| j | jS t |tr8|| j| j S t |trp| | | jt	|j
 }||| j | jS t |tr| | | jt	|j
 }||| j S t |tr|| jS t ||S r/   )r   r   r  r  r  r   r   r   r4   rM  r_  r   r   r   r   )rO   r   r   r  r   r%   r&   r   Y  s    







z)PhysicsSphericalDifferential.represent_asc                    sd   t |tr| |j|j |jS t |trV| | |jt	|j
 }| ||j |jS t ||S r/   )rs   r   r  r  r  r   r   r  r4   rM  r_  r   r  )r$   r   r   r  r   r%   r&   r  n  s    


z0PhysicsSphericalDifferential.from_representationFr  c                   s<   |r$|  | j| j|| jg|R  S t j|g|R  S d S r/   )rt   r  r  r  r   r   r  r   r%   r&   r   }  s     z-PhysicsSphericalDifferential._scale_operation)NNT)N)N)rd   r!   r"   re   r   re  r~   r   r   r  r   r   r%   r%   r   r&   r   D  s   r   c                       s&   e Zd ZdZeZd fdd	Z  ZS )r   a  Differential(s) of points in cylindrical coordinates.

    Parameters
    ----------
    d_rho : `~astropy.units.Quantity` ['speed']
        The differential cylindrical radius.
    d_phi : `~astropy.units.Quantity` ['angular speed']
        The differential azimuth.
    d_z : `~astropy.units.Quantity` ['speed']
        The differential height.
    copy : bool, optional
        If `True` (default), arrays will be copied. If `False`, arrays will
        be references, though possibly broadcast to ensure matching shapes.
    NFc                    s4   t  j||||d | jj| jjs0tdd S )Nrp   z+d_rho and d_z should have equivalent units.)r   r~   Z_d_rhor9   r"  r  r  r#  )rO   Zd_rhor  r  ri   r   r%   r&   r~     s    z CylindricalDifferential.__init__)NNF)rd   r!   r"   re   r   re  r~   r   r%   r%   r   r&   r     s   r   )r1   )>re   r   r
  r   r   r   Znumpyr4   Zastropy.unitsZunitsr  Zerfar   r8  Zanglesr   r   r   Z	distancesr   Zmatrix_utilitiesr   Zastropy.utilsr	   r
   Zastropy.utils.data_infor   Zastropy.utils.exceptionsr   __all__r+   r-   r   r   r(   r'   r.   r0   r7   r8   r   r   r   r   r   r   r   r{  r   r   r   r   r   r   r   r   r   r   r   r   r   r   r%   r%   r%   r&   <module>   sx   
T  z       & wl J Ow  Ex=g:Zk?6@