B
    }dK                 @   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mZ ddlm	Z	m
Z
 ddlmZ ddlmZ dd	lmZ d
ZedZeddddddddgZdddddddddZddddd d!d"d#d$ZyddlZW n ek
r   Y n.X d%d& Zeed'ejjZeed(ejjZG d)d* d*ejZed+eZ G d,d- d-eeZ!e!d.eZ"G d/d0 d0e#Z$e%d1e$ d2d3 Z&d4d5 Z'dSd7d8Z(dTd;d<Z)dUd=d>Z*dVd?d@Z+dAdB Z,dCdD Z-dEdF Z.e,e.e-dddde / e"/ dGdHfdIdJZ0dWdKdLZ1dXdMdNZ2e,e.dYdOdPZ3dQdR Z4dS )ZzKWrapper to the nds2-client package, providing network access
to LIGO data.
    N)OrderedDict)reducewraps   )to_gps)NumpyTypeEnum   )kinitz(Duncan Macleod <duncan.macleod@ligo.org>z[a-z]1nds[0-9]\Z)N)znds.ligo.caltech.eduiy  )ZH1)znds.ligo-wa.caltech.eduiy  )ZH0)znds.ligo-wa.caltech.eduiy  )ZL1)znds.ligo-la.caltech.eduiy  )ZL0)znds.ligo-la.caltech.eduiy  )ZV1)znds.ligo.caltech.eduiy  )ZC1)znds40.ligo.caltech.eduiy  )ZC0)znds40.ligo.caltech.eduiy  )r   UNKNOWN)r   Zonline)r   raw)   Zreduced)   zs-trend)   zm-trend)    ztest-pt)@   Zstatic)r
   ONLINEZRAWZRDSSTRENDMTRENDZ
TEST_POINTZSTATIC)r   Zint_2)r   Zint_4)r   Zint_8)r   Zreal_2)r   Zreal_4)r   Z	complex_8)r   Zuint_4)r
   ZINT16ZINT32ZINT64ZFLOAT32ZFLOAT64Z	COMPLEX32ZUINT32c             c   sP   t j}xDttd| |jD ],}t||}|t| d |||ffV  qW dS )zJRegenerate the relevant nds2 type dict from `nds2.channel` itself
        
startswithN)nds2channelfilteroperatormethodcaller__dict__getattrlen)prefixZ	to_stringZchannameattr r    Y/work/yifan.wang/ringdown/master-ringdown-env/lib/python3.7/site-packages/gwpy/io/nds2.py_nds2_attr_dictT   s    

r"   ZCHANNEL_TYPE_Z
DATA_TYPE_c               @   sJ   e Zd ZdZdddZedd Zedd Zed	d
 Zedd Z	dS )	_Nds2EnumzBase class for NDS2 enums
    Nc             C   s   t | |}||_||_|S )N)int__new___value_nds2name)clsvaluer'   objr    r    r!   r%   n   s    z_Nds2Enum.__new__c             C   s   t tj| jS )z3The logical OR of all members in this enum
        )r   r   or_r)   )r(   r    r    r!   anyt   s    z_Nds2Enum.anyc             C   s   dd | D S )z<The list of all recognised NDS2 names for this type
        c             S   s   g | ]
}|j qS r    )r'   ).0xr    r    r!   
<listcomp>~   s    z'_Nds2Enum.nds2names.<locals>.<listcomp>r    )r(   r    r    r!   	nds2namesz   s    z_Nds2Enum.nds2namesc             C   s$   t | j d| j dt |  S )z)DEPRECATED: see ``.nds2names()``
        z.names has been renamed z
