B
    ~d;!                 @   s  d Z ddlZddlZddlmZ ddlmZ ddlmZ ddl	Z	ddl
mZ ddlZddlmZ ddlmZ d	Zejd
ejdejdejdejdejdejdejdejdejdi
Zdd e D Ze	jeje	j eje	j!eje	j"eje	j#eje	j$eje	j%eje	j&eje	j'eje	j(eji
Z)dd e) D Z*dd e* D Z+e,dZ-dd Z.efddZ/dd Z0ej1ej2ej3ej4ej5e6dej7gZ8d d! Z9d"d# Z:d$d% Z;ed&d' ej<D Z=dS )(z]Utilies for interacting with the LIGO Algorithm Library.

This module requires lal >= 6.14.0
    N)OrderedDict)Fraction)reduce)units   )to_gpsz(Duncan Macleod <duncan.macleod@ligo.org>ZINT2ZINT4ZINT8ZUINT2ZUINT4ZUINT8ZREAL4ZREAL8ZCOMPLEX8Z	COMPLEX16c             C   s   i | ]\}}||qS  r   ).0kvr   r   [/work/yifan.wang/ringdown/master-ringdown-env/lib/python3.7/site-packages/gwpy/utils/lal.py
<dictcomp>:   s    r   c             C   s   i | ]\}}t | |qS r   )LAL_TYPE_STR)r	   r
   r   r   r   r   r   I   s   c             C   s   i | ]\}}||qS r   r   )r	   r
   r   r   r   r   r   K   s    z(U?INT|REAL|COMPLEX)\d+c          	   C   sV   | t kr| S | tkrt|  S yt| }t|j S  ttfk
rP   tdY nX dS )a  Convert the input python type to a LAL type string

    Examples
    --------
    To convert a python type:

    >>> from gwpy.utils.lal import to_lal_type_str
    >>> to_lal_type_str(float)
    'REAL8'

    To convert a `numpy.dtype`:

    >>> import numpy
    >>> to_lal_type_str(numpy.dtype('uint32'))
    'UINT4'

    To convert a LAL type code:

    >>> to_lal_type_str(11)
    'REAL8'

    Raises
    ------
    KeyError
        if the input doesn't map to a LAL type string
    z%Failed to map {!r} to LAL type stringN)	LAL_TYPE_FROM_STRr   numpydtypeLAL_TYPE_STR_FROM_NUMPYtype	TypeErrorKeyError
ValueError)pytyper   r   r   r   to_lal_type_strP   s    

r   c             C   s   t | }t|d|||S )a7  Returns the lal method for the correct type

    Parameters
    ----------
    pytype : `type`, `numpy.dtype`
        the python type, or dtype, to map

    prefix : `str`
        the function name prefix (before the type tag)

    suffix : `str`
        the function name suffix (after the type tag)

    Raises
    ------
    AttributeError
        if the function is not found

    Examples
    --------
    >>> from gwpy.utils.lal import find_typed_function
    >>> find_typed_function(float, 'Create', 'Sequence')
    <built-in function CreateREAL8Sequence>
    z	{0}{1}{2})r   getattrformat)r   prefixsuffixmodulelaltyper   r   r   find_typed_function{   s    r   c             C   sL   t | tst| } | j}t|}|r2|d tkr@t|dt|d  S )a  Convert the data type of a LAL instance or type into a numpy data type.

    Parameters
    ----------
    laltype : `SwigPyObject` or `type`
        the input LAL instance or type

    Returns
    -------
    dtype : `type`
        the numpy data type, such as `numpy.uint32`, `numpy.float64`, etc.

    Raises
    ------
    ValueError
        if the numpy data type cannot be inferred from the LAL object
    r   z# has no known numpy type equivalent)
isinstancer   __name__LAL_TYPE_REGEXmatchLAL_NUMPY_FROM_TYPE_STRr   )r   namer#   r   r   r   from_lal_type   s    

