B
    }dJ              	   @   s  d Z ddlZddlZddlmZmZ ddlmZmZ ddl	m
Z
 ddlmZ d	Zd
Zdd Zd=ddZd>ddZd?ddZd@ddZdd Zdd ZdAddZdBd d!Zd"d# Zd$d% Zd&d' Zd(d) Zd*d+ Zd,d- Zd.d/ ZdCd1d2ZdDd3d4Z d5d6 Z!d7d8 Z"d9d: Z#d;d< Z$dS )Ez@I/O utilities for GWF files using the lalframe or frameCPP APIs
    N   )SegmentSegmentList)to_gpsLIGOTimeGPS   )
read_cache)	file_pathz(Duncan Macleod <duncan.macleod@ligo.org>s   IGWDc          	   O   s   |dk	r>|  }|d z|dtkr.dS W d|| X |dk	r|drTdS |dryt|}W n tk
r~   dS X |d jdrdS dS )zIdentify a filename or file object as GWF

    This function is overloaded in that it will also identify a cache file
    as 'gwf' if the first entry in the cache contains a GWF file extension
    Nr      Tz.gwf)z.lcfz.cacheF)tellseekreadGWF_SIGNATUREendswithr   IOErrorpath)originfilepathfileobjargskwargsloccache r   X/work/yifan.wang/ringdown/master-ringdown-env/lib/python3.7/site-packages/gwpy/io/gwf.pyidentify_gwf'   s"    	


r   rc             C   sH   |dkrt dddlm} t| } |dkr:|t| S |t| S )a  Open a filename for reading or writing GWF format data

    Parameters
    ----------
    filename : `str`
        the path to read from, or write to

    mode : `str`, optional
        either ``'r'`` (read) or ``'w'`` (write)

    Returns
    -------
    `LDAStools.frameCPP.IFrameFStream`
        the input frame stream (if `mode='r'`), or
    `LDAStools.frameCPP.IFrameFStream`
        the output frame stream (if `mode='w'`)
    )r   wzmode must be either 'r' or 'w'r   )frameCPPr   )
ValueError	LDAStoolsr   r	   IFrameFStreamstrZOFrameFStream)filenamemoder   r   r   r   open_gwfE   s    r%   GZIPc       	      C   s   ddl m} ddlm}m} t|ts.|| }|dkr@||j }t| d}t||j	r\|g}x"|D ]}|
|t|t| qbW dS )a  Write a list of frame objects to a file

    **Requires:** |LDAStools.frameCPP|_

    Parameters
    ----------
    filename : `str`
        path to write into

    frames : `list` of `LDAStools.frameCPP.FrameH`
        list of frames to write into file

    compression : `int`, `str`, optional
        name of compresion algorithm to use, or its endian-appropriate
        ID, choose from

        - ``'RAW'``
        - ``'GZIP'``
        - ``'DIFF_GZIP'``
        - ``'ZERO_SUPPRESS'``
        - ``'ZERO_SUPPRESS_OTHERWISE_GZIP'``

    compression_level : `int`, optional
        compression level for given method, default is ``6`` for GZIP-based
        methods, otherwise ``0``
    r   )r   r   )CompressionDefaultCompressionLevelNr   )r    r   	_framecppr'   r(   
isinstanceintnamer%   FrameHZ
WriteFrame)	r#   framescompressionZcompression_levelr   r'   r(   streamframer   r   r   write_frames`   s    



r2   gwpyc       
      C   s   ddl m} ddlm} | }t| }||j|j}|	| |dk	rX|
