
    IR-er                         d dl Z d dlmZ d dlZd dlmZ d dlmZ d dl	m
Z
mZ d dlmZ d dlmZ dgZd	Z G d
 d          ZdS )    N)deepcopy)NDUncertainty)dimensionless_unscaled)
format_docsharedmethod)AstropyUserWarning)MaskedNDArithmeticMixina  
    Performs {name} by evaluating ``self`` {op} ``operand``.

    Parameters
    ----------
    operand, operand2 : `NDData`-like instance
        If ``operand2`` is ``None`` or not given it will perform the operation
        ``self`` {op} ``operand``.
        If ``operand2`` is given it will perform ``operand`` {op} ``operand2``.
        If the method was called on a class rather than on the instance
        ``operand2`` must be given.

    propagate_uncertainties : `bool` or ``None``, optional
        If ``None`` the result will have no uncertainty. If ``False`` the
        result will have a copied version of the first operand that has an
        uncertainty. If ``True`` the result will have a correctly propagated
        uncertainty from the uncertainties of the operands but this assumes
        that the uncertainties are `NDUncertainty`-like. Default is ``True``.

        .. versionchanged:: 1.2
            This parameter must be given as keyword-parameter. Using it as
            positional parameter is deprecated.
            ``None`` was added as valid parameter value.

    handle_mask : callable, ``'first_found'`` or ``None``, optional
        If ``None`` the result will have no mask. If ``'first_found'`` the
        result will have a copied version of the first operand that has a
        mask). If it is a callable then the specified callable must
        create the results ``mask`` and if necessary provide a copy.
        Default is `numpy.logical_or`.

        .. versionadded:: 1.2

    handle_meta : callable, ``'first_found'`` or ``None``, optional
        If ``None`` the result will have no meta. If ``'first_found'`` the
        result will have a copied version of the first operand that has a
        (not empty) meta. If it is a callable then the specified callable must
        create the results ``meta`` and if necessary provide a copy.
        Default is ``None``.

        .. versionadded:: 1.2

    compare_wcs : callable, ``'first_found'`` or ``None``, optional
        If ``None`` the result will have no wcs and no comparison between
        the wcs of the operands is made. If ``'first_found'`` the
        result will have a copied version of the first operand that has a
        wcs. If it is a callable then the specified callable must
        compare the ``wcs``. The resulting ``wcs`` will be like if ``False``
        was given otherwise it raises a ``ValueError`` if the comparison was
        not successful. Default is ``'first_found'``.

        .. versionadded:: 1.2

    uncertainty_correlation : number or `~numpy.ndarray`, optional
        The correlation between the two operands is used for correct error
        propagation for correlated data as given in:
        https://en.wikipedia.org/wiki/Propagation_of_uncertainty#Example_formulas
        Default is 0.

        .. versionadded:: 1.2


    kwargs :
        Any other parameter that should be passed to the callables used.

    Returns
    -------
    result : `~astropy.nddata.NDData`-like
        The resulting dataset

    Notes
    -----
    If a ``callable`` is used for ``mask``, ``wcs`` or ``meta`` the
    callable must accept the corresponding attributes as first two
    parameters. If the callable also needs additional parameters these can be
    defined as ``kwargs`` and must start with ``"wcs_"`` (for wcs callable) or
    ``"meta_"`` (for meta callable). This startstring is removed before the
    callable is called.

    ``"first_found"`` can also be abbreviated with ``"ff"``.
    c                      e Zd ZdZdej        dddddfdZd Zd	 Zdd
