"""
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 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 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)