"""
Implements the objects used to hold slit edge data.
.. include common links, assuming primary doc root is up one directory
.. include:: ../include/links.rst
"""
import inspect
from IPython import embed
import numpy as np
from pypeit import msgs
from pypeit import datamodel
from pypeit import calibframe
from pypeit.display import display
from pypeit.core import scattlight
from pypeit.images.buildimage import ScatteredLightImage
[docs]
class ScatteredLight(calibframe.CalibFrame):
"""
Defines a generic class for generating a model of the scattered light.
The datamodel attributes are:
.. include:: ../include/class_datamodel_scatteredlight.rst
"""
calib_type = 'ScatteredLight'
"""Name for type of calibration frame."""
calib_file_format = 'fits.gz'
"""File format for the calibration frame file."""
version = '1.0.0'
"""Scattered Light data model version."""
internals = calibframe.CalibFrame.internals
"""
Attributes kept separate from the datamodel.
"""
# Define the data model
datamodel = {'PYP_SPEC': dict(otype=str, descr='PypeIt spectrograph name'),
'pypeline': dict(otype=str, descr='PypeIt pypeline name'),
'detname': dict(otype=str, descr='Identifier for detector or mosaic'),
'nspec': dict(otype=int, descr='Number of pixels in the image spectral direction.'),
'nspat': dict(otype=int, descr='Number of pixels in the image spatial direction.'),
'binning': dict(otype=str, descr='Binning in PypeIt orientation (not the original)'),
'pad': dict(otype=int, descr='Integer number of pixels to mask beyond the slit edges'),
'scattlight_raw': dict(otype=np.ndarray, atype=np.floating,
descr='Image used to construct the edge traces; see '
':class:`~pypeit.images.buildimage.ScatteredLightImage` and '
':class:`~pypeit.images.pypeitimage.PypeItImage`.'),
'scattlight_model': dict(otype=np.ndarray, atype=np.floating,
descr='Model of the scattered light in scattlight_raw'),
'scattlight_param': dict(otype=np.ndarray, atype=np.floating,
descr='Model parameters that define the scattered light model')}
"""Provides the class data model."""
# TODO: Allow tweaked edges to be arguments?
# TODO: May want nspat to be a required argument.
# The INIT must contain every datamodel item or risk fail on I/O when it is a nested container
def __init__(self, pypeline=None, detname=None, nspec=None, nspat=None, PYP_SPEC=None, binning=None, pad=0,
scattlight_raw=None, scattlight_model=None, scattlight_param=None):
# Instantiate the DataContainer
args, _, _, values = inspect.getargvalues(inspect.currentframe())
_d = dict([(k,values[k]) for k in args[1:]])
# The dictionary passed to DataContainer.__init__ does not
# contain self.
# TODO: Does it matter if the calling function passes the
# keyword arguments in a different order? No.
datamodel.DataContainer.__init__(self, d=_d)
[docs]
def _validate(self):
"""
Validate the slit traces.
"""
# Allow the object to be empty
if self.scattlight_param is None:
return
if self.PYP_SPEC is None:
self.PYP_SPEC = 'unknown'
[docs]
def get_model(self, image):
"""Generate a model of the scattered light, based on an input image. This routine
requires that the scattered light has already been predefined.
Parameters
----------
image : `numpy.ndarray`_
A 2D image that you want to determine the amount of scattered light
Returns
-------
model : `numpy.ndarray`_
A model of the expected scattered light in the input image. Shape is (nspec, nspat).
"""
msgs.info("Generating a scattered light image")
if self.scattlight_param is None:
msgs.warn("No scattered light parameters are available")
return np.zeros_like(image)
# Return the model of the scattered light
return scattlight.scattered_light_model_pad(self.scattlight_param, image)
[docs]
def show(self, image=None, slits=None, mask=False, wcs_match=True):
""" Display the master scattered light frame, the model, and data-model.
Parameters
----------
image : `numpy.ndarray`_, optional
A 2D image that you want to display (including a scattered light model). If None,
the master Scattered Light frame wil be displayed by default
slits : :class:`~pypeit.slittrace.SlitTraceSet`, optional
The current slit traces
mask : :obj:`bool`
If True, the slits will be masked to show only the scattered light regions
wcs_match : :obj:`bool`, optional
Use a reference image for the WCS and match all image in other channels to it.
"""
offslitmask = slits.slit_img(pad=0, flexure=None) == -1 if mask else 1
# Prepare the frames
_data = self.scattlight_raw if image is None else image
_model = self.scattlight_model if image is None else self.get_model(image)
_resid = (_data - _model)
# Fold in the mask
_data *= offslitmask
_model *= offslitmask
_resid *= offslitmask
modmax = np.max(_model)
image_list = zip([_data, _model, _resid],
['data', 'model', 'data-model'],
[(0.0, modmax), (0.0, modmax), (-modmax/2,modmax/2)])
# Display frames
display.show_scattered_light(image_list, slits=slits, wcs_match=wcs_match)