Z	d Z
d Ze eedd          dd                        Ze eedd          dd                        Ze eedd          dd                        Ze eedd          dd                        Zed             Zed             Zed             Zed             Ze	 d d            ZdS )!r
   a	  
    Mixin class to add arithmetic to an NDData object.

    When subclassing, be sure to list the superclasses in the correct order
    so that the subclass sees NDData as the main superclass. See
    `~astropy.nddata.NDDataArray` for an example.

    Notes
    -----
    This class only aims at covering the most common cases so there are certain
    restrictions on the saved attributes::

        - ``uncertainty`` : has to be something that has a `NDUncertainty`-like
          interface for uncertainty propagation
        - ``mask`` : has to be something that can be used by a bitwise ``or``
          operation.
        - ``wcs`` : has to implement a way of comparing with ``=`` to allow
          the operation.

    But there is a workaround that allows to disable handling a specific
    attribute and to simply set the results attribute to ``None`` or to
    copy the existing attribute (and neglecting the other).
    For example for uncertainties not representing an `NDUncertainty`-like
    interface you can alter the ``propagate_uncertainties`` parameter in
    :meth:`NDArithmeticMixin.add`. ``None`` means that the result will have no
    uncertainty, ``False`` means it takes the uncertainty of the first operand
    (if this does not exist from the second operand) as the result's
    uncertainty. This behavior is also explained in the docstring for the
    different arithmetic operations.

    Decomposing the units is not attempted, mainly due to the internal mechanics
    of `~astropy.units.Quantity`, so the resulting data might have units like
    ``km/m`` if you divided for example 100km by 5m. So this Mixin has adopted
    this behavior.

    Examples
    --------
    Using this Mixin with `~astropy.nddata.NDData`:

        >>> from astropy.nddata import NDData, NDArithmeticMixin
        >>> class NDDataWithMath(NDArithmeticMixin, NDData):
        ...     pass

    Using it with one operand on an instance::

        >>> ndd = NDDataWithMath(100)
        >>> ndd.add(20)
        NDDataWithMath(120)

    Using it with two operand on an instance::

        >>> ndd = NDDataWithMath(-4)
        >>> ndd.divide(1, ndd)
        NDDataWithMath(-0.25)

    Using it as classmethod requires two operands::

        >>> NDDataWithMath.subtract(5, 4)
        NDDataWithMath(1)

    TNr   first_foundFc
                    i i i i i d}|
D ]_}|                     dd          }	 |
|         ||d                  |d         <   7# t          $ r t          d|d          d|           w xY wi }|d|d<   nd|d	v rG| j        (t          |d          rt	          |j                  |d<   n1t	          | j                  |d<   n | j        |||fi |d         |d<   |du o| j        du}|r|s\| j        9t          | j        d
          s$t          | j        | j        z  | j                  }nFt          | j        | j                  }n*t          j                            | j        | j                  } |||	          }t          |d          s:t          j                            |t          j        |t                              }n | j        ||fd|	i|d         }t          |d
          st          | d
          r
| j        |d
<   |d|d<   nU|s7| j        t	          |j                  |d<   n4t	          | j                  |d<   n | j        ||||fd|	i|d         |d<   | j        	|*|j        #t'          j        d|j         dt,                     |nlt          |d          rd|d<   nV|d	v r7| j        t	          |j                  |d<   n3t	          | j                  |d<   n | j        |||fd|	i|d         |d<   |d|d<   nT|d	v r7| j        st	          |j                  |d<   n1t	          | j                  |d<   n | j        |||fi |d         |d<   ||fS )a  
        Base method which calculates the result of the arithmetic operation.

        This method determines the result of the arithmetic operation on the
        ``data`` including their units and then forwards to other methods
        to calculate the other properties for the result (like uncertainty).

        Parameters
        ----------
        operation : callable
            The operation that is performed on the `NDData`. Supported are
            `numpy.add`, `numpy.subtract`, `numpy.multiply` and
            `numpy.true_divide`.

        operand : same type (class) as self
            see :meth:`NDArithmeticMixin.add`

        propagate_uncertainties : `bool` or ``None``, optional
            see :meth:`NDArithmeticMixin.add`

        handle_mask : callable, ``'first_found'`` or ``None``, optional
            see :meth:`NDArithmeticMixin.add`

        handle_meta : callable, ``'first_found'`` or ``None``, optional
            see :meth:`NDArithmeticMixin.add`

        compare_wcs : callable, ``'first_found'`` or ``None``, optional
            see :meth:`NDArithmeticMixin.add`

        uncertainty_correlation : ``Number`` or `~numpy.ndarray`, optional
            see :meth:`NDArithmeticMixin.add`

        operation_ignores_mask : bool, optional
            When True, masked values will be excluded from operations;
            otherwise the operation will be performed on all values,
            including masked ones.

        axis : int or tuple of ints, optional
            axis or axes over which to perform collapse operations like min, max, sum or mean.

        kwargs :
            Any other parameter that should be passed to the
            different :meth:`NDArithmeticMixin._arithmetic_mask` (or wcs, ...)
            methods.

        Returns
        -------
        result : ndarray or `~astropy.units.Quantity`
            The resulting data as array (in case both operands were without
            unit) or as quantity if at least one had a unit.

        kwargs : `dict`
            The kwargs should contain all the other attributes (besides data
            and unit) needed to create a new instance for the result. Creating
            the new instance is up to the calling method, for example
            :meth:`NDArithmeticMixin.add`.

        )maskmetawcsdatauncertainty_   r   zUnknown prefix z for parameter Nr   )ffr   unit)r   axisr   )dtyper   r   r   z!Not setting psf attribute during .r   )splitKeyErrorr   hasattrr   _arithmetic_wcsr   r   r   r	   npmamasked_array
