Source code for scopesim.effects.spectral_efficiency

"""Spectral grating efficiencies."""

import numpy as np

from astropy.io import fits
from astropy import units as u
from astropy.wcs import WCS
from astropy.table import Table

from .effects import Effect
from .ter_curves import TERCurve
from .ter_curves_utils import apply_throughput_to_cube
from ..utils import figure_factory, get_logger


logger = get_logger(__name__)


[docs]class SpectralEfficiency(Effect): """ Applies the grating efficiency (blaze function) for a SpectralTraceList. Input Data Format ----------------- The efficiency curves are taken from a fits file `filename`with a structure similar to the trace definition file (see `SpectralTraceList`). The required extensions are: - 0 : PrimaryHDU [header] - 1 : BinTableHDU or TableHDU[header, data] : Overview table of all traces - 2..N : BinTableHDU or TableHDU : Efficiency curves, one per trace. The tables must have the two columns `wavelength` and `efficiency` Note that there must be one extension for each trace defined in the `SpectralTraceList`. Extensions for other traces are ignored. EXT 0 : PrimaryHDU ++++++++++++++++++ Required header keywords: - ECAT : int : Extension number of overview table, normally 1 - EDATA : int : Extension number of first Trace table, normally 2 No data is required in this extension EXT 1 : (Bin)TableHDU : Overview of traces ++++++++++++++++++++++++++++++++++++++++++ No special header keywords are required in this extension. Required Table columns: - description : str : identifier for each trace - extension_id : int : which extension is each trace in EXT 2 : (Bin)TableHDU : Efficiencies for individual traces ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Required header keywords: - EXTNAME : must be identical to the `description` in EXT 1 Required Table columns: - wavelength : float : [um] - efficiency : float : number [0..1] """ def __init__(self, **kwargs): super().__init__(**kwargs) if "hdulist" in kwargs and isinstance(kwargs["hdulist"], fits.HDUList): self._file = kwargs["hdulist"] params = {"z_order": [630]} self.meta.update(params) self.efficiencies = self.get_efficiencies()
[docs] def get_efficiencies(self): """Read effciencies from file, returns a dictionary.""" hdul = self._file self.ext_data = hdul[0].header["EDATA"] self.ext_cat = hdul[0].header["ECAT"] self.catalog = Table(hdul[self.ext_cat].data) efficiencies = {} for row in self.catalog: params = {col: row[col] for col in row.colnames} params.update(self.meta) hdu = self._file[row["extension_id"]] name = hdu.header['EXTNAME'] tbl = Table.read(hdu) wavelength = tbl['wavelength'].quantity efficiency = tbl['efficiency'].value effic_curve = TERCurve(wavelength=wavelength, transmission=efficiency, **params) efficiencies[name] = effic_curve hdul.close() return efficiencies
[docs] def apply_to(self, obj, **kwargs): """Interface between FieldOfView and SpectralEfficiency.""" trace_id = obj.trace_id try: effic = self.efficiencies[trace_id] except KeyError: logger.warning("No grating efficiency for trace %s", trace_id) return obj wcs = WCS(obj.hdu.header).spectral wave_cube = wcs.all_pix2world(np.arange(obj.hdu.data.shape[0]), 0)[0] wave_cube = (wave_cube * u.Unit(wcs.wcs.cunit[0])).to(u.AA) obj.hdu = apply_throughput_to_cube(obj.hdu, effic.throughput) return obj
[docs] def plot(self): """Plot the grating efficiencies.""" fig, axes = figure_factory() for name, effic in self.efficiencies.items(): wave = effic.throughput.waveset axes.plot(wave.to(u.um), effic.throughput(wave), label=name) axes.set_xlabel("Wavelength [um]") axes.set_ylabel("Grating efficiency") axes.set_title(f"Grating efficiencies {self.display_name}") axes.legend() return fig