B
    d+9                 @   s   d Z ddlZddl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dd	 Zd
defddefddejfddefddefddefddefddefddefddeff
Zdd Zdd  Zde	fd!d"Zd,d#d$Zd-d&d'Zg g g dd(d)fd*d+ZdS ).z1
Reading HDF5 posterior sample chain HDF5 files.
    N)ColumnTable)+LALInferenceHDF5PosteriorSamplesDatasetName)LALINFERENCE_PARAM_FIXED)LALINFERENCE_PARAM_OUTPUT)read_sampleswrite_samplesextract_metadatac             C   s   | S )N )xr
   r
   a/work/yifan.wang/ringdown/master-ringdown-env/lib/python3.7/site-packages/lalinference/io/hdf5.py	_identity    s    r   ZrightascensionraZdeclinationdecZlogdistancedistZdistanceZpolarisationpsiZ	chirpmassZmcZa_spin1Za1Za_spin2Za2Z
tilt_spin1Ztilt1Z
tilt_spin2Ztilt2c             C   s6   x0t D ](\}}}|| jkr|| j|| |< qW d S )N)_colname_mapcolnamescolumnspop)tableZold_namenew_namefuncr
   r
   r   _remap_colnames0   s    
r   c          	      sn   i   fdd}|  | t dkr6tdt dkr`tddt    \}|S )ag  Recursively search an HDF5 group or file for a dataset by name.

    Parameters
    ----------
    group : `h5py.File` or `h5py.Group`
        The file or group to search
    tablename : str
        The name of the table to search for

    Returns
    -------
    table : `h5py.Dataset`
        The dataset whose name is `tablename`

    Raises
    ------
    KeyError
        If the table is not found or if multiple matching tables are found

    Check that we can find a file by name:
    >>> import os.path
    >>> from tempfile import TemporaryDirectory
    >>> table = Table(np.eye(3), names=['a', 'b', 'c'])
    >>> with TemporaryDirectory() as dir:
    ...     filename = os.path.join(dir, 'test.hdf5')
    ...     table.write(filename, path='foo/bar', append=True)
    ...     table.write(filename, path='foo/bat', append=True)
    ...     table.write(filename, path='foo/xyzzy/bat', append=True)
    ...     with h5py.File(filename, 'r') as f:
    ...         _find_table(f, 'bar')
    <HDF5 dataset "bar": shape (3,), type "|V24">

    Check that an exception is raised if the table is not found:
    >>> with TemporaryDirectory() as dir:
    ...     filename = os.path.join(dir, 'test.hdf5')
    ...     table.write(filename, path='foo/bar', append=True)
    ...     table.write(filename, path='foo/bat', append=True)
    ...     table.write(filename, path='foo/xyzzy/bat', append=True)
    ...     with h5py.File(filename, 'r') as f:
    ...         _find_table(f, 'plugh')
    Traceback (most recent call last):
        ...
    KeyError: 'Table not found: plugh'

    Check that an exception is raised if multiple tables are found:
    >>> with TemporaryDirectory() as dir:
    ...     filename = os.path.join(dir, 'test.hdf5')
    ...     table.write(filename, path='foo/bar', append=True)
    ...     table.write(filename, path='foo/bat', append=True)
    ...     table.write(filename, path='foo/xyzzy/bat', append=True)
    ...     with h5py.File(filename, 'r') as f:
    ...         _find_table(f, 'bat')
    Traceback (most recent call last):
        ...
    KeyError: 'Multiple tables called bat exist: foo/bat, foo/xyzzy/bat'
    c                s$   |  d\}}}|kr | | < d S )N/)
rpartition)keyvalue_name)results	tablenamer
   r   visitorq   s    z_find_table.<locals>.visitorr   zTable not found: {0}   z%Multiple tables called {0} exist: {1}z, )Z
visititemslenKeyErrorformatjoinsortedkeysvalues)groupr!   r"   r   r
   )r    r!   r   _find_table6   s    9

r,   c       	   	   C   s  t | d,}|dk	r || }n
t||}t|}W dQ R X x0t|j D ]\}}|jd	| |jd< qNW x|j
 D ]\}}|dks||dks||dks||drq|||jkr|jt|gt| |dtid	d
d q||t|gt| |dtid	 q|W |j  t| |S )a<  Read an HDF5 sample chain file.

    Parameters
    ----------
    filename : str
        The path of the HDF5 file on the filesystem.
    path : str, optional
        The path of the dataset within the HDF5 file.
    tablename : str, optional
        The name of table to search for recursively within the HDF5 file.
        By default, search for 'posterior_samples'.

    Returns
    -------
    table : `astropy.table.Table`
        The sample chain as an Astropy table.

    Test reading a file written using the Python API:
    >>> import os.path
    >>> from tempfile import TemporaryDirectory
    >>> table = Table([
    ...     Column(np.ones(10), name='foo', meta={'vary': FIXED}),
    ...     Column(np.arange(10), name='bar', meta={'vary': LINEAR}),
    ...     Column(np.arange(10) * np.pi, name='bat', meta={'vary': CIRCULAR}),
    ...     Column(np.arange(10), name='baz', meta={'vary': OUTPUT})
    ... ])
    >>> with TemporaryDirectory() as dir:
    ...     filename = os.path.join(dir, 'test.hdf5')
    ...     write_samples(table, filename, path='foo/bar/posterior_samples')
    ...     len(read_samples(filename))
    10

    Test reading a file that was written using the LAL HDF5 C API:
    >>> table = read_samples('test.hdf5')
    >>> table.colnames
    ['uvw', 'opq', 'lmn', 'ijk', 'def', 'abc', 'rst', 'ghi']
    rNzFIELD_{0}_VARYvaryZCLASSVERSIONZTITLEZFIELD_)r   metaT)Zrename_duplicate)h5pyFiler,   r   read	enumerater   r*   r0   r&   items
startswithr   
add_columnr   r$   FIXEDclearr   )	filenamepathr!   fr   icolumnr   r   r
   r
   r   r      s$    &

"

r   c             K   s  |   } xL| j D ]>}d|jkrt|d |dd krHt|jd< qt|jd< qW x`t| j	 D ]N\}}|jd tkrftj
|dd |d d|j |d | j|< | |= qfW x0t| j D ]\}}|jd | jd|< qW | j|fddi| |rt|d	r}xj|	 D ]^\}}	xR|		 D ]F\}
}y||| j|
< W n( tk
rr   td
||
|Y nX q0W qW W dQ R X dS )a  Write an HDF5 sample chain file.

    Parameters
    ----------
    table : `astropy.table.Table`
        The sample chain as an Astropy table.
    filename : str
        The path of the HDF5 file on the filesystem.
    metadata: dict (optional)
        Dictionary of (path, value) pairs of metadata attributes
        to add to the output file
    kwargs: dict
        Any keyword arguments for `astropy.table.Table.write`.

    Check that we catch columns that are supposed to be FIXED but are not:
    >>> table = Table([
    ...     Column(np.arange(10), name='foo', meta={'vary': FIXED})
    ... ])
    >>> write_samples(table, 'bar.hdf5', 'bat/baz') # doctest: +ELLIPSIS
    Traceback (most recent call last):
        ...
    AssertionError:
    Arrays are not equal
    Column foo is a fixed column, but its values are not identical
    ...

    And now try writing an arbitrary example to a temporary file.
    >>> import os.path
    >>> from tempfile import TemporaryDirectory
    >>> table = Table([
    ...     Column(np.ones(10), name='foo', meta={'vary': FIXED}),
    ...     Column(np.arange(10), name='bar', meta={'vary': LINEAR}),
    ...     Column(np.arange(10) * np.pi, name='bat', meta={'vary': CIRCULAR}),
    ...     Column(np.arange(10), name='baz', meta={'vary': OUTPUT})
    ... ])
    >>> with TemporaryDirectory() as dir:
    ...     write_samples(
    ...         table, os.path.join(dir, 'test.hdf5'), path='bat/baz')
    r.   r   r#   Nz>Column {0} is a fixed column, but its values are not identicalzFIELD_{0}_VARYr&   Zhdf5az%Unable to set metadata {0}[{1}] = {2})copyr   r*   r0   npallr8   OUTPUTtupler5   testingZassert_array_equalr&   r   r4   writer1   r2   attrsr%   )r   r:   metadatakwargsr>   Zcolnamer=   hdfZinternal_path