zeros_likebool_arithmetic_datar   _arithmetic_uncertaintypsfwarningswarn__name__r   _arithmetic_maskr   _arithmetic_meta)self	operationoperandpropagate_uncertaintieshandle_maskhandle_metauncertainty_correlationcompare_wcsoperation_ignores_maskr   kwdskwds2isplittedkwargsuse_masked_arithmasked_inputresults                     Blib/python3.11/site-packages/astropy/nddata/mixins/ndarithmetic.py_arithmeticzNDArithmeticMixin._arithmetic   s   R RBrRR 	R 	RAwwsAHR26q'hqk"8A;// R R RP!PPQPPQQQR   F5MM111xGGU$;$; ( 5 5u ( 2 2u0D07K 38< F5M #d?Dty/D 	 * 
H 9(F1K1K(#)$)ty*@ty#Q#Q#QLL#)$)$)#D#D#DLL  "u11$)TYGGY|$777F 66** ++vT!B!B!B ,   +T*7 )-16v F
 vv&& 	'74+@+@ 	'!YF6N #*$(F=!!( 	'(01D(E(E}%%(01A(B(B}%%$@D$@'	% %
 % &% %F=! 8G$7GK<SMII4FIII"  
 VV$$ 	 "F6NN111y !)',!7!7v!)$)!4!4v2T27K 6:>CFm F6N !F6NN1119 5!)',!7!7v!)$)!4!4v2T27K 38= F6N
 v~s   A&A(c                 *   | j         et          |d          rUt          |d          r|j          || j        |j                  }n || j        t          z  |j        |j         z            }nt          |d          rU|j         ' || j        | j         z  |j        |j         z            }nh || j        | j         z  |j        t          z            }nA|' || j        | j         z  |j        |j         z            }n || j        |d                   }|S )a}  
        Calculate the resulting data.

        Parameters
        ----------
        operation : callable
            see `NDArithmeticMixin._arithmetic` parameter description.

        operand : `NDData`-like instance
            The second operand wrapped in an instance of the same class as
            self.

        kwds :
            Additional parameters.

        Returns
        -------
        result_data : ndarray or `~astropy.units.Quantity`
            If both operands had no unit the resulting data is a simple numpy
            array, but if any of the operands had a unit the return is a
            Quantity.
        Nr   r   r   r   )r   r   r   r   )r,   r-   r.   r5   r<   s        r=   r$   z"NDArithmeticMixin._arithmetic_datab  s*   0 9&!9!9w'' GL,@"49gl;;"I!779U  Wf%% 
	=|'"49	#97<7<;WXX"I*GL<R,R   YtyDI5w|w|7STTFFYtytF|<<<F    c                    | j         )t          | j         t                    st          d          |0|j         )t          |j         t                    st          d          | j         t	          |d          r|j         dS | j         E|j                             d          | _         | j                             ||||          }d| _         |S |L|j         E| j                             d          |_         | j                             ||||          }d|_         |S d|v rt          |d                   nt                      } | j         j        ||||fi |S )a  
        Calculate the resulting uncertainty.

        Parameters
        ----------
        operation : callable
            see :meth:`NDArithmeticMixin._arithmetic` parameter description.

        operand : `NDData`-like instance
            The second operand wrapped in an instance of the same class as
            self.

        result : `~astropy.units.Quantity` or `~numpy.ndarray`
            The result of :meth:`NDArithmeticMixin._arithmetic_data`.

        correlation : number or `~numpy.ndarray`
            see :meth:`NDArithmeticMixin.add` parameter description.

        kwds :
            Additional parameters.

        Returns
        -------
        result_uncertainty : `NDUncertainty` subclass instance or None
            The resulting uncertainty already saved in the same `NDUncertainty`
            subclass that ``self`` had (or ``operand`` if self had no
            uncertainty). ``None`` only if both had no uncertainty.
        NzHUncertainty propagation is only defined for subclasses of NDUncertainty.r   r   r   )r   
