Coverage for python/lsst/obs/lsst/translators/ts3.py : 60%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
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 LSST BNL TestStand 3 headers"""
13__all__ = ("LsstTS3Translator", )
15import logging
16import re
17import os.path
19import astropy.units as u
20from astropy.time import Time
22from astro_metadata_translator import cache_translation
24from .lsst import LsstBaseTranslator
26log = logging.getLogger(__name__)
28# There is only a single sensor at a time so define a
29# fixed sensor name
30_DETECTOR_NAME = "S00"
33class LsstTS3Translator(LsstBaseTranslator):
34 """Metadata translator for LSST BNL Test Stand 3 data.
35 """
37 name = "LSST-TS3"
38 """Name of this translation class"""
40 _const_map = {
41 # TS3 is not attached to a telescope so many translations are null.
42 "telescope": "LSST",
43 "location": None,
44 "boresight_rotation_coord": None,
45 "boresight_rotation_angle": None,
46 "boresight_airmass": None,
47 "tracking_radec": None,
48 "altaz_begin": None,
49 "object": "UNKNOWN",
50 "relative_humidity": None,
51 "temperature": None,
52 "pressure": None,
53 "detector_name": _DETECTOR_NAME, # Single sensor
54 }
56 _trivial_map = {
57 "detector_serial": "LSST_NUM",
58 "physical_filter": "FILTER",
59 "exposure_time": ("EXPTIME", dict(unit=u.s)),
60 }
62 DETECTOR_NAME = _DETECTOR_NAME
63 """Fixed name of single sensor."""
65 DETECTOR_MAX = 999
66 """Maximum number of detectors to use when calculating the
67 detector_exposure_id."""
69 cameraPolicyFile = "policy/ts3.yaml"
71 @classmethod
72 def can_translate(cls, header, filename=None):
73 """Indicate whether this translation class can translate the
74 supplied header.
76 There is no usable ``INSTRUME`` header in TS3 data. Instead we use
77 the ``TSTAND`` header.
79 Parameters
80 ----------
81 header : `dict`-like
82 Header to convert to standardized form.
83 filename : `str`, optional
84 Name of file being translated.
86 Returns
87 -------
88 can : `bool`
89 `True` if the header is recognized by this class. `False`
90 otherwise.
91 """
92 return cls.can_translate_with_options(header, {"TSTAND": "BNL-TS3-2-Janeway"}, filename=filename)
94 @staticmethod
95 def compute_exposure_id(dateobs, seqnum=0, controller=None):
96 """Helper method to calculate the TS3 exposure_id.
98 Parameters
99 ----------
100 dateobs : `str`
101 Date of observation in FITS ISO format.
102 seqnum : `int`, unused
103 Sequence number. Ignored.
104 controller : `str`, unused
105 Controller type. Ignored.
107 Returns
108 -------
109 exposure_id : `int`
110 Exposure ID.
111 """
112 # There is worry that seconds are too coarse so use 10th of second
113 # and read the first 21 characters.
114 exposure_id = re.sub(r"\D", "", dateobs[:21])
115 return int(exposure_id)
117 @cache_translation
118 def to_instrument(self):
119 """Calculate the instrument name.
121 Returns
122 -------
123 instrume : `str`
124 Name of the test stand.
125 """
126 return "LSST-TS3"
128 @cache_translation
129 def to_datetime_begin(self):
130 # Docstring will be inherited. Property defined in properties.py
131 self._used_these_cards("MJD-OBS")
132 return Time(self._header["MJD-OBS"], scale="utc", format="mjd")
134 def to_exposure_id(self):
135 """Generate a unique exposure ID number
137 Note that SEQNUM is not unique for a given day in TS3 data
138 so instead we convert the ISO date of observation directly to an
139 integer.
141 Returns
142 -------
143 exposure_id : `int`
144 Unique exposure number.
145 """
146 iso = self._header["DATE-OBS"]
147 self._used_these_cards("DATE-OBS")
149 return self.compute_exposure_id(iso)
151 # For now assume that visit IDs and exposure IDs are identical
152 to_visit_id = to_exposure_id
154 @cache_translation
155 def to_science_program(self):
156 """Calculate the science program information.
158 There is no header recording this in TS3 data so instead return
159 the observing day in YYYY-MM-DD format.
161 Returns
162 -------
163 run : `str`
164 Observing day in YYYY-MM-DD format.
165 """
166 # Get a copy so that we can edit the default formatting
167 date = self.to_datetime_begin().copy()
168 date.format = "iso"
169 date.out_subfmt = "date" # YYYY-MM-DD format
170 return str(date)
172 @cache_translation
173 def to_observation_id(self):
174 # Docstring will be inherited. Property defined in properties.py
175 filename = self._header["FILENAME"]
176 self._used_these_cards("FILENAME")
177 return os.path.splitext(filename)[0]
179 @cache_translation
180 def to_detector_group(self):
181 # Docstring will be inherited. Property defined in properties.py
182 serial = self.to_detector_serial()
183 detector_info = self.compute_detector_info_from_serial(serial)
184 return detector_info[0]