Source code for pypeit.spectrographs.wht_isis

"""
Module for WHT/ISIS specific methods.

.. include:: ../include/links.rst
"""
import numpy as np

from pypeit import msgs
from pypeit import telescopes
from pypeit.core import framematch
from pypeit.spectrographs import spectrograph
from pypeit.core import parse
from pypeit.images import detector_container


[docs]class WHTISISSpectrograph(spectrograph.Spectrograph): """ Child to handle WHT/ISIS specific code """ ndet = 1 telescope = telescopes.WHTTelescopePar() url = 'https://www.ing.iac.es/astronomy/instruments/isis/'
[docs] def init_meta(self): """ Define how metadata are derived from the spectrograph files. That is, this associates the PypeIt-specific metadata keywords with the instrument-specific header cards using :attr:`meta`. """ self.meta = {} # Required (core) self.meta['ra'] = dict(ext=0, card='RA') self.meta['dec'] = dict(ext=0, card='DEC') self.meta['target'] = dict(ext=0, card='OBJECT') self.meta['decker'] = dict(card=None, compound=True) self.meta['binning'] = dict(card=None, compound=True) self.meta['mjd'] = dict(ext=0, card='MJD-OBS') self.meta['exptime'] = dict(ext=0, card='EXPTIME') self.meta['airmass'] = dict(ext=0, card='AIRMASS') self.meta['decker'] = dict(ext=0, card='ISISLITU') # Extras for config and frametyping self.meta['dispname'] = dict(ext=0, card='ISIGRAT') self.meta['dichroic'] = dict(ext=0, card='ISIDICHR') self.meta['dispangle'] = dict(ext=0, card='CENWAVE', rtol=1e-3) self.meta['slitwid'] = dict(ext=0, card='ISISLITW') self.meta['idname'] = dict(ext=0, card='IMAGETYP') # Lamps self.meta['lampstat01'] = dict(ext=0, card='CAGLAMPS')
[docs] def compound_meta(self, headarr, meta_key): """ Methods to generate metadata requiring interpretation of the header data, instead of simply reading the value of a header card. Args: headarr (:obj:`list`): List of `astropy.io.fits.Header`_ objects. meta_key (:obj:`str`): Metadata keyword to construct. Returns: object: Metadata value read from the header(s). """ if meta_key == 'binning': binspatial = headarr[0]['CCDXBIN'] binspec = headarr[0]['CCDYBIN'] return parse.binning2string(binspec, binspatial) msgs.error("Not ready for this compound meta")
[docs] def configuration_keys(self): """ Return the metadata keys that define a unique instrument configuration. This list is used by :class:`~pypeit.metadata.PypeItMetaData` to identify the unique configurations among the list of frames read for a given reduction. Returns: :obj:`list`: List of keywords of data pulled from file headers and used to constuct the :class:`~pypeit.metadata.PypeItMetaData` object. """ return ['dispname', 'decker', 'binning', 'dispangle', 'dichroic']
[docs] def raw_header_cards(self): """ Return additional raw header cards to be propagated in downstream output files for configuration identification. The list of raw data FITS keywords should be those used to populate the :meth:`~pypeit.spectrographs.spectrograph.Spectrograph.configuration_keys` or are used in :meth:`~pypeit.spectrographs.spectrograph.Spectrograph.config_specific_par` for a particular spectrograph, if different from the name of the PypeIt metadata keyword. This list is used by :meth:`~pypeit.spectrographs.spectrograph.Spectrograph.subheader_for_spec` to include additional FITS keywords in downstream output files. Returns: :obj:`list`: List of keywords from the raw data files that should be propagated in output files. """ return ['ISIGRAT', 'ISISLITU', 'CCDXBIN', 'CCDYBIN', 'CENWAVE', 'ISIDICHR']
[docs] def pypeit_file_keys(self): """ Define the list of keys to be output into a standard PypeIt file. Returns: :obj:`list`: The list of keywords in the relevant :class:`~pypeit.metadata.PypeItMetaData` instance to print to the :ref:`pypeit_file`. """ return super().pypeit_file_keys() + ['slitwid']
[docs]class WHTISISBlueSpectrograph(WHTISISSpectrograph): """ Child to handle WHT/ISIS blue specific code """ name = 'wht_isis_blue' camera = 'ISISb' comment = 'Blue camera'
[docs] def get_detector_par(self, det, hdu=None): """ Return metadata for the selected detector. Args: det (:obj:`int`): 1-indexed detector number. hdu (`astropy.io.fits.HDUList`_, optional): The open fits file with the raw image of interest. If not provided, frame-dependent parameters are set to a default. Returns: :class:`~pypeit.images.detector_container.DetectorContainer`: Object with the detector metadata. """ # Binning # TODO: Could this be detector dependent?? binning = '1,1' if hdu is None else self.get_meta_value(self.get_headarr(hdu), 'binning') # Detector 1 detector_dict = dict( binning = binning, det = 1, dataext = 1, specaxis = 0, specflip = False, spatflip = False, platescale = 0.20, darkcurr = 0.0, # e-/pixel/hour saturation = 65535., nonlinear = 0.76, mincounts = -1e10, numamplifiers = 1, gain = np.atleast_1d(1.2), ronoise = np.atleast_1d(5.0), datasec = np.atleast_1d('[:,2:4030]'), ) return detector_container.DetectorContainer(**detector_dict)
[docs] @classmethod def default_pypeit_par(cls): """ Return the default parameters to use for this instrument. Returns: :class:`~pypeit.par.pypeitpar.PypeItPar`: Parameters required by all of PypeIt methods. """ par = super().default_pypeit_par() # Ignore PCA par['calibrations']['slitedges']['sync_predict'] = 'nearest' # JFH Is this correct? # Processing steps par.reset_all_processimages_par(use_overscan=False) # Make a bad pixel mask par['calibrations']['bpm_usebias'] = True # Set pixel flat combination method par['calibrations']['pixelflatframe']['process']['combine'] = 'median' # Change the wavelength calibration method par['calibrations']['wavelengths']['method'] = 'full_template' par['calibrations']['wavelengths']['lamps'] = ['NeI', 'ArI', 'ArII', 'CuI'] par['calibrations']['wavelengths']['n_first'] = 3 par['calibrations']['wavelengths']['n_final'] = 5 par['calibrations']['wavelengths']['sigdetect'] = 10.0 # Do not flux calibrate par['fluxcalib'] = None # Set the default exposure time ranges for the frame typing par['calibrations']['biasframe']['exprng'] = [None, 0.001] par['calibrations']['darkframe']['exprng'] = [999999, None] # No dark frames par['calibrations']['pinholeframe']['exprng'] = [999999, None] # No pinhole frames par['calibrations']['arcframe']['exprng'] = [None, 120] par['calibrations']['standardframe']['exprng'] = [None, 120] par['scienceframe']['exprng'] = [90, None] return par
[docs] def config_specific_par(self, scifile, inp_par=None): """ Modify the PypeIt parameters to hard-wired values used for specific instrument configurations. Args: scifile (:obj:`str`): File to use when determining the configuration and how to adjust the input parameters. inp_par (:class:`~pypeit.par.parset.ParSet`, optional): Parameter set used for the full run of PypeIt. If None, use :func:`default_pypeit_par`. Returns: :class:`~pypeit.par.parset.ParSet`: The PypeIt parameter set adjusted for configuration specific parameter values. """ # Start with instrument wide par = super().config_specific_par(scifile, inp_par=inp_par) # Wavelength calibrations if self.get_meta_value(scifile, 'dispname') == 'R1200B': par['calibrations']['wavelengths']['reid_arxiv'] = 'wht_isis_blue_1200_4800.fits' return par
[docs] def check_frame_type(self, ftype, fitstbl, exprng=None): """ Check for frames of the provided type. Args: ftype (:obj:`str`): Type of frame to check. Must be a valid frame type; see frame-type :ref:`frame_type_defs`. fitstbl (`astropy.table.Table`_): The table with the metadata for one or more frames to check. exprng (:obj:`list`, optional): Range in the allowed exposure time for a frame of type ``ftype``. See :func:`pypeit.core.framematch.check_frame_exptime`. Returns: `numpy.ndarray`_: Boolean array with the flags selecting the exposures in ``fitstbl`` that are ``ftype`` type frames. """ good_exp = framematch.check_frame_exptime(fitstbl['exptime'], exprng) if ftype in ['science', 'standard']: return good_exp & (fitstbl['lampstat01'] == 'Off') & (fitstbl['idname'] == 'object') if ftype == 'bias': return good_exp & (fitstbl['idname'] == 'zero') if ftype in ['pixelflat', 'trace']: return good_exp & (fitstbl['lampstat01'] == 'W') & (fitstbl['idname'] == 'flat') if ftype in ['pinhole', 'dark']: # Don't type pinhole or dark frames return np.zeros(len(fitstbl), dtype=bool) if ftype in ['arc', 'tilt']: return good_exp & (fitstbl['lampstat01'] == 'CuNe+CuAr') & (fitstbl['idname'] == 'arc') msgs.warn('Cannot determine if frames are of type {0}.'.format(ftype)) return np.zeros(len(fitstbl), dtype=bool)
[docs]class WHTISISRedSpectrograph(WHTISISSpectrograph): """ Child to handle WHT/ISISr red specific code """ name = 'wht_isis_red' camera = 'ISISr' comment = 'Red camera'
[docs] def get_detector_par(self, det, hdu=None): """ Return metadata for the selected detector. Args: det (:obj:`int`): 1-indexed detector number. hdu (`astropy.io.fits.HDUList`_, optional): The open fits file with the raw image of interest. If not provided, frame-dependent parameters are set to a default. Returns: :class:`~pypeit.images.detector_container.DetectorContainer`: Object with the detector metadata. """ # Binning # TODO: Could this be detector dependent?? binning = '1,1' if hdu is None else self.get_meta_value(self.get_headarr(hdu), 'binning') # Detector 1 detector_dict = dict( binning=binning, det=1, dataext=1, specaxis=0, specflip=False, spatflip=False, platescale=0.22, darkcurr=0.0, # e-/pixel/hour saturation=65535., nonlinear=0.76, mincounts=-1e10, numamplifiers=1, gain=np.atleast_1d(0.98), ronoise=np.atleast_1d(4.0), datasec=np.atleast_1d('[:,:]'), ) return detector_container.DetectorContainer(**detector_dict)
[docs] @classmethod def default_pypeit_par(cls): """ Return the default parameters to use for this instrument. Returns: :class:`~pypeit.par.pypeitpar.PypeItPar`: Parameters required by all of PypeIt methods. """ par = super().default_pypeit_par() # Ignore PCA par['calibrations']['slitedges']['sync_predict'] = 'nearest' # Turn off the overscan par.reset_all_processimages_par(use_overscan=False) # Make a bad pixel mask par['calibrations']['bpm_usebias'] = True # Set pixel flat combination method par['calibrations']['pixelflatframe']['process']['combine'] = 'median' # Change the wavelength calibration method par['calibrations']['wavelengths']['method'] = 'full_template' par['calibrations']['wavelengths']['lamps'] = ['NeI', 'ArI', 'ArII', 'CuI'] par['calibrations']['wavelengths']['sigdetect'] = 10.0 # Do not flux calibrate par['fluxcalib'] = None # Set the default exposure time ranges for the frame typing par['calibrations']['biasframe']['exprng'] = [None, 0.001] par['calibrations']['darkframe']['exprng'] = [999999, None] # No dark frames par['calibrations']['pinholeframe']['exprng'] = [999999, None] # No pinhole frames par['calibrations']['arcframe']['exprng'] = [None, 120] par['calibrations']['standardframe']['exprng'] = [None, 120] par['scienceframe']['exprng'] = [90, None] return par
[docs] def config_specific_par(self, scifile, inp_par=None): """ Modify the PypeIt parameters to hard-wired values used for specific instrument configurations. Args: scifile (:obj:`str`): File to use when determining the configuration and how to adjust the input parameters. inp_par (:class:`~pypeit.par.parset.ParSet`, optional): Parameter set used for the full run of PypeIt. If None, use :func:`default_pypeit_par`. Returns: :class:`~pypeit.par.parset.ParSet`: The PypeIt parameter set adjusted for configuration specific parameter values. """ # Start with instrument wide par = super().config_specific_par(scifile, inp_par=inp_par) # Wavelength calibrations if self.get_meta_value(scifile, 'dispname') == 'R1200R': par['calibrations']['wavelengths']['reid_arxiv'] = 'wht_isis_red_1200_6000.fits' # Return return par
[docs] def check_frame_type(self, ftype, fitstbl, exprng=None): """ Check for frames of the provided type. Args: ftype (:obj:`str`): Type of frame to check. Must be a valid frame type; see frame-type :ref:`frame_type_defs`. fitstbl (`astropy.table.Table`_): The table with the metadata for one or more frames to check. exprng (:obj:`list`, optional): Range in the allowed exposure time for a frame of type ``ftype``. See :func:`pypeit.core.framematch.check_frame_exptime`. Returns: `numpy.ndarray`_: Boolean array with the flags selecting the exposures in ``fitstbl`` that are ``ftype`` type frames. """ good_exp = framematch.check_frame_exptime(fitstbl['exptime'], exprng) if ftype in ['science', 'standard']: return good_exp & (fitstbl['lampstat01'] == 'Off') & (fitstbl['idname'] == 'object') if ftype == 'bias': return good_exp & (fitstbl['idname'] == 'zero') if ftype in ['pixelflat', 'trace']: return good_exp & (fitstbl['lampstat01'] == 'W') & (fitstbl['idname'] == 'flat') if ftype in ['pinhole', 'dark']: # Don't type pinhole or dark frames return np.zeros(len(fitstbl), dtype=bool) if ftype in ['arc', 'tilt']: return good_exp & (fitstbl['lampstat01'] == 'CuNe+CuAr') & (fitstbl['idname'] == 'arc') msgs.warn('Cannot determine if frames are of type {0}.'.format(ftype)) return np.zeros(len(fitstbl), dtype=bool)