t| x&|p`g D ]}	||||	 | qbW || || |S )a  Create a new :class:`~LDAStools.frameCPP.FrameH`

    **Requires:** |LDAStools.frameCPP|_

    Parameters
    ----------
    time : `float`, optional
        frame start time in GPS seconds

    duration : `float`, optional
        frame length in seconds

    name : `str`, optional
        name of project or other experiment description

    run : `int`, optional
        run number (number < 0 reserved for simulated data); monotonic for
        experimental runs

    ifos : `list`, optional
        list of interferometer prefices (e.g. ``'L1'``) associated with this
        frame

    Returns
    -------
    frame : :class:`~LDAStools.frameCPP.FrameH`
        the newly created frame header
    r   )r   r   )DetectorLocationN)r    r   r)   r5   r-   r   ZGPSTimeZ
gpsSecondsZgpsNanoSecondsZSetGTimeZSetDtfloatZAppendFrDetectorZGetDetectorZSetNameZSetRun)
timedurationr,   runZifosr   r5   r1   Zgpsprefixr   r   r   create_frame   s    


r;      c          
   C   sp   ddl m} | jdr"| jdkr*td|t| |||d| j	d j
}|tt| jj
t|  |S )u7  Create a `~frameCPP.FrAdcData` from a `~gwpy.types.Series`

    .. note::

       Currently this method is restricted to 1-dimensional arrays.

    Parameters
    ----------
    series : `~gwpy.types.Series`
        the input data array to store

    frame_epoch : `float`, `int`, optional
        the GPS start epoch of the `Frame` that will contain this
        data structure

    Returns
    -------
    frdata : `~frameCPP.FrAdcData`
        the newly created data structure

    Notes
    -----
    See Table 10 (§4.3.2.4) of LIGO-T970130 for more details
    r   )r   sr   z>only 1-dimensional timeseries data can be written as FrAdcData)r    r   xunitis_equivalentndim	TypeErrorZ	FrAdcData_series_namedxtovalueZSetTimeOffsetr6   r   x0)seriesframe_epochZchannelgroupZ	channelidnbitsr   Zfrdatar   r   r   create_fradcdata   s    rJ   c             C   s   | j drt| jS dS )Nr=   r   )r>   r?   absxspan)rG   r   r   r   _get_series_trange   s    
rM   c             C   s:   | j drt| jS | jdkr6| jdr6t| jS dS )NHzr   r   )r>   r?   rK   rL   r@   yunitZyspan)rG   r   r   r   _get_series_frange   s
    

rP   c
             C   sv   ddl m}
 |dkrt| }|dkr,t| }|
t| t|p@| jt| |t	| |t
t| jjt| |||||	
S )u  Create a `~frameCPP.FrAdcData` from a `~gwpy.types.Series`

    .. note::

       Currently this method is restricted to 1-dimensional arrays.

    Parameters
    ----------
    series : `~gwpy.types.Series`
        the input data array to store

    frame_epoch : `float`, `int`, optional
        the GPS start epoch of the `Frame` that will contain this
        data structure

    comment : `str`, optional
        comment

    type : `int`, `str`, optional
        type of data object

    subtype : `int`, `str`, optional
        subtype for f-Series

    trange : `float`, optional
        duration of sampled data

    fshift : `float`, optional
        frequency in the original data that corresponds to 0 Hz in the
        heterodyned series

    phase : `float`, optional
        phase of the heterodyning signal at start of dataset

    frange : `float`, optional
        frequency range

    bandwidth : `float, optional
        reoslution bandwidth

    Returns
    -------
    frdata : `~frameCPP.FrAdcData`
        the newly created data structure

    Notes
    -----
    See Table 17 (§4.3.2.11) of LIGO-T970130 for more details
    r   )r   N)r    r   rM   rP   Z
FrProcDatarB   r"   r,   _get_frprocdata_type_get_frprocdata_subtyper6   r   rF   rE   )rG   rH   commenttypesubtypeZtrangefshiftphaseZfrange	bandwidthr   r   r   r   create_frprocdata  s     4rY   c          	   C   sd   ddl m} | jds td|t| t|p4| jd| j	
d jtt| jjt| ||S )u  Create a `~frameCPP.FrAdcData` from a `~gwpy.types.Series`

    .. note::

       Currently this method is restricted to 1-dimensional arrays.

    Parameters
    ----------
    series : `~gwpy.types.Series`
        the input data array to store

    frame_epoch : `float`, `int`, optional
        the GPS start epoch of the `Frame` that will contain this
        data structure

    fshift : `float`, optional
        frequency in the original data that corresponds to 0 Hz in the
        heterodyned series

    phase : `float`, optional
        phase of the heterodyning signal at start of dataset

    Returns
    -------
    frdata : `~frameCPP.FrSimData`
        the newly created data structure

    Notes
    -----
    See Table 20 (§4.3.2.14) of LIGO-T970130 for more details
    r   )r   r=   z0only timeseries data can be written as FrSimDatar   )r    r   r>   r?   rA   Z	FrSimDatarB   r"   r,   rC   rD   rE   r6   r   rF   )rG   rH   rS   rV   rW   r   r   r   r   create_frsimdataL  s     rZ   c             C   s   ddl m} ddlm} || jd | jjt| jj	d}|