.nds2names)warningswarn__name__DeprecationWarningr0   )r(   r    r    r!   names   s    z_Nds2Enum.namesc             C   s|   t |}| r| t|S y| |  S  tk
r`   x"| D ]}| |j kr>|S q>W Y nX td| d| j dS )z>Returns the NDS2 type corresponding to the given name
        'z' is not a valid N)	strisdigitr$   upperKeyErrorlowerr'   
ValueErrorr3   )r(   r   itemr    r    r!   find   s    
z_Nds2Enum.find)N)
r3   
__module____qualname____doc__r%   classmethodr,   r0   r5   r>   r    r    r    r!   r#   k   s   

r#   Nds2ChannelTypec               @   s   e Zd ZdS )_Nds2DataTypeN)r3   r?   r@   r    r    r    r!   rD      s   rD   Nds2DataTypec               @   s   e Zd ZdZdS )
NDSWarningz=Warning about communicating with the Network Data Server
    N)r3   r?   r@   rA   r    r    r    r!   rF      s   rF   alwaysc             C   s:   t | dr| jS t | dr2d| j| | jfS t| S )zReturns the NDS2-formatted name for a channel

    Understands how to format NDS name strings from
    `gwpy.detector.Channel` and `nds2.channel` objects
    ndsnamechannel_type,)hasattrrH   joinr   channel_type_to_stringrI   r7   )r   r    r    r!   _get_nds2_name   s    

rN   c             C   s
   t t| S )z7Maps `_get_nds2_name` for a list of input channels
    )maprN   )channelsr    r    r!   _get_nds2_names   s    rQ   	NDSSERVERc          	   C   sr   g }xht | dD ]T}y|dd\}}W n tk
rF   d}Y n
X t|}||f|kr|||f qW |S )a  Parse the NDSSERVER environment variable into a list of hosts

    Parameters
    ----------
    env : `str`, optional
        environment variable name to use for server order,
        default ``'NDSSERVER'``. The contents of this variable should
        be a comma-separated list of `host:port` strings, e.g.
        ``'nds1.server.com:80,nds2.server.com:80'``

    Returns
    -------
    hostiter : `list` of `tuple`
        a list of (unique) ``(str, int)`` tuples for each host:port
        pair
    rJ   :r   N)osgetenvsplitrsplitr<   r$   append)envhostshostportr    r    r!   parse_nds_env   s    
r]   now u c       	   	   C   s   g }|rt |rt|}tdt| |kr8d| g}n| dg}xb|D ]Z}yt| \}}W n* tk
r   |std|  d Y qFX ||f|krF|||f qFW t	|S )a  Generate a logical ordering of NDS (host, port) tuples for this IFO

    Parameters
    ----------
    ifo : `str`
        prefix for IFO of interest
    env : `str`, optional
        environment variable name to use for server order,
        default ``'NDSSERVER'``. The contents of this variable should
        be a comma-separated list of `host:port` strings, e.g.
        ``'nds1.server.com:80,nds2.server.com:80'``
    epoch : `~gwpy.time.LIGOTimeGPS`, `float`, `str`
        GPS epoch of data requested
    lookback : `float`
        duration of spinning-disk cache. This value triggers defaulting to
        the CIT NDS2 server over those at the LIGO sites

    Returns
    -------
    hro : `list` of `2-tuples <tuple>`
        ordered `list` of ``(host, port)`` tuples
    r^   NzNo default host found for ifo 'r6   )
rT   rU   r]   r   DEFAULT_HOSTSr:   r1   r2   rX   list)	ZiforY   epochZlookbackrZ   ZifolistZdifor[   r\   r    r    r!   host_resolution_order   s    

rc   c             C   s<   ddl }|dkrt| rd}|dkr0|| S || |S )a8  Open an `nds2.connection` to a given host and port

    Parameters
    ----------
    host : `str`
        name of server with which to connect

    port : `int`, optional
        connection port

    Returns
    -------
    connection : `nds2.connection`
        a new open connection to the given NDS host
    r   Ni  )r   NDS1_HOSTNAMEmatch
connection)r[   r\   r   r    r    r!   connect$  s    
rg   c          
   C   sd   y
t | |S  tk
r: } zdt|kr* W dd}~X Y nX td|  d| t t  t | |S )a  Open an `nds2.connection` handling simple authentication errors

    This method will catch exceptions related to kerberos authentication,
    and execute a kinit() for the user before attempting to connect again.

    Parameters
    ----------
    host : `str`
        name of server with which to connect

    port : `int`, optional
        connection port

    Returns
    -------
    connection : `nds2.connection`
        a new open connection to the given NDS host
    zRequest SASL authenticationNzError authenticating against rS   )rg   RuntimeErrorr7   r1   r2   rF   r	   )r[   r\   excr    r    r!   auth_connect@  s    
rj   c                s   t   fdd}|S )zBDecorate a function to create a `nds2.connection` if required
    c                 s\   | dd d krRy|d}W n tk
r:   tdY nX t||dd |d<  | |S )Nrf   r[   z>one of `connection` or `host` is required to query NDS2 serverr\   )getpopr:   	TypeErrorrj   )argskwargsr[   )funcr    r!   wrapped_func`  s    z%open_connection.<locals>.wrapped_func)r   )rp   rq   r    )rp   r!   open_connection]  s    
rr   c                s   t   fdd}|S )zCDecorate a function to translate a type string into an integer
    c                 sh   x\dt fdtffD ]H\}}||d d kr8| ||< qt|| ts||| j||< qW  | |S )Ntypedtype)rC   rE   rk   r,   
