B
    dWB                 @   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	m
Z
 ddl	mZ d	Zdd
lmZ ddlmZ d#ddZdd Zdd Zdd Zdd ZG dd dejZG dd dejZd$ddZd%ddZd&dd Zd'd!d"ZdS )(z7
LIGO Light-Weight XML coincidence analysis front end.
    N)LIGOTimeGPS)
CacheEntry)segments   )offsetvector)packingz"Kipp Cannon <kipp.cannon@ligo.org>)date)versionFc             C   s@   |rt d| pd tjd | dk	r,t| }ntj}dd |D S )z
	Parse a LAL cache file named filename into a list of
	lal.utils.CacheEntry objects.  If filename is None then input is
	taken from stdin.
	zreading %s ...stdin)fileNc             S   s   g | ]}t |qS  )r   ).0liner   r   Z/work/yifan.wang/ringdown/master-ringdown-env/lib/python3.7/site-packages/lalburst/cafe.py
<listcomp>G   s    zload_cache.<locals>.<listcomp>)printsysstderropenr
   )filenameverbosefr   r   r   
load_cache;   s    
r   c             C   s$   t  }x| D ]}||jO }qW |S )z^
	Construct a coalesced segmentlistdict object from a list of
	lal.utils.CacheEntry objects.
	)r   segmentlistdict)cachescr   r   r   cache_to_seglistdictJ   s    
r   c                s0   x*|   D ]} fdd|D |dd< q
W dS )z
	Convert the times in a segmentlist dictionary to floats relative to
	origin.  The purpose is to allow segment lists stored as
	LIGOTimeGPS times to be manipulated more quickly without loss of
	precision.  The modification is done in place.
	c             3   s2   | ]*}t t|d    t|d   V  qdS )r   r   N)r   segmentfloat)r   seg)originr   r   	<genexpr>f   s    z,segmentlistdict_normalize.<locals>.<genexpr>N)
itervalues)seglistdictr!   seglistr   )r!   r   segmentlistdict_normalize^   s    r&   c             C   s   |   } t| }t| j}t }xNt|dD ]>}t||r0| j	| | 
| }|j  ||O }q0W |j	| |S )a  
	Compute the segments for which data is required in order to perform
	a complete coincidence analysis given the segments for which data
	is available and the list of offset vectors to be applied to the
	data during the coincidence analysis.

	seglistdict is a segmentlistdict object defining the instruments
	and times for which data is available.  offset_vectors is a list of
	offset vectors to be applied to the data --- dictionaries of
	instrument/offset pairs.

	The offset vectors in offset_vectors are applied to the input
	segments one by one and the interesection of the shifted segments
	is computed.  The segments surviving the intersection are unshifted
	to their original positions and stored.  The return value is the
	union of the results of this operation.

	In all cases all pair-wise intersections are computed, that is if
	an offset vector lists three instruments then this function returns
	the times when any two of those isntruments are on, including times
	when all three are on.

	For example, let us say that "input" is a segmentlistdict object
	containing segment lists for three instruments, "H1", "H2" and
	"L1".  And let us say that "slides" is a list of dictionaries, and
	is equal to [{"H1":0, "H2":0, "L1":0}, {"H1":0, "H2":10}].  Then if

	output = get_coincident_segmentlistdict(input, slides)

	output will contain, for each of the three instruments, the
	segments (or parts thereof) from the original lists that are
	required in order to perform a triple- and double-coincident
	analyses at zero lag with the three instruments, *and* a
	double-coincident analysis between H1 and H2 with H2 offset by 10
	seconds.

	The segmentlistdict object returned by this function has its
	offsets set to those of the input segmentlistdict.
	   )copysetdictoffsetsr   r   r   Zcomponent_offsetvectorsissubsetupdateZextract_commonkeysclear)r$   offset_vectorsZall_instrumentsZorigoffsetsZcoincseglistsoffset_vectorintersectionr   r   r   get_coincident_segmentlistdicti   s    )

r3   c                s0   x*|   D ]} fdd|D |dd< q
W dS )z
	The opposite of segmentlistdict_normalize(), restores the times in
	a segmentlist dictionary to absolute times.  The modification is
	done in place.
	c             3   s*   | ]"}t  |d    |d  V  qdS )r   r   N)r   r   )r   r    )r!   r   r   r"      s    z.segmentlistdict_unnormalize.<locals>.<genexpr>N)r#   )r$   r!   r%   r   )r!   r   segmentlistdict_unnormalize   s    r4   c               @   s`   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dd Zdd Zdd ZdS )LALCacheBina  
	Subclass of the packing.Bin class representing a LAL file cache.
	The files contained in the bin are available in the .objects
	attribute, which is a list of lal.utils.CacheEntry objects.  The
	.size attribute holds a ligo.segments.segmentlistdict object giving
	the times spanned by the files in the bin.  The .extent attribute
	holds the result of running .extent_all() on the .size attribute.
	c             C   s    t j|  t | _d | _d S )N)r   Bin__init__r   r   sizeextent)selfr   r   r   r7      s    