isinstancer   	TypeErrorr   	__class__	propagatedict)r,   r-   r.   r<   correlationr5   result_uncert
axis_kwargs           r=   r%   z)NDArithmeticMixin._arithmetic_uncertainty  s   > '
m1
 1
' /  
 #/w2MBB 0 /   #// $3:3F3N 4%  '2<<TBBD ,667FK M  $D   W%8%@"&"2"<"<T"B"BG ,667FK M #'G   5;dNN4<0000J-4#-7FK ;E  r@   c                     | j         	||j         |dS | j         |t          |j                   S |t          |dd          t          | j                   S  || j         |j         fi |S )a  
        Calculate the resulting mask.

        This is implemented as the piecewise ``or`` operation if both have a
        mask.

        Parameters
        ----------
        operation : callable
            see :meth:`NDArithmeticMixin._arithmetic` parameter description.
            By default, the ``operation`` will be ignored.

        operand : `NDData`-like instance
            The second operand wrapped in an instance of the same class as
            self.

        handle_mask : callable
            see :meth:`NDArithmeticMixin.add`

        kwds :
            Additional parameters given to ``handle_mask``.

        Returns
        -------
        result_mask : any type
            If only one mask was present this mask is returned.
            If neither had a mask ``None`` is returned. Otherwise
            ``handle_mask`` must create (and copy) the returned mask.
        Nr   )r   r   getattr)r,   r-   r.   r0   r   r5   s         r=   r*   z"NDArithmeticMixin._arithmetic_mask  s    @ I'"5',:N 4Y7#6GL)))_ > > F DI&&& ;ty',??$???r@   c                 p     || j         |j         fi |st          d          t          | j                   S )aA  
        Calculate the resulting wcs.

        There is actually no calculation involved but it is a good place to
        compare wcs information of both operands. This is currently not working
        properly with `~astropy.wcs.WCS` (which is the suggested class for
        storing as wcs property) but it will not break it neither.

        Parameters
        ----------
        operation : callable
            see :meth:`NDArithmeticMixin._arithmetic` parameter description.
            By default, the ``operation`` will be ignored.

        operand : `NDData` instance or subclass
            The second operand wrapped in an instance of the same class as
            self.

        compare_wcs : callable
            see :meth:`NDArithmeticMixin.add` parameter description.

        kwds :
            Additional parameters given to ``compare_wcs``.

        Raises
        ------
        ValueError
            If ``compare_wcs`` returns ``False``.

        Returns
        -------
        result_wcs : any type
            The ``wcs`` of the first operand is returned.
        zWCS are not equal.)r   
ValueErrorr   )r,   r-   r.   r3   r5   s        r=   r   z!NDArithmeticMixin._arithmetic_wcs  sD    R {48W[99D99 	31222!!!r@   c                 *     || j         |j         fi |S )a  
        Calculate the resulting meta.

        Parameters
        ----------
        operation : callable
            see :meth:`NDArithmeticMixin._arithmetic` parameter description.
            By default, the ``operation`` will be ignored.

        operand : `NDData`-like instance
            The second operand wrapped in an instance of the same class as
            self.

        handle_meta : callable
            see :meth:`NDArithmeticMixin.add`

        kwds :
            Additional parameters given to ``handle_meta``.

        Returns
        -------
        result_meta : any type
            The result of ``handle_meta``.
        )r   )r,   r-   r.   r1   r5   s        r=   r+   z"NDArithmeticMixin._arithmetic_metaB  s"    4 {49gl;;d;;;r@   addition+)nameopc                 6     | j         t          j        ||fi |S N)_prepare_then_do_arithmeticr   addr,   r.   operand2r9   s       r=   rV   zNDArithmeticMixin.add^  s%     0t/TTVTTTr@   subtraction-c                 6     | j         t          j        ||fi |S rT   )rU   r   subtractrW   s       r=   r\   zNDArithmeticMixin.subtractc  1     0t/K(
 
.4
 
 	
r@   multiplication*c                 6     | j         t          j        ||fi |S rT   )rU   r   multiplyrW   s       r=   ra   zNDArithmeticMixin.multiplyj  r]   r@   division/c                 6     | j         t          j        ||fi |S rT   )rU   r   true_dividerW   s       r=   dividezNDArithmeticMixin.divideq  s1     0t/NGX
 