attributesr   r   r
   r
   r   r      s4    )


r   raisec             C   s   || kri | |< x|D ]}|| | kr|dkrt|| | | | kr|dkrR|sRqqt d|||| | | | f q|dkrt| | | tr| | | ||  q| | | || g| | |< q|dkrqt d| q|| | | |< qW dS )zUpdates the sub-dictionary 'key' of 'metadata' with the values from
        'attrs', while enforcing that existing values are equal to those with
        which the dict is updated.
        rL   versionz3Metadata mismatch on level %r for key %r:
	%r != %rappendignorezInvalid value for collision: %rN)
ValueError
isinstancelistrN   )rH   levelrG   strict_versions	collisionr   r
   r
   r   update_metadata  s(    
rV   FTc          	   C   s  t | d}d}	||	 }
t||	|
j| t||	  dkrXtdt||	   t||	  d }d| }	||	 }
t||	|
j|dd |r||
jd	  ||
jd
  ||
jd  |dkrt	}d| d | }	d| d t	 }||	 }
t|||
j|dd |S Q R X dS )a  
        Extract metadata from HDF5 sample chain file

        Parameters
        ----------
        filename : str
            The path of the HDF5 file on the filesystem.
        metadata : dict
            Dict into which to place metadata
        log_noise_evidences : array (optional)
            Array into which to place log noise evidences (if nest = True)
        log_max_likelihoods : array (optional)
            Array into which to place log max likelihoods (if nest = True)
        nlive : array (optional)
            Array into which to place number of live points (if nest = True)
        return_run_identifier : Boolean (optional : default False)
            Whether to return the run identifier
        nest : Boolean (optional : default False)
            Whether to output quantities that only exist for nest runs

        Returns
        -------
        run_identifier : str
            The run identifier
        r-   z/lalinferencer#   z"Multiple run-identifiers found: %rr   z/lalinference/rN   )rU   Zlog_noise_evidenceZlog_max_likelihoodZnumber_live_pointsNr   rO   )
r1   r2   rV   rG   r$   r)   r%   rR   rN   POSTERIOR_SAMPLES)r:   rH   Zlog_noise_evidencesZlog_max_likelihoodsZnliveZ	dset_namenestrT   rJ   Zcurrent_levelr+   Zrun_identifierZcurrent_level_posteriorr
   r
   r   r	   3  s,    r	   )N)rL   )__doc__numpyrA   r1   Zastropy.tabler   r   Zlalinferencer   rW   r   r8   r   rC   __all__r   expr   r   r,   r   r   rV   r	   r
   r
   r
   r   <module>   s0   
MI
I
