Coverage for python/lsst/obs/lsst/translators/comCamSim.py: 31%
70 statements
« prev ^ index » next coverage.py v7.5.1, created at 2024-05-09 04:14 -0700
« prev ^ index » next coverage.py v7.5.1, created at 2024-05-09 04:14 -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 Simulated LSST Commissioning Camera"""
13__all__ = ("LsstComCamSimTranslator", )
15import logging
16import warnings
18import astropy
19import astropy.utils.exceptions
20from astropy.coordinates import AltAz
21from astro_metadata_translator import cache_translation
23from .lsstCam import LsstCamTranslator
24from .lsst import SIMONYI_TELESCOPE
26log = logging.getLogger(__name__)
29class LsstComCamSimTranslator(LsstCamTranslator):
30 """Metadata translation for the LSST Commissioning Camera."""
32 name = "LSSTComCamSim"
33 """Name of this translation class"""
35 _const_map = {
36 "instrument": "LSSTComCamSim",
37 }
39 cameraPolicyFile = 'policy/comCamSim.yaml'
41 @classmethod
42 def can_translate(cls, header, filename=None):
43 """Indicate whether this translation class can translate the
44 supplied header.
46 Looks for "COMCAMSIM" instrument in case-insensitive manner but
47 must be on LSST telescope. This avoids confusion with other
48 telescopes using commissioning cameras.
50 Parameters
51 ----------
52 header : `dict`-like
53 Header to convert to standardized form.
54 filename : `str`, optional
55 Name of file being translated.
57 Returns
58 -------
59 can : `bool`
60 `True` if the header is recognized by this class. `False`
61 otherwise.
62 """
63 if "INSTRUME" in header and "TELESCOP" in header:
64 telescope = header["TELESCOP"]
65 instrument = header["INSTRUME"].lower()
66 if instrument == "comcamsim" and telescope in (SIMONYI_TELESCOPE, "LSST"):
67 return True
69 return False
71 @classmethod
72 def fix_header(cls, header, instrument, obsid, filename=None):
73 """Fix Simulated ComCam headers.
75 Notes
76 -----
77 Content will be added as needed.
79 Corrections are reported as debug level log messages.
81 See `~astro_metadata_translator.fix_header` for details of the general
82 process.
83 """
84 modified = False
86 # Calculate the standard label to use for log messages
87 log_label = cls._construct_log_prefix(obsid, filename)
89 # Some simulated files lack RASTART/DECSTART etc headers. Since these
90 # are simulated they can be populated directly from the RA/DEC headers.
91 synced_radec = False
92 for key in ("RA", "DEC"):
93 for time in ("START", "END"):
94 time_key = f"{key}{time}"
95 if not header.get(time_key):
96 if (value := header.get(key)):
97 header[time_key] = value
98 synced_radec = True
99 if synced_radec:
100 modified = True
101 log.debug("%s: Synced RASTART/RAEND/DECSTART/DECEND headers with RA/DEC headers", log_label)
103 if not header.get("RADESYS") and header.get("RA") and header.get("DEC"):
104 header["RADESYS"] = "ICRS"
105 log.debug("%s: Forcing undefined RADESYS to '%s'", log_label, header["RADESYS"])
106 modified = True
108 if not header.get("TELCODE"):
109 if camcode := header.get("CAMCODE"):
110 header["TELCODE"] = camcode
111 modified = True
112 log.debug("%s: Setting TELCODE header from CAMCODE header", log_label)
113 else:
114 # Get the code from the OBSID.
115 code, _ = obsid.split("_", 1)
116 header["TELCODE"] = code
117 modified = True
118 log.debug("%s: Determining telescope code of %s from OBSID", log_label, code)
120 return modified
122 def _is_on_mountain(self):
123 """Indicate whether these data are coming from the instrument
124 installed on the mountain.
125 Returns
126 -------
127 is : `bool`
128 `True` if instrument is on the mountain.
130 Notes
131 -----
132 TODO: DM-33387 This is currently a terrible hack and MUST be removed
133 once CAP-807 and CAP-808 are done.
134 Until then, ALL non-calib ComCam data will look like it is on sky.
135 """
136 return True
138 @cache_translation
139 def to_altaz_begin(self):
140 # Tries to calculate the value. Simulated files for ops-rehearsal 3
141 # did not have the AZ/EL headers defined.
142 if self.are_keys_ok(["ELSTART", "AZSTART"]):
143 return super().to_altaz_begin()
145 # Calculate it from the RA/Dec and time.
146 # The time is not consistent with the HASTART/AMSTART values.
147 # This means that the elevation may well come out negative.
148 if self.are_keys_ok(["RA", "DEC"]):
149 # Derive from RADec in absence of any other information
150 radec = self.to_tracking_radec()
151 if radec is not None:
152 # This can trigger warnings because of the future dates
153 with warnings.catch_warnings():
154 warnings.simplefilter("ignore", category=astropy.utils.exceptions.AstropyWarning)
155 altaz = radec.transform_to(AltAz())
156 return altaz
158 return None
160 @classmethod
161 def observing_date_to_offset(cls, observing_date: astropy.time.Time) -> astropy.time.TimeDelta | None:
162 # Always use the 12 hour offset.
163 return cls._ROLLOVER_TIME