t| t|| j| j|t| j	}tj| jdgd| dd< |S )aV  Create a `~frameCPP.FrVect` from a `~gwpy.types.Series`

    .. note::

       Currently this method is restricted to 1-dimensional arrays.

    Parameters
    ----------
    series : `~gwpy.types.Series`
        the input data array to store

    Returns
    -------
    frvect : `~frameCPP.FrVect`
        the newly created data vector
    r   )r   r   )
FrVectTypeC)requirementsN)r    r   r)   r[   Z	DimensionshaperC   rE   r"   unitZFrVectrB   r+   findZdtyper@   numpyrequireZGetDataArray)rG   r   r[   ZdimsZvectr   r   r   create_frvect|  s    
rc   c             C   s   t t| S )a?  Find the total number of channels in this framefile

    **Requires:** |LDAStools.frameCPP|_

    Parameters
    ----------
    framefile : `str`
        path to GWF-format file on disk

    Returns
    -------
    n : `int`
        the total number of channels found in the table of contents for this
        file
    )lenget_channel_names)	framefiler   r   r   num_channels  s    rg   c             C   sB   t | } x t|D ]\}}| |kr|S qW td|  d| dS )a  Find the channel type in a given GWF file

    **Requires:** |LDAStools.frameCPP|_

    Parameters
    ----------
    channel : `str`, `~gwpy.detector.Channel`
        name of data channel to find

    framefile : `str`
        path of GWF file in which to search

    Returns
    -------
    ctype : `str`
        the type of the channel ('adc', 'sim', or 'proc')

    Raises
    ------
    ValueError
        if the channel is not found in the table-of-contents
    'z%' not found in table-of-contents for N)r"   _iter_channelsr   )channelrf   r,   type_r   r   r   get_channel_type  s    rl   c             C   s*   t | } xt|D ]}| |krdS qW dS )a  Determine whether a channel is stored in this framefile

    **Requires:** |LDAStools.frameCPP|_

    Parameters
    ----------
    channel : `str`
        name of channel to find

    framefile : `str`
        path of GWF file to test

    Returns
    -------
    inframe : `bool`
        whether this channel is included in the table of contents for
        the given framefile
    TF)r"   iter_channel_names)rj   rf   r,   r   r   r   channel_in_frame  s
    rn   c             c   s    xt | D ]\}}|V  q
W dS )am  Iterate over the names of channels found in a GWF file

    **Requires:** |LDAStools.frameCPP|_

    Parameters
    ----------
    framefile : `str`
        path of GWF file to read

    Returns
    -------
    channels : `generator`
        an iterator that will loop over the names of channels as read from
        the table of contents of the given GWF file
    N)ri   )rf   r,   _r   r   r   rm     s    rm   c             C   s   t t| S )a  Return a list of all channel names found in a GWF file

    This method just returns

    >>> list(iter_channel_names(framefile))

    **Requires:** |LDAStools.frameCPP|_

    Parameters
    ----------
    framefile : `str`
        path of GWF file to read

    Returns
    -------
    channels : `list` of `str`
        a `list` of channel names as read from the table of contents of
        the given GWF file
    )listrm   )rf   r   r   r   re   
  s    re   c             c   sj   ddl m} t| |js"t| d} |  }x:dD ]2}| }x$t|d|  D ]}||fV  qPW q0W dS )zYields the name and type of each channel in a GWF file TOC

    **Requires:** |LDAStools.frameCPP|_

    Parameters
    ----------
    framefile : `str`, `LDAStools.frameCPP.IFrameFStream`
        path of GWF file, or open file stream, to read
    r   )r   r   )ZSimZProcZADCZGetN)r    r   r*   r!   r%   GetTOClowergetattr)rf   r   toctypenameZtypenr,   r   r   r   ri   !  s    


