Source code for mosviz.loaders.jwst_loaders

import numpy as np
from astropy.io import fits
from astropy.wcs import WCS
from astropy.table import Table
from glue.core import Data
from glue.core.coordinates import coordinates_from_header, coordinates_from_wcs

from .utils import mosviz_spectrum1d_loader, mosviz_spectrum2d_loader, mosviz_cutout_loader, mosviz_level2_loader


__all__ = ['pre_nirspec_spectrum1d_reader', 'pre_nirspec_spectrum2d_reader',
           'pre_nircam_image_reader', 'pre_nirspec_level2_reader']


@mosviz_spectrum1d_loader("NIRSpec 1D Spectrum")
def nirspec_spectrum1d_reader(file_name):
    with fits.open(file_name) as hdulist:
        header = hdulist['PRIMARY'].header

    tab = Table.read(file_name)

    data = Data(label="1D Spectrum")
    data.header = header
    data.add_component(tab['WAVELENGTH'], "Wavelength")
    data.add_component(tab['FLUX'], "Flux")
    data.add_component(tab['ERROR'], "Uncertainty")

    return data


@mosviz_spectrum2d_loader('NIRSpec 2D Spectrum')
def nirspec_spectrum2d_reader(file_name):
    """
    Data loader for simulated NIRSpec 2D spectrum.

    This function extracts the DATA, QUALITY, and VAR
    extensions and returns them as a glue Data object.

    It then uses the header keywords of the DATA extension
    to detemine the wavelengths.
    """

    hdulist = fits.open(file_name)

    data = Data(label="2D Spectrum")
    data.header = hdulist['PRIMARY'].header
    data.coords = coordinates_from_header(hdulist[1].header)
    data.add_component(hdulist['SCI'].data, 'Flux')
    data.add_component(np.sqrt(hdulist['CON'].data), 'Uncertainty')

    hdulist.close()

    return data


[docs]@mosviz_spectrum1d_loader('Pre NIRSpec 1D Spectrum') def pre_nirspec_spectrum1d_reader(file_name): """ Data loader for MOSViz 1D spectrum. This function extracts the DATA, QUALITY, and VAR extensions and returns them as a glue Data object. It then uses the header keywords of the DATA extension to detemine the wavelengths. """ hdulist = fits.open(file_name) # make wavelength a seperate component in addition to coordinate # so you can plot it on the x axis wavelength = np.linspace(hdulist['DATA'].header['CRVAL1'], hdulist['DATA'].header['CRVAL1'] * hdulist['DATA'].header['CDELT1'], hdulist['DATA'].header['NAXIS1'])[::-1] data = Data(label='1D Spectrum') data.header = hdulist['DATA'].header data.add_component(wavelength, 'Wavelength') data.add_component(hdulist['DATA'].data, 'Flux') data.add_component(np.sqrt(hdulist['VAR'].data), 'Uncertainty') hdulist.close() return data
[docs]@mosviz_spectrum2d_loader('Pre NIRSpec 2D Spectrum') def pre_nirspec_spectrum2d_reader(file_name): """ Data loader for simulated NIRSpec 2D spectrum. This function extracts the DATA, QUALITY, and VAR extensions and returns them as a glue Data object. It then uses the header keywords of the DATA extension to detemine the wavelengths. """ hdulist = fits.open(file_name) data = Data(label='2D Spectrum') data.header = hdulist['DATA'].header data.coords = coordinates_from_header(hdulist[1].header) data.add_component(hdulist['DATA'].data, 'Flux') data.add_component(np.sqrt(hdulist['VAR'].data), 'Uncertainty') hdulist.close() return data
[docs]@mosviz_cutout_loader('NIRCam Image') def pre_nircam_image_reader(file_name): """ Data loader for simulated NIRCam image. This is for the full image, where cut-outs will be created on the fly. From the header: If ISWFS is T, structure is: - Plane 1: Signal [frame3 - frame1] in ADU - Plane 2: Signal uncertainty [sqrt(2*RN/g + \|frame3\|)] If ISWFS is F, structure is: - Plane 1: Signal from linear fit to ramp [ADU/sec] - Plane 2: Signal uncertainty [ADU/sec] Note that in the later case, the uncertainty is simply the formal uncertainty in the fit parameter (eg. uncorrelated, WRONG!). Noise model to be implemented at a later date. In the case of WFS, error is computed as SQRT(2*sigma_read + \|frame3\|) which should be a bit more correct - ~Fowler sampling. The FITS file has a single extension with a data cube. The data is the first slice of the cube and the uncertainty is the second slice. """ hdulist = fits.open(file_name) data = Data(label='NIRCam Image') data.header = hdulist[0].header wcs = WCS(hdulist[0].header) # drop the last axis since the cube will be split data.coords = coordinates_from_wcs(wcs) data.add_component(hdulist[0].data, 'Flux') data.add_component(hdulist[0].data / 100, 'Uncertainty') hdulist.close() return data
[docs]@mosviz_level2_loader('Pre NIRSpec 2D Level 2 Spectra') def pre_nirspec_level2_reader(file_name): """ THIS IS A TEST! """ #TODO The level 2 file has multiple exposures. #TODO the level 2 test file has SCI extensions with different shapes. #TODO hdulist = fits.open(file_name) data = Data(label='2D Spectra') hdulist[1].header['CTYPE2'] = 'Spatial Y' data.header = hdulist[1].header # This is a stop gap fix to let fake data be ingested as # level 2 apectra. The level 2 file we have for testing # right now has SCI extensions with different sized arrays # among them. It remains to be seen if this is a expected # feature of level 2 spectra, or just a temporary glitch. # In case it's actually what lvel 2 spectral files look # like, proper handling must be put in place to allow # glue Data objects with different sized components. Or, # if that is not feasible, to properly cut the arrays so # as to make them all of the same size. The solution below # is a naive interpretation of this concept. x_min = 10000 y_min = 10000 for k in range(1, len(hdulist)): if 'SCI' in hdulist[k].header['EXTNAME']: x_min = min(x_min, hdulist[k].data.shape[0]) y_min = min(y_min, hdulist[k].data.shape[1]) # hdulist[k].header['CTYPE2'] = 'Spatial Y' # wcs = WCS(hdulist[1].header) # original WCS has both axes named "LAMBDA", glue requires unique component names # data.coords = coordinates_from_wcs(wcs) # data.header = hdulist[k].header # data.add_component(hdulist[1].data['FLUX'][0], 'Flux') count = 1 for k in range(1, len(hdulist)): if 'SCI' in hdulist[k].header['EXTNAME']: data.add_component(hdulist[k].data[0:x_min, 0:y_min], 'Flux_' + '{:03d}'.format(count)) count += 1 # data.add_component(1 / np.sqrt(hdulist[1].data['IVAR'][0]), 'Uncertainty') return data