isinstancer$   r>   r)   )rn   ro   ZkwdZenum_)rp   r    r!   rq   p  s    z&parse_nds2_enums.<locals>.wrapped_func)r   )rp   rq   r    )rp   r!   parse_nds2_enumsm  s    	rv   c                s   t   fdd}|S )zWrap a function to reset the epoch when finished

    This is useful for functions that wish to use `connection.set_epoch`.
    c           
      sF   | dd }|r| nd }z
 | |S |d k	r@||j|j X d S )Nrf   )rk   Zcurrent_epoch	set_epoch	gps_startgps_stop)rn   ro   rf   rb   )rp   r    r!   rq     s    
z!reset_epoch.<locals>.wrapped_func)r   )rp   rq   r    )rp   r!   reset_epoch|  s    	rz   FALLc	             C   sx   t |ts|pdf}|j|  t |ttfr6||f}n|dkrDt }g }	x*t| D ]}
|	t||
||||d qRW |	S )a  Query an NDS2 server for channel information

    Parameters
    ----------
    channels : `list` of `str`
        list of channel names to query, each can include bash-style globs

    connection : `nds2.connection`, optional
        open NDS2 connection to use for query

    host : `str`, optional
        name of NDS2 server to query, required if ``connection`` is not
        given

    port : `int`, optional
        port number on host to use for NDS2 connection

    sample_rate : `int`, `float`, `tuple`, optional
        a single number, representing a specific sample rate to match,
        or a tuple representing a ``(low, high)` interval to match

    type : `int`, optional
        the NDS2 channel type to match

    dtype : `int`, optional
        the NDS2 data type to match

    unique : `bool`, optional, default: `False`
        require one (and only one) match per channel

    epoch : `str`, `tuple` of `int`, optional
        the NDS epoch to restrict to, either the name of a known epoch,
        or a 2-tuple of GPS ``[start, stop)`` times

    Returns
    -------
    channels : `list` of `nds2.channel`
        list of NDS2 channel objects

    See also
    --------
    nds2.connection.find_channels
        for documentation on the underlying query method

    Examples
    --------
    >>> from gwpy.io.nds2 import find_channels
    >>> find_channels(['G1:DER_DATA_H'], host='nds.ligo.caltech.edu')
    [<G1:DER_DATA_H (16384Hz, RDS, FLOAT64)>]
    r{   N)unique)ru   tuplerw   r$   floatrQ   extend_find_channel)rP   rf   r[   r\   sample_raters   rt   r|   rb   outr   r    r    r!   find_channels  s    :



r   c             C   sj   t |||  \}}| j|||f| }|s0|S t|dkrJdd |D }t|dkrftd| d|S )a<  Internal method to find a single channel

    Parameters
    ----------
    connection : `nds2.connection`, optional
        open NDS2 connection to use for query

    name : `str`
        the name of the channel to find

    ctype : `int`
        the NDS2 channel type to match

    dtype : `int`
        the NDS2 data type to match

    sample_rate : `tuple`
        a pre-formatted rate tuple (see `find_channels`)

    unique : `bool`, optional, default: `False`
        require one (and only one) match per channel

    Returns
    -------
    channels : `list` of `nds2.channel`
        list of NDS2 channel objects, if `unique=True` is given the list
        is guaranteed to have only one element.

    See also
    --------
    nds2.connection.find_channels
        for documentation on the underlying query method
    r   c             S   s   g | ]}|j tjjkr|qS r    )rI   rC   r   r)   )r-   cr    r    r!   r/     s    z!_find_channel.<locals>.<listcomp>r   z)unique NDS2 channel match not found for 'r6   )_strip_ctypeget_protocolr   r   r<   )rf   r   ctypert   r   r|   foundr    r    r!   r     s    $r   c             C   sh   y|  dd\} }W n tk
r(   Y n8X t|j}|dkr`|tjjtjjfkr`| d| 7 } | |fS )zStrip the ctype from a channel name for the given nds server version

    This is needed because NDS1 servers store trend channels _including_
    the suffix, but not raw channels, and NDS2 doesn't do this.
    rJ   r   )rW   r<   rC   r>   r)   r   r   )r   r   protocolZctypestrr    r    r!   r     s    
r   c          	      s   ddl m m}m} ||| tttt| ||f|dd}|	|}	| }
x4t
| |	D ]&\}}	| fdd|	 D |
|< qZW |
S )a  Query an NDS2 server for data availability

    Parameters
    ----------
    channels : `list` of `str`
        list of channel names to query; this list is mapped to NDS channel
        names using :func:`find_channels`.

    start : `int`
        GPS start time of query

    end : `int`
        GPS end time of query

    connection : `nds2.connection`, optional
        open NDS2 connection to use for query

    host : `str`, optional
        name of NDS2 server to query, required if ``connection`` is not
        given

    port : `int`, optional
        port number on host to use for NDS2 connection

    Returns
    -------
    segdict : `~gwpy.segments.SegmentListDict`
        dict of ``(name, SegmentList)`` pairs

    Raises
    ------
    ValueError
        if the given channel name cannot be mapped uniquely to a name
        in the NDS server database.

    See also
    --------
    nds2.connection.get_availability
        for documentation on the underlying query method
    r   )SegmentSegmentListSegmentListDictT)rb   rf   r|   c                s   g | ]} |j |jqS r    )rx   ry   )r-   s)r   r    r!   r/   d  s    z$get_availability.<locals>.<listcomp>)segmentsr   r   r   rw   ra   rO   rN   r   get_availabilityzipZsimple_list)rP   startendrf   r[   r\   r   r   r5   resultr   r   r    )r   r!   r   +  s    -
r   c             C   sD   | d rt | d d } |d r4t |d d d }t | t |fS )aY  Expand a [start, end) interval for use in querying for minute trends

    NDS2 requires start and end times for minute trends to be a multiple of
    60 (to exactly match the time of a minute-trend sample), so this function
    expands the given ``[start, end)`` interval to the nearest multiples.

    Parameters
    ----------
    start : `int`
        GPS start time of query

    end : `int`
        GPS end time of query

    Returns
    -------
    mstart : `int`
        ``start`` rounded down to nearest multiple of 60
    mend : `int`
        ``end`` rounded up to nearest multiple of 60
    <   )r$   )r   r   r    r    r!   minute_trend_timesi  s
    r   )rR   )rR   r^   r_   )N)N)F)r   )NNN)5rA   enumr   rT   rer1   collectionsr   	functoolsr   r   timer   Z
utils.enumr   Zkerberosr	   
__author__compilerd   r`   Z_NDS2_CHANNEL_TYPEZ_NDS2_DATA_TYPEr   ModuleNotFoundErrorr"   dictr   rM   Zdata_type_to_stringIntFlagr#   rC   rD   rE   UserWarningrF   simplefilterrN   rQ   r]   rc   rg   rj   rr   rv   rz   r,   r   r   r   r   r   r    r    r    r!   <module>   s   
5
 
0

G
:
;