ri   Tc             C   s0   t  }x | D ]}|t|||d qW | S )a  Returns the segments containing data for a channel

    **Requires:** |LDAStools.frameCPP|_

    A frame is considered to contain data if a valid FrData structure
    (of any type) exists for the channel in that frame.  No checks
    are directly made against the underlying FrVect structures.

    Parameters
    ----------
    paths : `list` of `str`
        a list of GWF file paths

    channel : `str`
        the name to check in each frame

    warn : `bool`, optional
        emit a `UserWarning` when a channel is not found in a frame

    Returns
    -------
    segments : `~gwpy.segments.SegmentList`
        the list of segments containing data
    )warn)r   extend_gwf_channel_segmentsZcoalesce)pathsrj   rv   segmentsr   r   r   r   data_segments5  s    
r{   c             #   s   t |    }| }| }| } fdddD }xtt|||D ]\}\}	}
}xx|D ]P}y||| W n ttfk
r   w`Y nX |g}t	|	|
}t
||| V  P q`W |rLtd| d| d|   qLW dS )zIYields the segments containing data for ``channel`` in this GWF path
    c                s"   g | ]}t  d |  dqS )ZReadFrData)rs   title).0rk   )r0   r   r   
<listcomp>^  s   z)_gwf_channel_segments.<locals>.<listcomp>)procsimZadcrh   z' not found in frame z of N)r%   rq   Z	GetGTimeSZ	GetGTimeNZGetDt	enumeratezip
IndexErrorr   r   r   warningsrv   )r   rj   rv   rt   ZsecsZnanoZdurZreadersir=   nsdtr   epochr   )r0   r   rx   T  s(    
 

rx   c             C   s   t | tr| S |t|   S )z}Handle a type string, or just return an `int`

    Only to be called in relation to FrProcDataType and FrProcDataSubType
    )r*   r+   r"   upper)rk   enumr   r   r   	_get_types  s    
r   c             C   s   ddl m} |dk	rt||S | jdkr<| jdr<|j}nr| jdkrZ| jdrZ|j}nT| jdkrl|j}nB| jdkr| jdr| j	dr|j
}n| jdkr|j}n|j}|S )u   Determine the appropriate `FrProcDataType` for this series

    Notes
    -----
    See Table 17 (§4.3.2.11) of LIGO-T970130 for more details
    r   )FrProcDataTypeNr=   rN   r   )r)   r   r   r@   r>   r?   ZTIME_SERIESZFREQUENCY_SERIESZOTHER_1D_SERIES_DATArO   ZTIME_FREQUENCYZMULTI_DIMENSIONALUNKNOWN)rG   rk   r   r   r   r   rQ   }  s"    



rQ   c             C   s4   ddl m} |dk	rt||S | jdkr.|jS |jS )u   Determine the appropriate `FrProcDataSubType` for this series

    Notes
    -----
    See Table 17 (§4.3.2.11) of LIGO-T970130 for more details
    r   )FrProcDataSubTypeNZ	coherence)r)   r   r   r_   Z	COHERENCEr   )rG   rU   r   r   r   r   rR     s    

rR   c             C   s   | j pt| jpdpdS )aN  Returns the 'name' of a `Series` that should be written to GWF

    This is basically `series.name or str(series.channel) or ""`

    Parameters
    ----------
    series : `gwpy.types.Series`
        the input series that will be written

    Returns
    -------
    name : `str`
        the name to use when storing this series
     N)r,   r"   rj   )rG   r   r   r   rB     s    rB   )r   )r&   N)r   Nr3   r4   N)r   r   r   r<   )	r   NNNNr   r   Nr   )r   Nr   r   )T)T)%__doc__r   ra   rz   r   r   r7   r   r   r   r   utilsr	   
__author__r   r   r%   r2   r;   rJ   rM   rP   rY   rZ   rc   rg   rl   rn   rm   re   ri   r{   rx   r   rQ   rR   rB   r   r   r   r   <module>   sB   

/
7 
-  
H
0- 


 