zLALCacheBin.__init__c             C   s"   t j| ||j | j | _| S )N)r   r6   addr   r8   
extent_allr9   )r:   cache_entryr   r   r   r;      s    zLALCacheBin.addc             G   s"   t jj| f|  | j | _| S )N)r   r6   __iadd__r8   r<   r9   )r:   argsr   r   r   r>      s    zLALCacheBin.__iadd__c             C   s   | j |j k S )N)r9   )r:   otherr   r   r   __lt__   s    zLALCacheBin.__lt__c             C   s   | j |j kS )N)r9   )r:   r@   r   r   r   __le__   s    zLALCacheBin.__le__c             C   s   | j |j kS )N)r9   )r:   r@   r   r   r   __eq__   s    zLALCacheBin.__eq__c             C   s   | j |j kS )N)r9   )r:   r@   r   r   r   __ne__   s    zLALCacheBin.__ne__c             C   s   | j |j kS )N)r9   )r:   r@   r   r   r   __ge__   s    zLALCacheBin.__ge__c             C   s   | j |j kS )N)r9   )r:   r@   r   r   r   __gt__   s    zLALCacheBin.__gt__c             C   s   d tt| jS )N
)joinmapstrobjects)r:   r   r   r   __str__   s    zLALCacheBin.__str__N)__name__
__module____qualname____doc__r7   r;   r>   rA   rB   rC   rD   rE   rF   rL   r   r   r   r   r5      s   r5   c               @   s    e Zd ZdZdd Zdd ZdS )
CafePackerzP
	Packing algorithm implementing the ligolw_cafe file list packing
	algorithm.
	c             C   s\   t || _| jjdd d tdd |D }tdd |D }|| | _| jdksXtdS )	z
		Set the list of offset vectors to be considered when
		deciding the bins in which each file belongs.  Must be
		called before packing any files.  The input is a list of
		dictionaries, each mapping instruments to offsets.
		c             S   s   t |  S )N)sorteditems)r1   r   r   r   <lambda>       z/CafePacker.set_offset_vectors.<locals>.<lambda>)keyc             s   s   | ]}t | V  qd S )N)minvalues)r   r1   r   r   r   r"     s    z0CafePacker.set_offset_vectors.<locals>.<genexpr>c             s   s   | ]}t | V  qd S )N)maxrX   )r   r1   r   r   r   r"     s    r   N)listr0   sortrW   rY   max_gapAssertionError)r:   r0   Z
min_offset
max_offsetr   r   r   set_offset_vectors   s    

zCafePacker.set_offset_vectorsc             C   s  t  }|| g }xtt| jd ddD ]}| j| }|jd |jd | j k rVP xL| jD ]B}|jj	
| |jj	
| |jj|j| dr^|| P q^W |jj	  q,W |jj	  |s| j| n6| j|d }||7 }x|D ]}|| j|7 }qW | j  dS )ag  
		Find all bins in which this lal.utils.CacheEntry instance
		belongs, merge them, and add this cache entry to the
		result.  Create a new bin for this cache entry if it does
		not belong in any of the existing bins.

		The cache entry "belongs" in a bin if after each of the
		preset offset vectors (see the .set_offset_vectors()
		method) is applied to both the contents of a bin and the
		cache entry, any of the segment lists of the bin and cache
		entry are found to intersect.  When checking for
		intersection, only the segment lists whose instrument names
		are listed in the offset vector are compared.
		r   r   )r.   N)r5   r;   rangelenbinsr9   r\   r0   r8   r+   r-   Zis_coincidentr.   appendr/   popr[   )r:   r=   newZmatching_binsnbinr1   destr   r   r   pack  s,    
	


zCafePacker.packN)rM   rN   rO   rP   r_   rj   r   r   r   r   rQ      s   rQ   c          
      s  xt t| jd ddD ]l}| j| ttttj|   dkrPqjd g fddt d D  jd g }|rt	dt
jddd	 |dd D f tjd
 dd t|dd |dd D }g }x|D ]}|t  || j}xbjD ]X}|j|r"q|j}	x8| jD ].}
