Coverage for python/lsst/obs/lsst/translators/lsstCam.py: 41%
43 statements
« prev ^ index » next coverage.py v7.2.6, created at 2023-05-24 09:52 +0000
« prev ^ index » next coverage.py v7.2.6, created at 2023-05-24 09:52 +0000
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 main LSST Camera"""
13__all__ = ("LsstCamTranslator", )
15import logging
16import astropy.units as u
18from astro_metadata_translator.translators.helpers import is_non_science
20from .lsst import LsstBaseTranslator, SIMONYI_TELESCOPE
22log = logging.getLogger(__name__)
24# Normalized name of the LSST Camera
25LSST_CAM = "LSSTCam"
28def is_non_science_or_lab(self):
29 """Pseudo method to determine whether this is a lab or non-science
30 header.
32 Raises
33 ------
34 KeyError
35 If this is a science observation and on the mountain.
36 """
37 # Return without raising if this is not a science observation
38 # since the defaults are fine.
39 try:
40 # This will raise if it is a science observation.
41 is_non_science(self)
42 return
43 except KeyError:
44 pass
46 # We are still in the lab, return and use the default.
47 if not self._is_on_mountain():
48 return
50 # This is a science observation on the mountain so we should not
51 # use defaults.
52 raise KeyError(f"{self._log_prefix}: Required key is missing and this is a mountain science observation")
55class LsstCamTranslator(LsstBaseTranslator):
56 """Metadata translation for the main LSST Camera."""
58 name = LSST_CAM
59 """Name of this translation class"""
61 supported_instrument = LSST_CAM
62 """Supports the lsstCam instrument."""
64 _const_map = {
65 "instrument": LSST_CAM,
66 "telescope": SIMONYI_TELESCOPE,
67 # Migrate these to full translations once test data appears that
68 # includes them
69 "altaz_begin": None,
70 "object": "UNKNOWN",
71 "relative_humidity": None,
72 "temperature": None,
73 "pressure": None,
74 }
76 _trivial_map = {
77 "detector_group": "RAFTBAY",
78 "detector_name": "CCDSLOT",
79 "observation_id": "OBSID",
80 "exposure_time": ("EXPTIME", dict(unit=u.s)),
81 "detector_serial": "LSST_NUM",
82 "science_program": (["PROGRAM", "RUNNUM"], dict(default="unknown")),
83 "boresight_rotation_angle": (["ROTPA", "ROTANGLE"], dict(checker=is_non_science_or_lab,
84 default=0.0, unit=u.deg)),
85 }
87 # Use Imsim raft definitions until a true lsstCam definition exists
88 cameraPolicyFile = "policy/lsstCam.yaml"
90 @classmethod
91 def fix_header(cls, header, instrument, obsid, filename=None):
92 """Fix LSSTCam headers.
94 Notes
95 -----
96 See `~astro_metadata_translator.fix_header` for details of the general
97 process.
98 """
100 modified = False
102 # Calculate the standard label to use for log messages
103 log_label = cls._construct_log_prefix(obsid, filename)
105 if "FILTER" not in header and header.get("FILTER2") is not None:
106 ccdslot = header.get("CCDSLOT", "unknown")
107 raftbay = header.get("RAFTBAY", "unknown")
109 log.warning("%s %s_%s: No FILTER key found but FILTER2=\"%s\" (removed)",
110 log_label, raftbay, ccdslot, header["FILTER2"])
111 header["FILTER2"] = None
112 modified = True
114 return modified
116 @classmethod
117 def can_translate(cls, header, filename=None):
118 """Indicate whether this translation class can translate the
119 supplied header.
121 Parameters
122 ----------
123 header : `dict`-like
124 Header to convert to standardized form.
125 filename : `str`, optional
126 Name of file being translated.
128 Returns
129 -------
130 can : `bool`
131 `True` if the header is recognized by this class. `False`
132 otherwise.
133 """
134 # INSTRUME keyword might be of two types
135 if "INSTRUME" in header:
136 instrume = header["INSTRUME"].lower()
137 if instrume == cls.supported_instrument.lower():
138 return True
139 return False