Coverage for python/lsst/obs/lsst/translators/comCam.py: 29%
60 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-06 05:23 -0700
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-06 05:23 -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 from 2019 reports that it is LSST_CAMERA.
82 if telcode == "CC" and instrument == "lsst_camera":
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 header.get("INSTRUME") == "LSST_CAMERA":
131 header["INSTRUME"] = "ComCam" # Must match the can_translate check above
132 modified = True
133 log.debug("%s: Correct instrument header for ComCam", log_label)
135 if "LSST_NUM" not in header:
136 slot = header.get("CCDSLOT", None)
137 if slot in DETECTOR_SERIALS:
138 header["LSST_NUM"] = DETECTOR_SERIALS[slot]
139 modified = True
140 log.debug("%s: Set LSST_NUM to %s", log_label, header["LSST_NUM"])
142 if "ROTPA" not in header or not isinstance(header["ROTPA"], Number):
143 header["ROTPA"] = 0.0
144 log.warning("Missing ROTPA in header - replacing with 0.0")
145 modified = True
147 return modified
149 def _is_on_mountain(self):
150 """Indicate whether these data are coming from the instrument
151 installed on the mountain.
152 Returns
153 -------
154 is : `bool`
155 `True` if instrument is on the mountain.
157 Notes
158 -----
159 TODO: DM-33387 This is currently a terrible hack and MUST be removed
160 once CAP-807 and CAP-808 are done.
161 Until then, ALL non-calib ComCam data will look like it is on sky.
162 """
163 return True