B
    d0                 @   s6  d Z ddlZddl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mZ ddlmZmZmZ dd	lmZ dd
lmZ ddlmZ ddlmZ dZe Z!ee! Z"ee" Z#e$ddgZ%dd Z&d$ddZ'd%ddZ(d&ddZ)dd Z*dd Z+d'ddZ,dd Z-d d! Z.e*ej/G d"d# d#e
Z	dS )(z(Tools for dealing with LIGOLW XML files.    N)	lsctables)ligolw)ParamLIGOLWContentHandler)TableByName)ColumnTableStream)
FormatFunc
FromPyTypeToPyType)process)r   )Array)default_null_valuereturn_empty_snglreturn_search_summarylegacy_row_id_converterget_table_columnsr   z	ilwd:charzilwd:char_uc             C   s8   |dkrdS |dkrdS |dkr$dS t d| |dS )	zR
    Associate a sensible "null" default value to a given LIGOLW column type.
    )Zreal_4Zreal_8g        )Zint_4sZint_8sr   Zlstring z2Do not know how to initialize column {} of type {}N)NotImplementedErrorformat)col_nameZcol_type r   \/work/yifan.wang/ringdown/master-ringdown-env/lib/python3.7/site-packages/pycbc/io/ligolw.pyr   1   s    r   Fc             C   sN   t  }t jj}x8|D ]0}t|}| r,dnt||| }t||| qW |S )a  
    Function to create a SnglInspiral object where all columns are populated
    but all are set to values that test False (ie. strings to '', floats/ints
    to 0, ...). This avoids errors when you try to create a table containing
    columns you don't care about, but which still need populating. NOTE: This
    will also produce a process_id and event_id with 0 values. For most
    applications these should be set to their correct values.

    Parameters
    ----------
    nones : bool (False)
        If True, just set all columns to None.

    Returns
    --------
    lsctables.SnglInspiral
        The "empty" SnglInspiral object.
    N)r   ZSnglInspiralZSnglInspiralTablevalidcolumnsr   
ColumnNamer   setattr)ZnonesZsnglcolsentryr   valuer   r   r   r   ?   s    

r   c       	      C   s   |dkrg }t  }t jj}x0|D ](}t|}t||| }t||| q"W |rX||_|rb||_	| r|rt
| |_t
| d d |_t
||_t
|d d |_t
| |_t
| d d |_t
||_t
|d d |_|S )aM  
    Function to create a SearchSummary object where all columns are populated
    but all are set to values that test False (ie. strings to '', floats/ints
    to 0, ...). This avoids errors when you try to create a table containing
    columns you don't care about, but which still need populating. NOTE: This
    will also produce a process_id with 0 values. For most applications these
    should be set to their correct values.

    It then populates columns if given them as options.

    Returns
    --------
    lsctables.SeachSummary
        The "empty" SearchSummary object.
    N   g    eA)r   ZSearchSummaryZSearchSummaryTabler   r   r   r   r   instrumentsneventsintZin_start_timeZin_start_time_nsZin_end_timeZin_end_time_nsZout_start_timeZout_start_time_nsZout_end_timeZout_end_time_ns)	
start_timeend_timer!   ZifosZsearch_summaryr   r   r   r   r   r   r   r   [   s,    





r   c          
   C   s   |dkrt jtjd }|dkr&i }tjp.d}| }g }x2| D ]&\}}	t	|	t
t krF|| qFW t|dkrx|D ]}|| qW tj| ||tjdtj |||d}
|
S )zfCreate a LIGOLW process table with sane defaults, add it to a LIGOLW
    document, and return it.
    Nr   zpycbc/)versionZcvs_repositorycvs_entry_timer    comment)ospathbasenamesysargvpycbc_versiondatecopyitemstypetupler
   keysappendlenpopligolw_processZregister_to_xmldocr%   Z
git_branch)documentZprogram_nameZ	detectorsr'   optionsr&   optsZkey_delkeyr   r   r   r   r   create_process_table   s&    


r<   c                sL   | j fdd}i  | jf fdd	}| jf fdd	}|| _ || _|| _| S )a^  Convert from old-style to new-style row IDs on the fly.

    This is loosely adapted from :func:`ligo.lw.utils.ilwd.strip_ilwdchar`.

    Notes
    -----
    When building a ContentHandler, this must be the _outermost_ decorator,
    outside of :func:`ligo.lw.lsctables.use_in`, :func:`ligo.lw.param.use_in`,
    or :func:`ligo.lw.table.use_in`.
    c             S   sj   t | jtrZ| jjtkrZt| jj }t|| jj}t|	dd }t
| j_t|| j_|| || dS )z8Convert values of <Param> elements from ilwdchar to int.:N)
isinstancecurrentr   TypeIDTypesr   strpcdataROWID_PYTYPEsplit
ROWID_TYPEROWID_FORMATFUNC)selfZuri_localnameZqnameZ__orig_endElementNSold_typeold_val	new_valuer   r   r   endElementNS   s    z-legacy_row_id_converter.<locals>.endElementNSc                s   || ||}|j tkrDt|j    fdd}|t||jf< t|_ |jtkrt|j j}|j|krdd |D }|j|kr|d||j  |S )zConvert types in <Column> elements from ilwdchar to int.

        Notes
        -----
        This method is adapted from
        :func:`ligo.lw.utils.ilwd.strip_ilwdchar`.

        c                s   t t | dd S )Nr=   r>   )rE   rC   rF   )	old_value)rJ   r   r   	converter   s    z?legacy_row_id_converter.<locals>.startColumn.<locals>.converterc             S   s   i | ]}|t |qS r   )r   r   ).0namer   r   r   