17
 
 	
r@   c                 2     | j         t          j        fi |S rT   )rU   r   sumr,   r9   s     r=   rh   zNDArithmeticMixin.sumx  s    /t/AA&AAAr@   c                 2     | j         t          j        fi |S rT   )rU   r   meanri   s     r=   rk   zNDArithmeticMixin.mean|  s    /t/BB6BBBr@   c                 b    |                     dd           } | j        t          j        fd|i|S Nr/   )poprU   r   minr,   r9   r/   s      r=   ro   zNDArithmeticMixin.min  J     #)**-F"M"M/t/F
 
,C
GM
 
 	
r@   c                 b    |                     dd           } | j        t          j        fd|i|S rm   )rn   rU   r   maxrp   s      r=   rs   zNDArithmeticMixin.max  rq   r@   c                    t          | t                    r| j        }||}| }n* ||          }n| }|t          d           ||          }|8t	          |j        t                    s ||          } |j        ||fi |\  }}n@t	          |j        t                    r |j        |||fi |\  }}n | j        ||fi |\  }} ||fi |S )a  Intermediate method called by public arithmetic (i.e. ``add``)
        before the processing method (``_arithmetic``) is invoked.

        .. warning::
            Do not override this method in subclasses.

        This method checks if it was called as instance or as class method and
        then wraps the operands and the result from ``_arithmetic`` in the
        appropriate subclass.

        Parameters
        ----------
        self_or_cls : instance or class
            ``sharedmethod`` behaves like a normal method if called on the
            instance (then this parameter is ``self``) but like a classmethod
            when called on the class (then this parameter is ``cls``).

        operations : callable
            The operation (normally a numpy-ufunc) that represents the
            appropriate action.

        operand, operand2, kwargs :
            See for example ``add``.

        Result
        ------
        result : `~astropy.nddata.NDData`-like
            Depending how this method was called either ``self_or_cls``
            (called on class) or ``self_or_cls.__class__`` (called on instance)
            is the NDData-subclass that is used as wrapper for the result.
        NzCoperand2 must be given when the method isn't called on an instance.)rB   r
   rD   rC   
issubclassr>   )self_or_clsr-   r.   rX   r9   clsr<   	init_kwdss           r=   rU   z-NDArithmeticMixin._prepare_then_do_arithmetic  sb   J k#455 	# 'C #%
 #g,, C -   c'llG 
 1)
 )
 s8}}H !4 3Ix R R6 R RFII*,=>> 	 /! ! 	! !FII !8 7! ! ! !FI s6''Y'''r@   rT   )NN)r)   
__module____qualname____doc__r   
logical_orr>   r$   r%   r*   r   r+   r   r   	_arit_docrV   r\   ra   rf   rh   rk   ro   rs   rU    r@   r=   r
   r
   g   s<       < <D !%M !!$z z z zx+ + +ZT T Tl-@ -@ -@ -@^," ," ,"\< < <8 Z	
s333U U U 43 \U Z	#666
 
 
 76 \

 Z	 0S999
 
 
 :9 \

 Z	
s333
 
 
 43 \

 B B \B C C \C 
 
 \
 
 
 \
 7;`( `( `( \`( `( `(r@   )r'   copyr   numpyr   astropy.nddata.nduncertaintyr   astropy.unitsr   astropy.utilsr   r   astropy.utils.exceptionsr   astropy.utils.maskedr	   __all__r}   r
   r~   r@   r=   <module>r      s               6 6 6 6 6 6 0 0 0 0 0 0 2 2 2 2 2 2 2 2 7 7 7 7 7 7 ' ' ' ' ' '

P	fJ
( J
( J
( J
( J
( J
( J
( J
( J
( J
(r@   