Source code for sndata.csp._dr3

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-

"""This module defines the CSP DR3 API"""

import os
from typing import List

import numpy as np
from astropy.table import Table

from sndata.base_classes import DefaultParser, PhotometricRelease
from sndata.utils import downloads, unit_conversion


def parse_snoopy_path(path: str):
    """Return data from a snoopy file as an astropy table

    Args:
        path: The file path of a snoopy input file

    Returns:
        An astropy table with columns 'time', 'band', 'mag', and 'mag_err'
    """

    out_table = Table(
        names=['time', 'band', 'mag', 'mag_err'],
        dtype=[float, object, float, float]
    )

    with open(path) as ofile:
        # Get meta data from first line
        name, z, ra, dec = ofile.readline().split()
        out_table.meta['obj_id'] = name
        out_table.meta['ra'] = float(ra)
        out_table.meta['dec'] = float(dec)
        out_table.meta['z'] = float(z)
        out_table.meta['z_err'] = None

        # Read photometric data from the rest of the file
        band = None
        for line in ofile.readlines():
            line_list = line.split()
            if line.startswith('filter'):
                band = line_list[1]
                continue

            time, mag, mag_err = line_list
            out_table.add_row([time, band, mag, mag_err])

    out_table['time'] = unit_conversion.convert_to_jd(out_table['time'], format='snpy')
    return out_table


def fix_dr3_readme(readme_path: str):
    """Fix typos in the DR3 CDS Readme so it is machine parsable

    Args:
        readme_path: Path of the README file to fix
    """

    os.chmod(readme_path, 438)  # Make sure we can edit the file
    with open(readme_path, 'r+') as readme:
        lines = readme.readlines()

        # Mistakes in Table 2
        lines[148] = lines[148].replace('[0.734/2.256]?', '?=-')
        lines[150] = lines[150].replace('[0.036/0.198]?', '?')
        lines[153] = lines[153].replace('Wang et al.', '?=- Wang et al.')
        lines[155] = lines[155].replace('Branch et al.', '?=- Branch et al.')
        lines[161] = lines[161].replace('[-11/66]?', '?=-')

        # Mistakes in Table 3
        lines[186] = lines[186].replace('[53263.77/54960.03]?', '?=-')
        lines[189] = lines[189].replace('[0.06/2.71]?', '?')
        lines[190] = lines[190].replace('[53234.7/55165.94]?', '?=-')
        lines[193] = lines[193].replace('[0.6/1.24]?', '?')
        lines[194] = lines[194].replace('[0.278/1.993]?', '?=-')
        lines[195] = lines[195].replace('[0.01/0.175]?', '?')
        lines[196] = lines[196].replace('[0.734/2.256]?', '?=-')
        lines[198] = lines[198].replace('[0.036/0.198]?', '?')
        lines[199] = lines[199].replace('[0.301/1.188]?', '?=-')
        lines[201] = lines[201].replace('[0.005/1.761]?', '?')
        lines[202] = lines[202].replace('[0.06/1.28]?', '?=-')
        lines[204] = lines[204].replace('[0.06/0.067]?', '?')

        readme.seek(0)
        readme.writelines(lines)