<dictcomp>   s   z@legacy_row_id_converter.<locals>.startColumn.<locals>.<dictcomp>Name)	rA   rB   r   idrS   rG   r   r   ZsetAttribute)rI   parentattrsZ__orig_startColumnresultrO   r   Zstripped_column_to_valid_column)remapped)rJ   r   startColumn   s    





z,legacy_row_id_converter.<locals>.startColumnc                sd   || |}t |tr`tj jdk	r8 tjM  |j fddtjjD  |S )zConvert values in table <Stream> elements from ilwdchar to int.

        Notes
        -----
        This method is adapted from
        :meth:`ligo.lw.table.TableStream.config`.

        Nc                s0   g | ](\}}| kr( t|f|nd qS )N)r6   rT   )rP   ZpytypeZcolname)loadcolumnsrU   rX   r   r   
<listcomp>   s   z@legacy_row_id_converter.<locals>.startStream.<locals>.<listcomp>)	r?   r   setcolumnnamesrZ   Z
_tokenizerZ	set_typeszipZcolumnpytypes)rI   rU   rV   Z__orig_startStreamrW   )rX   )rZ   rU   r   startStream   s    



z,legacy_row_id_converter.<locals>.startStream)rM   rY   r_   )ZContentHandlerrM   rY   r_   r   )rX   r   r      s    
#r   c             C   s(  t jjj}t |dt| jji}|d k	r<||t 	 _
|t j| jd |tjd| jdd t| |}t| jjrttt| jj| | jjj| jjjf}n$ttt| jj| | jjf}tj| j||d}	t| j|	_|	t j j!d }
||
_| j|
_"||
_#||	 |S )NrS   epochf0zs^-1)unit)	dim_namesr   )$r   sax	xmlreaderAttributesImplLIGO_LWrC   	__class____name__appendChildCommentrD   TimeZfrom_gpsr`   LIGOLWParamfrom_pyvaluera   getattrnumpyZiscomplexobjdataZ	row_stackZaranger5   realimagLIGOLWArraybuildrQ   sampleUnitsZUnitZgetElementsByTagNameZDimZtagNameZStartZScale)Zseriesrc   r'   Z
delta_nameZ
delta_unit
Attributeselemdeltarq   aZdim0r   r   r   _build_series   s0    


r{   c       	      C   s   |dkrt  n|jd }d}t jjj}|t |d|i}x@|  D ]4\}}t	|dddd}||}|t
d| qJW |S )	znAdd a set of PSDs to a LIGOLW XML document. If the document is not
    given, a new one is created first.
    Nr   psdrS   )zFrequency,RealZ	FrequencyZdeltaFzs^-1
instrument)r   ZDocument
childNodesrd   re   rf   rj   rg   r0   r{   rm   rn   )	ZpsddictZxmldocZ	root_namerw   Zlwr}   r|   Z	xmlseriesfsr   r   r   make_psd_xmldoc  s    

r   c             C   sN   |   }d|_d|_t|dddd}|jd |}td|}|| dS )	z\Save an SNR time series into an XML document, in a format compatible
    with BAYESTAR.
    Zsnrr   )rl   zTime,Real,ImaginaryNZdeltaTsr>   Zevent_id)ZlalrQ   rv   r{   r~   rj   rm   rn   )Z
snr_seriesr8   Zsngl_inspiral_idZsnr_lalZsnr_xmlZsnr_nodeZ	eid_paramr   r   r   snr_series_to_xml4  s    r   c             C   s:   g }x0| j D ]&}|dd }|| jkr|| qW |S )ah  Return a list of columns that are present in the given table, in a
    format that can be passed to `lsctables.New()`.

    The split on ":" is needed for columns like `process:process_id`, which
    must be listed as `process:process_id` in `lsctables.New()`, but are
    listed as just `process_id` in the `columnnames` attribute of the given
    table.
    r=   r>   )r   rF   r]   r4   )tablecolumnscolZattr   r   r   r   F  s    	
r   c               @   s   e Zd ZdZdS )r   z+Dummy class needed for loading LIGOLW filesN)ri   
__module____qualname____doc__r   r   r   r   r   W  s   r   )F)r   r   r   N)NNNN)N)0r   r(   r+   rp   Zligo.lwr   r   Zligo.lw.ligolwr   r   ZOrigLIGOLWContentHandlerZligo.lw.lsctablesr   Zligo.lw.tabler   r   Zligo.lw.typesr	   r
   r   Zligo.lw.utilsr   r7   Zligo.lw.paramrm   Zligo.lw.arrayr   rt   Zpycbc.versionr%   r-   __all__r"   rE   rG   rH   r\   rB   r   r   r   r<   r   r{   r   r   r   Zuse_inr   r   r   r   <module>   s>   

, 
Z
