Source code for scopesim.detector.detector_array
# -*- coding: utf-8 -*-
"""Contains DetectorArray and aux functions."""
from astropy.io import fits
from .detector import Detector
from ..utils import stringify_dict, get_logger
logger = get_logger(__name__)
[docs]class DetectorArray:
"""Manages the individual Detectors, mostly used for readout."""
# TODO: Should this class be called DetectorManager analogous to the
# FOVManager and OpticsManager classes?
# TODO: Either way this could inherit from some collections.abc
def __init__(self, detector_list=None, cmds=None, **kwargs):
self.meta = {}
self.meta.update(kwargs)
self.cmds = cmds
# The effect from which the instance is constructed
self._detector_list = detector_list
self.array_effects = []
self.dtcr_effects = []
self.detectors = []
# The (initially empty) HDUList produced by the readout
self.latest_exposure = None
[docs] def readout(self, image_planes, array_effects=None, dtcr_effects=None,
**kwargs) -> fits.HDUList:
"""
Read out the detector array into a FITS HDU List.
1. Select the relevant image plane to extract images from.
2. Apply detector array effects (apply to the entire image plane)
3. Make a series of Detectors for each row in a DetectorList object.
4. Iterate through all Detectors, extract image from image_plane.
5. Apply all effects (to all Detectors).
6. Add necessary header keywords (not implemented).
7. Generate a HDUList with the ImageHDUs and any extras:
- add ``PrimaryHDU`` with meta data regarding observation in header
- add ``ImageHDU`` objects
- add ``ASCIITableHDU`` with Effects meta data in final table
extension (not implemented)
Parameters
----------
image_planes : list of ImagePlane objects
The correct image plane is automatically chosen from the list
array_effects : list of Effect objects
A list of effects related to the detector array
dtcr_effects : list of Effect objects
A list of effects related to the detectors
Returns
-------
latest_exposure : fits.HDUList
Output FITS HDU List.
"""
# .. note:: Detector is what used to be called Chip
# DetectorArray is the old Detector
self.array_effects = array_effects or []
self.dtcr_effects = dtcr_effects or []
self.meta.update(kwargs)
# 1. Get the image plane that corresponds to this detector array
# TODO: This silently only returns the first match, is that intended??
image_plane = next(implane for implane in image_planes if
implane.id == self._detector_list.image_plane_id)
# 2. Apply detector array effects (apply to the entire image plane)
for effect in self.array_effects:
image_plane = effect.apply_to(image_plane, **self.meta)
# 3. make a series of Detectors for each row in a DetectorList object
self.detectors = [Detector(hdr, cmds=self.cmds, **self.meta)
for hdr in self._detector_list.detector_headers()]
# 4. iterate through all Detectors, extract image from image_plane
logger.info("Extracting from %d detectors...", len(self.detectors))
for detector in self.detectors:
detector.extract_from(image_plane)
# 5. apply all effects (to all Detectors)
for effect in self.dtcr_effects:
detector = effect.apply_to(detector)
# 6. add necessary header keywords
# .. todo: add keywords
# 7. Generate a HDUList with the ImageHDUs and any extras:
pri_hdu = make_primary_hdu(self.meta)
# ..todo: effects_hdu unnecessary as long as make_effects_hdu does not do anything
# effects_hdu = make_effects_hdu(self.array_effects + self.dtcr_effects)
hdu_list = fits.HDUList([pri_hdu]
+ [dtcr.hdu for dtcr in self.detectors])
# + [effects_hdu])
for effect in self.array_effects:
image_plane = effect.apply_to(image_plane, **self.meta)
self.latest_exposure = hdu_list
return self.latest_exposure
def __repr__(self):
msg = (f"{self.__class__.__name__}"
f"({self._detector_list!r}, **{self.meta!r})")
return msg
def __str__(self):
return f"{self.__class__.__name__} with {self._detector_list!s}"
def _repr_pretty_(self, p, cycle):
"""For ipython."""
if cycle:
p.text(f"{self.__class__.__name__}(...)")
else:
p.text(str(self))
[docs]def make_primary_hdu(meta):
"""Create the primary header from meta data."""
prihdu = fits.PrimaryHDU()
prihdu.header.update(stringify_dict(meta))
return prihdu
[docs]def make_effects_hdu(effects):
# .. todo:: decide what goes into the effects table of meta data
return fits.TableHDU()