[docs]class DR3(DefaultParser, PhotometricRelease): """The ``DR3`` class provides access to data from the third data release of the Carnegie Supernova Project (CSP) which includes natural-system optical (ugriBV) and near-infrared (YJH) photometry of 134 supernovae (SNe) that were observed in 2004-2009 as part of the first stage of the Carnegie Supernova Project (CSP-I). The sample consists of 123 Type Ia SNe, 5 Type Iax SNe, 2 super-Chandrasekhar SN candidates, 2 Type Ia SNe interacting with circumstellar matter, and 2 SN 2006bt-like events. The redshifts of the objects range from z=0.0037 to 0.0835; the median redshift is 0.0241. For 120 (90%) of these SNe, near-infrared photometry was obtained. (Source: Krisciunas et al. 2017) Deviations from the standard UI: - None Cuts on returned data: - None """ survey_name = 'Carnegie Supernova Project' survey_abbrev = 'CSP' release = 'DR3' survey_url = 'https://csp.obs.carnegiescience.edu/news-items/csp-dr3-photometry-released' publications = ('Krisciunas et al. 2017',) ads_url = 'https://ui.adsabs.harvard.edu/abs/2017AJ....154..278K/abstract' _band_names = ( 'u', 'g', 'r', 'i', 'B', 'V0', 'V1', 'V', 'Y', 'J', 'Jrc2', 'H', 'Ydw', 'Jdw', 'Hdw' ) band_names = tuple(f'csp_dr3_{f}' for f in _band_names) zero_point = ( 12.986, 15.111, 14.902, 14.545, 14.328, 14.437, 14.393, 14.439, 13.921, 13.836, 13.836, 13.510, 13.770, 13.866, 13.502 ) def __init__(self): """Define local and remote paths of data""" super().__init__() # Local paths self._photometry_dir = self._data_dir / 'DR3' self._filter_dir = self._data_dir / 'filters' self._table_dir = self._data_dir / 'tables' # Define urls for remote data self._photometry_url = 'https://csp.obs.carnegiescience.edu/data/CSP_Photometry_DR3.tgz' self._filter_url = 'https://csp.obs.carnegiescience.edu/data/' self._table_url = 'http://cdsarc.u-strasbg.fr/viz-bin/nph-Cat/tar.gz?J/AJ/154/211' # Filter information self._filter_file_names = ( 'u_tel_ccd_atm_ext_1.2.dat', # u 'g_tel_ccd_atm_ext_1.2.dat', # g 'r_tel_ccd_atm_ext_1.2_new.dat', # r 'i_tel_ccd_atm_ext_1.2_new.dat', # i 'B_tel_ccd_atm_ext_1.2.dat', # B 'V_LC3014_tel_ccd_atm_ext_1.2.dat', # V0 'V_LC3009_tel_ccd_atm_ext_1.2.dat', # V1 'V_tel_ccd_atm_ext_1.2.dat', # V 'Y_SWO_TAM_scan_atm.dat', # Y 'J_old_retrocam_swope_atm.dat', # J 'J_SWO_TAM_atm.dat', # Jrc2 'H_SWO_TAM_scan_atm.dat', # H 'Y_texas_DUP_atm.dat', # Ydw 'J_texas_DUP_atm.dat', # Jdw 'H_texas_DUP_atm.dat' # Hdw ) self._instrument_offsets = { 'csp_dr3_u': -0.06, 'csp_dr3_g': -0.02, 'csp_dr3_r': -0.01, 'csp_dr3_i': 0, 'csp_dr3_B': -0.13, 'csp_dr3_V': -0.02, 'csp_dr3_V0': -0.02, 'csp_dr3_V1': -0.02, 'csp_dr3_Y': 0.63, 'csp_dr3_J': 0.91, 'csp_dr3_Jrc2': 0.90, 'csp_dr3_H': 1.34, 'csp_dr3_Ydw': 0.64, 'csp_dr3_Jdw': 0.90, 'csp_dr3_Hdw': 1.34 } def _get_available_ids(self) -> List[str]: """Return a list of target object IDs for the current survey""" files = self._photometry_dir.glob('*.txt') return sorted(f.stem.split('_')[0].lstrip('SN') for f in files) def _get_data_for_id(self, obj_id: str, format_table: bool = True) -> Table: """Returns data for a given object ID Args: obj_id: The ID of the desired object format_table: Format for use with ``sncosmo`` (Default: True) Returns: An astropy table of data for the given ID """ # Read data file for target file_path = self._photometry_dir / f'SN{obj_id}_snpy.txt' data_table = parse_snoopy_path(file_path) data_table.meta['obj_id'] = data_table.meta['obj_id'].lstrip('SN') if format_table: # Convert band names to package standard data_table['band'] = 'csp_dr3_' + data_table['band'] offsets = np.array([self._instrument_offsets[b] for b in data_table['band']]) data_table['mag'] += offsets # Add flux values data_table['zp'] = self.get_zp_for_band(data_table['band']) data_table['zpsys'] = np.full(len(data_table), 'ab') data_table['flux'] = 10 ** ((data_table['mag'] - data_table['zp']) / -2.5) data_table['fluxerr'] = np.log(10) * data_table['flux'] * data_table['mag_err'] / 2.5 return data_table def _download_module_data(self, force: bool = False, timeout: float = 15): """Download data for the current survey / data release Args: force: Re-Download locally available data timeout: Seconds before timeout for individual files/archives """ downloads.download_tar( url=self._table_url, out_dir=self._table_dir, skip_exists=self._table_dir, mode='r:gz', force=force, timeout=timeout ) # Fix formatting of CDS Readme readme_path = self._table_dir / 'ReadMe' if readme_path.exists(): fix_dr3_readme(readme_path) # Download photometry downloads.download_tar( url=self._photometry_url, out_dir=self._data_dir, skip_exists=self._photometry_dir, mode='r:gz', force=force, timeout=timeout ) for file_name in self._filter_file_names: downloads.download_file( url=self._filter_url + file_name, destination=self._filter_dir / file_name, force=force, timeout=timeout )