Source code for uvex_transients.utils.lightcurve_archive
"""Access to the packaged literature light-curve archive (``test_data/transients/lightcurves.h5``).
The archive groups every calibration light curve used by the Sphinx transient-type galleries
(``docs/source/transients/*.rst``) under ``/<transient_type>/<transient>/<field>``, where
``<transient_type>`` matches one of the `uvex_transients.transients` modules (``kilonovae``,
``lfbots``, ``supernovae``, ``tdes``), ``<transient>`` is ``<designation>_<citekey>`` (e.g.
``gw170817_waxman``), and ``<field>`` is an observable such as ``L_bol`` or ``T_phot``. Each leaf is
an `~astropy.table.QTable` with ``time`` and ``<field>`` columns as unit-aware `~astropy.units.Quantity`
columns, plus a ``reference`` entry in ``.meta`` recording the source.
Supernovae are additionally split by spectroscopic classification, so their ``<transient_type>`` is
``supernovae/<class>`` with ``<class>`` one of ``Ia``, ``II``, ``IIP``, ``IIb``, ``Ib``, ``Ic``,
``Ic-BL`` or ``SLSN-I`` (e.g. ``archive.table("supernovae/IIb", "2011dh_lyman2016", "L_bol")``).
:meth:`LightcurveArchive.types` lists only top-level groups, so use :meth:`LightcurveArchive.events`
on ``"supernovae"`` to list the classes.
"""
from pathlib import Path
import h5py
from astropy.table import QTable
import uvex_transients
__all__ = ["LightcurveArchive"]
def _default_archive_path() -> Path:
return Path(uvex_transients.__file__).parent.parent / "test_data" / "transients" / "lightcurves.h5"
[docs]
class LightcurveArchive:
"""
Read-only access to the packaged literature light-curve archive.
Parameters
----------
path : str or pathlib.Path, optional
Path to the archive HDF5 file. Defaults to the packaged
``test_data/transients/lightcurves.h5``.
Examples
--------
>>> archive = LightcurveArchive()
>>> archive.types() # doctest: +SKIP
['kilonovae', 'lfbots', 'supernovae', 'tdes']
>>> lbol = archive.table(
... "kilonovae", "gw170817_waxman", "L_bol"
... ) # doctest: +SKIP
>>> lbol["time"], lbol["L_bol"] # doctest: +SKIP
"""
def __init__(self, path: str | Path | None = None):
"""
Initialize the light-curve archive.
Parameters
----------
path : str or pathlib.Path, optional
Path to the archive HDF5 file. If not provided, use the packaged
``test_data/transients/lightcurves.h5`` archive.
"""
self.path = Path(path) if path is not None else _default_archive_path()
[docs]
def types(self) -> list[str]:
"""
Return the transient types available in the archive.
Returns
-------
list of str
Sorted names of the top-level transient-type groups.
"""
with h5py.File(self.path, "r") as f:
return sorted(f.keys())
[docs]
def events(self, transient_type: str) -> list[str]:
"""
Return the transients available under a transient type.
Parameters
----------
transient_type : str
Name of the transient-type group, such as ``"kilonovae"`` or
``"supernovae/IIb"``.
Returns
-------
list of str
Sorted transient identifiers of the form
``<designation>_<citekey>``.
"""
with h5py.File(self.path, "r") as f:
return sorted(f[transient_type].keys())
[docs]
def fields(self, transient_type: str, event: str) -> list[str]:
"""
Return the observable fields available for a transient.
Parameters
----------
transient_type : str
Name of the transient-type group, such as ``"kilonovae"`` or
``"supernovae/IIb"``.
event : str
Transient identifier of the form ``<designation>_<citekey>``.
Returns
-------
list of str
Sorted observable field names, such as ``"L_bol"`` or
``"T_phot"``.
"""
with h5py.File(self.path, "r") as f:
keys = f[f"{transient_type}/{event}"].keys()
return sorted(k for k in keys if not k.endswith("__table_column_meta__"))
[docs]
def table(self, transient_type: str, event: str, field: str) -> QTable:
"""
Return the ``time``/``<field>`` light curve for one transient as a `~astropy.table.QTable`.
Parameters
----------
transient_type : str
One of :meth:`types`, e.g. ``"supernovae"``.
event : str
One of :meth:`events`, e.g. ``"1999em_bersten2009"``.
field : str
One of :meth:`fields`, e.g. ``"L_bol"`` or ``"T_phot"``.
Returns
-------
astropy.table.QTable
Columns ``time`` and ``<field>``, both unit-aware. ``.meta["reference"]`` records the
literature source.
"""
return QTable.read(self.path, path=f"{transient_type}/{event}/{field}")
def __repr__(self) -> str:
try:
types = self.types()
n_events = sum(len(self.events(t)) for t in types)
except OSError:
return f"<LightcurveArchive path={self.path!s} (not found)>"
return f"<LightcurveArchive path={self.path!s} types={types} n_events={n_events}>"