Source code for libra.spectra.irtf

"""
This submodule taken from: https://github.com/bmorris3/irtf_templates
"""

import os

import astropy.units as u
import h5py
import numpy as np
from astropy.modeling.blackbody import blackbody_lambda

from .spectrum import Spectrum1D
from .spectral_types import spt_to_teff

__all__ = ['IRTFTemplate']

hdf5_archive_path = os.path.join(os.path.dirname(__file__), os.pardir, 'data',
                                 'irtf_templates.hdf5')


class TemplateArchive(object):
    def __init__(self):
        self._hdf5 = None

    @property
    def hdf5(self):
        return h5py.File(hdf5_archive_path, 'r+')

archive = TemplateArchive()


[docs]class IRTFTemplate(Spectrum1D): def __init__(self, sptype, fill_gaps=True): """ Parameters ---------- sptype : str Spectral type of target. """ with archive.hdf5 as f: data = f['templates'][sptype.upper()][:] header = {k: v for k, v in f['templates'][sptype.upper()].attrs.items()} self.wavelength = data[:, 0] * u.um self.flux = data[:, 1] * u.W * u.m**-2 * u.um**-1 self.error = data[:, 2] self.header = header try: self.t_eff = spt_to_teff(sptype) except KeyError: self.t_eff = None if fill_gaps: self.fill_gaps()
[docs] def fill_gaps(self): """ Fill gaps in template spectra at strong telluric absorption bands. Will do a quadratic fit to the nearby continuum and fill the gap by extrapolating the smooth quadratic across the gap. """ normed_template = self.flux# / self.flux.max() diffs = np.diff(self.wavelength) indices = np.where(diffs > 100*np.median(diffs))[0] gap_fillers = [] for i in indices: wl_min, wl_max = self.wavelength[i], self.wavelength[i+1] delta_lambda = self.wavelength[i] - self.wavelength[i-1] p = np.polyfit(self.wavelength[i-500:i+500], normed_template[i-500:i+500], 2) gap_wavelengths = np.arange(wl_min.value+delta_lambda.value, wl_max.value-delta_lambda.value, delta_lambda.value) * u.um fit = np.polyval(p, gap_wavelengths) gap_fillers.append([gap_wavelengths, fit]) # Extend to 5.3 um if self.wavelength.max() < 5.3 * u.um: p = np.polyfit(self.wavelength[-1000:], normed_template[-1000:], 1) gap_wavelengths = np.arange(self.wavelength.max().value, 5.3, delta_lambda.value) * u.um fit = np.polyval(p, gap_wavelengths) gap_fillers.append([gap_wavelengths, fit]) gap_wls = [i[0] for i in gap_fillers] gap_fluxes = [i[1] for i in gap_fillers] wl_unit = self.wavelength.unit fl_unit = self.flux.unit self.wavelength = np.concatenate([self.wavelength] + gap_wls) self.flux = np.concatenate([self.flux] + gap_fluxes) sort = np.argsort(self.wavelength) self.wavelength = u.Quantity(self.wavelength[sort].value, wl_unit)
self.flux = u.Quantity(self.flux[sort].value, fl_unit)
[docs] def scale_temperature(self, delta_teff, plot=False): """ Scale up or down the flux according to the ratio of blackbodies between the effective temperature of the IRTF template spectrum and the new effective temperature ``t_eff + delta_teff``. Parameters ---------- delta_teff : float Change in effective temperature to approximate Returns ------- spec : `~libra.IRTFTemplate` Scaled spectral template to ``t_eff + delta_teff`` """ new_t_eff = self.t_eff + delta_teff old_bb = blackbody_lambda(self.wavelength, self.t_eff) new_bb = blackbody_lambda(self.wavelength, new_t_eff) ratio_bbs = (new_bb / old_bb).value if plot: import matplotlib.pyplot as plt fig, ax = plt.subplots(figsize=(10, 8)) ax.plot(self.wavelength, self.flux, label='init') ax.plot(self.wavelength, old_bb * np.max(self.flux) / np.max(old_bb), label='old bb') ax.plot(self.wavelength, new_bb * np.max(self.flux) / np.max(old_bb), label='new bb', ls='--') ax.plot(self.wavelength, ratio_bbs * self.flux, label='scaled', ls=':') ax.legend() return Spectrum1D(self.wavelength, ratio_bbs * self.flux,
header=self.header, t_eff=new_t_eff)