|	j|
 |	|r0|d | P q0W qW ||d _qW || j||d < qW dS )zX
	Split bins in CafePacker so that each bin has an extent no longer
	than extentlimit.
	r   r`   r   c                s0   g | ](}t jd  |ttj    qS )r   )r   r9   r   abs)r   i)rg   origbinr   r   r   t  s    zsplit_bins.<locals>.<listcomp>z"	splitting cache spanning %s at %sz, c             s   s   | ]}t |V  qd S )N)rJ   )r   r9   r   r   r   r"   v  s    zsplit_bins.<locals>.<genexpr>)r   c             S   s   g | ]}t j| qS r   )r   r   )r   Zboundsr   r   r   r   w  s    N)ra   rb   rc   intmathceilr   rk   r9   r   rJ   rH   r   r   ziprd   r5   Zprotractr\   rK   r   Zdisjointr   r0   r+   r-   Zintersects_segmentr;   )Z
cafepackerextentlimitr   idxZextentsZnewbinsr9   Zextent_plus_max_gapr=   Zcache_entry_segsr1   r   )rg   rm   r   
split_binsT  s0     
24$
rt   c             C   s   g }t |r&dttt |d  }xt|D ]t\}}|| |f }|| |rdtd| tjd t	|d}	x4|j
D ]*}
|d ks|t|
j@ rvtt|
|	d qvW q0W |S )Nz%%s%%0%dd.cacher   zwriting %s ...)r   w)rb   rn   ro   log10	enumeraterd   r   r   r   r   rK   r)   r   rJ   )baserc   instrumentsr   	filenamespatternrg   rh   r   r   
cacheentryr   r   r   write_caches  s    

r}   c             C   s.   x(|D ] }t d| |f |t|g| qW d S )Nz%s%s_)r}   r)   )rx   rc   ry   r   Z
instrumentr   r   r   write_single_instrument_caches  s    
r~   c       	         s  |rt dtjd t|  tdd   D p2dg}t | t | t | |rft dtjd  fdd| D } |rt dtjd | j	d	d
 d g }t
|}|| |rt dt| tjd x\t| D ]P\}}|r|d st dd| t|  |d t|f dtjd || qW |rLt dt| t|f tjd |dk	r|rnt d| tjd t|||d |rt dt| t|f tjd |rt dtjd x|D ]} | j	  qW  |fS )a  
	Transform a LAL cache into a list of caches each of whose contents
	can be subjected to a coincidence analysis independently of the
	contents of the other caches, assuming the coincidence analyses
	will involve the application of the given offset vectors.

	cache is a sequence (e.g., list, tuple, etc.) of
	lal.utils.CacheEntry objects.  offset_vectors is a sequence of
	instrument/offset dictionaries describing the offset vectors to
	consider.  Set verbose to True for verbosity.

	The output is a two-element tuple.  The first element is a
	ligo.segments.segmentlistdict object describing the times for which
	coincident data is available (derived from the segment metadata of
	the input cache).  The second element is a list of LALCacheBin
	objects, providing the file groups.
	zcomputing segment list ...)r   c             S   s"   g | ]}|rt d d |D qS )c             s   s   | ]}|d  V  qdS )r   Nr   )r   r    r   r   r   r"     s    z)ligolw_cafe.<locals>.<listcomp>.<genexpr>)rW   )r   r%   r   r   r   r     s    zligolw_cafe.<locals>.<listcomp>Nzfiltering input cache ...c                s   g | ]}  |jr|qS r   )Zintersects_allr   )r   r   )seglistsr   r   r     s    zsorting input cache ...c             S   s   | j S )N)r   )xr   r   r   rT     rU   zligolw_cafe.<locals>.<lambda>)rV   z1packing files (considering %s offset vectors) ...   z	%.1f%%	(%d files, %d caches)g      Y@r    )endr   z	100.0%%	(%d files, %d caches)z2splitting caches with extent greater than %g s ...)r   z		(%d files, %d caches)zsorting output caches ...)r   r   r   r   rW   rX   r&   r3   r4   r[   rQ   r_   rb   rw   rj   rt   rK   )	r   r0   r   rr   epochZoutputcachespackerrg   r|   r   )r   r   ligolw_cafe  sF    



.

r   )F)F)NF)F)FN)rP   ro   r   Zlalr   Z	lal.utilsr   Zligor    r   r   
__author__Zgit_versionr   __date__r	   __version__r   r   r&   r3   r4   r6   r5   PackerrQ   rt   r}   r~   r   r   r   r   r   <module>   s*   
?.k
m