r&   Zstrainc       	      C   s   t | trt| } |  } t| j}|rN| rNt	dt
| }d}nt	 }| j}xt| j| jD ]p\}}yt|}W n4 tk
r } zd| df|_ W dd}~X Y nX t|}|j|j|< |jd |j|< qlW ||fS )au  Convert the input unit into a `lal.Unit` and a scaling factor.

    Parameters
    ----------
    aunit : `~astropy.units.Unit`, `str`
        the input unit

    Returns
    -------
    unit : `lal.Unit`
        the LAL representation of the base unit.

    scale : `float`
        the linear scaling factor that should be applied to any associated
        data, see _Notes_ below.

    Notes
    -----
    Astropy supports 'scaled' units of the form ``<N> <u>``
    ere ``<N>`` is a `float` and ``<u>`` the base `astropy.units.Unit`,
    e.g. ``'123 m'``, e.g:

    >>> from astropy.units import Quantity
    >>> x = Quantity(4, '123m')
    >>> print(x)
    4.0 123 m
    >>> print(x.decompose())
    492.0 m

    LAL doesn't support scaled units in this way, so this function simply
    returns the scaling factor of the unit so that it may be applied
    manually to any associated data.

    Examples
    --------
    >>> print(to_lal_unit('m**2 / kg ** 4'))
    (m^2 kg^-4, 1.0)
    >>> print(to_lal_unit('123 m'))
    (m, 123.0)

    Raises
    ------
    ValueError
        if LAL doesn't understand the base units for the input
    z10^   z"LAL has no unit corresponding to ''N)r    strr   UnitZ	decomposer   log10scale
is_integerlalintzipbasesZpowersLAL_UNIT_INDEXindexr   argsr   	numeratorunitNumeratordenominatorunitDenominatorMinusOne)	ZaunitZpow10lunitr,   basepoweriexcfracr   r   r   to_lal_unit   s&    /

r?   c             C   s.   t tjdd tt| j| jD d| j  S )a  Convert a LALUnit` into a `~astropy.units.Unit`

    Parameters
    ----------
    lunit : `lal.Unit`
        the input unit

    Returns
    -------
    unit : `~astropy.units.Unit`
        the Astropy representation of the input

    Raises
    ------
    TypeError
        if ``lunit`` cannot be converted to `lal.Unit`
    ValueError
        if Astropy doesn't understand the base units for the input
    c             s   s4   | ],\}\}}t | tt|t|d   V  qdS )r'   N)r2   r   r/   )r	   r<   numZdenr   r   r   	<genexpr>#  s   z from_lal_unit.<locals>.<genexpr>
   )r   operatormul	enumerater0   r6   r8   Z
powerOfTen)r9   r   r   r   from_lal_unit  s    rF   c             C   s   t | } t| j| jS )ae  Convert the given GPS time to a `lal.LIGOTimeGPS` object

    Parameters
    ----------
    gps : `~gwpy.time.LIGOTimeGPS`, `float`, `str`
        input GPS time, can be anything parsable by :meth:`~gwpy.time.to_gps`

    Returns
    -------
    ligotimegps : `lal.LIGOTimeGPS`
        a SWIG-LAL `~lal.LIGOTimeGPS` representation of the given GPS time
    )r   r.   ZLIGOTimeGPSZ
gpsSecondsZgpsNanoSeconds)Zgpsr   r   r   to_lal_ligotimegps,  s    rG   c             c   s   | ]}|j j|j fV  qd S )N)Z
frDetectorr   )r	   Zifor   r   r   rA   ?  s    rA   )>__doc__rC   recollectionsr   	fractionsr   	functoolsr   r   Zastropyr   r.   timer   detectorZ
gwpy_units
__author__ZI2_TYPE_CODEZI4_TYPE_CODEZI8_TYPE_CODEZU2_TYPE_CODEZU4_TYPE_CODEZU8_TYPE_CODEZS_TYPE_CODEZD_TYPE_CODEZC_TYPE_CODEZZ_TYPE_CODEr   itemsr   Zint16Zint32Zint64Zuint16Zuint32Zuint64Zfloat32Zfloat64Z	complex64Z
complex128ZLAL_TYPE_FROM_NUMPYr   r$   compiler"   r   r   r&   ZmeterZkilogramsecondZampereZKelvinr*   countr2   r?   rF   rG   ZCachedDetectorsZLAL_DETECTORSr   r   r   r   <module>   sf   

+L 