Coverage for python/lsst/obs/lsst/translators/comCam.py: 27%
56 statements
« prev ^ index » next coverage.py v7.2.5, created at 2023-05-23 04:18 -0700
« prev ^ index » next coverage.py v7.2.5, created at 2023-05-23 04:18 -0700
1# This file is currently part of obs_lsst but is written to allow it
2# to be migrated to the astro_metadata_translator package at a later date.
3#
4# This product includes software developed by the LSST Project
5# (http://www.lsst.org).
6# See the LICENSE file in this directory for details of code ownership.
7#
8# Use of this source code is governed by a 3-clause BSD-style
9# license that can be found in the LICENSE file.
11"""Metadata translation code for the LSST Commissioning Camera"""
13__all__ = ("LsstComCamTranslator", )
15import logging
16from numbers import Number
18from astropy.time import Time
19from .lsstCam import LsstCamTranslator
20from .lsst import SIMONYI_TELESCOPE
22log = logging.getLogger(__name__)
24DETECTOR_SERIALS = {
25 "S00": "ITL-3800C-229",
26 "S01": "ITL-3800C-251",
27 "S02": "ITL-3800C-215",
28 "S10": "ITL-3800C-326",
29 "S11": "ITL-3800C-283",
30 "S12": "ITL-3800C-243",
31 "S20": "ITL-3800C-319",
32 "S21": "ITL-3800C-209",
33 "S22": "ITL-3800C-206",
34}
36# Date ComCam left Tucson bound for Chile
37COMCAM_TO_CHILE_DATE = Time("2020-03-13T00:00", format="isot", scale="utc")
40class LsstComCamTranslator(LsstCamTranslator):
41 """Metadata translation for the LSST Commissioning Camera."""
43 name = "LSSTComCam"
44 """Name of this translation class"""
46 _const_map = {
47 "instrument": "LSSTComCam",
48 }
50 # Use the comCam raft definition
51 cameraPolicyFile = "policy/comCam.yaml"
53 @classmethod
54 def can_translate(cls, header, filename=None):
55 """Indicate whether this translation class can translate the
56 supplied header.
58 Looks for "COMCAM" instrument in case-insensitive manner but
59 must be on LSST telescope. This avoids confusion with other
60 telescopes using commissioning cameras.
62 Parameters
63 ----------
64 header : `dict`-like
65 Header to convert to standardized form.
66 filename : `str`, optional
67 Name of file being translated.
69 Returns
70 -------
71 can : `bool`
72 `True` if the header is recognized by this class. `False`
73 otherwise.
74 """
75 if "INSTRUME" in header and "TELESCOP" in header:
76 telescope = header["TELESCOP"]
77 instrument = header["INSTRUME"].lower()
78 if instrument == "comcam" and telescope in (SIMONYI_TELESCOPE, "LSST"):
79 return True
80 telcode = header.get("TELCODE", None)
81 # Some lab data reports that it is LSST_CAMERA
82 if telcode == "CC" and telescope in (SIMONYI_TELESCOPE, "LSST"):
83 return True
85 return False
87 @classmethod
88 def fix_header(cls, header, instrument, obsid, filename=None):
89 """Fix ComCam headers.
91 Notes
92 -----
93 Fixes the following issues:
95 * If ComCam was in Chile, the FILTER is always empty (or unknown).
96 * If LSST_NUM is missing it is filled in by looking at the CCDSLOT
97 value and assuming that the ComCam detectors are fixed.
98 * If ROTPA is missing or non-numeric, it is set to 0.0.
100 Corrections are reported as debug level log messages.
102 See `~astro_metadata_translator.fix_header` for details of the general
103 process.
104 """
105 modified = False
107 # Calculate the standard label to use for log messages
108 log_label = cls._construct_log_prefix(obsid, filename)
110 physical_filter = header.get("FILTER")
111 if physical_filter in (None, "r", ""):
112 # Create a translator since we need the date
113 translator = cls(header)
114 if physical_filter is None:
115 header["FILTER"] = "unknown"
116 physical_filter_str = "None"
117 else:
118 date = translator.to_datetime_begin()
119 if date > COMCAM_TO_CHILE_DATE:
120 header["FILTER"] = "empty"
121 else:
122 header["FILTER"] = "r_03" # it's currently 'r', which is a band not a physical_filter
124 physical_filter_str = f'"{physical_filter}"'
126 log.warning("%s: replaced FILTER %s with \"%s\"",
127 log_label, physical_filter_str, header["FILTER"])
128 modified = True
130 if "LSST_NUM" not in header:
131 slot = header.get("CCDSLOT", None)
132 if slot in DETECTOR_SERIALS:
133 header["LSST_NUM"] = DETECTOR_SERIALS[slot]
134 modified = True
135 log.debug("%s: Set LSST_NUM to %s", log_label, header["LSST_NUM"])
137 if "ROTPA" not in header or not isinstance(header["ROTPA"], Number):
138 header["ROTPA"] = 0.0
139 log.warning("Missing ROTPA in header - replacing with 0.0")
140 modified = True
142 return modified
144 def _is_on_mountain(self):
145 """Indicate whether these data are coming from the instrument
146 installed on the mountain.
147 Returns
148 -------
149 is : `bool`
150 `True` if instrument is on the mountain.
152 Notes
153 -----
154 TODO: DM-33387 This is currently a terrible hack and MUST be removed
155 once CAP-807 and CAP-808 are done.
156 Until then, ALL non-calib ComCam data will look like it is on sky.
157 """
158 return True