Coverage for tests/test_fitsRawFormatter.py : 43%

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 part of obs_base.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <https://www.gnu.org/licenses/>.
22import unittest
24from astropy.coordinates import Angle
25import astropy.units as u
27import lsst.utils.tests
29from astro_metadata_translator import FitsTranslator, StubTranslator
30from astro_metadata_translator.translators.helpers import tracking_from_degree_headers
31from lsst.afw.cameraGeom.testUtils import CameraWrapper, DetectorWrapper
32import lsst.afw.geom
33import lsst.daf.base
34import lsst.daf.butler
35import lsst.geom
36from lsst.obs.base import FitsRawFormatterBase, MakeRawVisitInfoViaObsInfo, FilterDefinitionCollection
37from lsst.obs.base.utils import createInitialSkyWcs, InitialSkyWcsError
40class SimpleTestingTranslator(FitsTranslator, StubTranslator):
41 _const_map = {"boresight_rotation_angle": Angle(90*u.deg),
42 "boresight_rotation_coord": "sky",
43 "detector_exposure_id": 12345,
44 # The following are defined to prevent warnings about
45 # undefined translators
46 "dark_time": 0.0*u.s,
47 "exposure_time": 0.0*u.s,
48 "physical_filter": "u",
49 "detector_num": 0,
50 "detector_name": "0",
51 "detector_group": "",
52 "detector_unique_name": "0",
53 "detector_serial": "",
54 "observation_id": "--",
55 "science_program": "unknown",
56 "object": "unknown",
57 "exposure_id": 0,
58 "visit_id": 0,
59 "relative_humidity": 30.0,
60 "pressure": 0.0*u.MPa,
61 "temperature": 273*u.K,
62 "altaz_begin": None,
63 }
64 _trivial_map = {"boresight_airmass": "AIRMASS",
65 "observation_type": "OBSTYPE"}
67 def to_tracking_radec(self):
68 radecsys = ("RADESYS", )
69 radecpairs = (("RA", "DEC"),)
70 return tracking_from_degree_headers(self, radecsys, radecpairs, unit=(u.deg, u.deg))
73class MakeTestingRawVisitInfo(MakeRawVisitInfoViaObsInfo):
74 metadataTranslator = SimpleTestingTranslator
77class SimpleFitsRawFormatter(FitsRawFormatterBase):
78 filterDefinitions = FilterDefinitionCollection()
80 @property
81 def translatorClass(self):
82 return SimpleTestingTranslator
84 def getDetector(self, id):
85 """Use CameraWrapper to create a fake detector that can map from
86 PIXELS to FIELD_ANGLE.
88 Always return Detector #10, so all the tests are self-consistent.
89 """
90 return CameraWrapper().camera.get(10)
93class FitsRawFormatterTestCase(lsst.utils.tests.TestCase):
94 def setUp(self):
95 # reset the filters before we test anything
96 FilterDefinitionCollection.reset()
98 # The FITS WCS and VisitInfo coordinates in this header are
99 # intentionally different, to make comparisons between them more
100 # obvious.
101 self.boresight = lsst.geom.SpherePoint(10., 20., lsst.geom.degrees)
102 self.header = {
103 "TELESCOP": "TEST",
104 "INSTRUME": "UNKNOWN",
105 "AIRMASS": 1.2,
106 "RADESYS": "ICRS",
107 "OBSTYPE": "science",
108 "EQUINOX": 2000,
109 "OBSGEO-X": "-5464588.84421314",
110 "OBSGEO-Y": "-2493000.19137644",
111 "OBSGEO-Z": "2150653.35350771",
112 "RA": self.boresight.getLatitude().asDegrees(),
113 "DEC": self.boresight.getLongitude().asDegrees(),
114 "CTYPE1": "RA---SIN",
115 "CTYPE2": "DEC--SIN",
116 "CRPIX1": 5,
117 "CRPIX2": 6,
118 "CRVAL1": self.boresight.getLatitude().asDegrees() + 1,
119 "CRVAL2": self.boresight.getLongitude().asDegrees() + 1,
120 "CD1_1": 1e-5,
121 "CD1_2": 0,
122 "CD2_2": 1e-5,
123 "CD2_1": 0
124 }
125 # make a property list of the above, for use by the formatter.
126 self.metadata = lsst.daf.base.PropertyList()
127 self.metadata.update(self.header)
129 maker = MakeTestingRawVisitInfo()
130 self.visitInfo = maker(self.header)
132 self.metadataSkyWcs = lsst.afw.geom.makeSkyWcs(self.metadata, strip=False)
133 self.boresightSkyWcs = createInitialSkyWcs(self.visitInfo, CameraWrapper().camera.get(10))
135 # set these to `contextlib.nullcontext()` to print the log warnings
136 self.warnContext = self.assertLogs(level="WARNING")
137 self.logContext = lsst.log.UsePythonLogging()
139 # Make a data ID to pass to the formatter.
140 universe = lsst.daf.butler.DimensionUniverse()
141 dataId = lsst.daf.butler.DataCoordinate.standardize(instrument="Cam1", exposure=2, detector=10,
142 physical_filter="u", band="u", universe=universe)
144 # We have no file in these tests, so make an empty descriptor.
145 fileDescriptor = lsst.daf.butler.FileDescriptor(None, None)
146 self.formatter = SimpleFitsRawFormatter(fileDescriptor, dataId)
147 # Force the formatter's metadata to be what we've created above.
148 self.formatter._metadata = self.metadata
150 def test_makeWcs(self):
151 detector = self.formatter.getDetector(1)
152 wcs = self.formatter.makeWcs(self.visitInfo, detector)
153 self.assertNotEqual(wcs, self.metadataSkyWcs)
154 self.assertEqual(wcs, self.boresightSkyWcs)
156 def test_makeWcs_warn_if_metadata_is_bad(self):
157 """If the metadata is bad, log a warning and use the VisitInfo WCS.
158 """
159 detector = self.formatter.getDetector(1)
160 self.metadata.remove("CTYPE1")
161 with self.warnContext, self.logContext:
162 wcs = self.formatter.makeWcs(self.visitInfo, detector)
163 self.assertNotEqual(wcs, self.metadataSkyWcs)
164 self.assertEqual(wcs, self.boresightSkyWcs)
166 def test_makeWcs_warn_if_visitInfo_is_None(self):
167 """If VisitInfo is None, log a warning and use the metadata WCS.
168 """
169 detector = self.formatter.getDetector(1)
170 with self.warnContext, self.logContext:
171 wcs = self.formatter.makeWcs(None, detector)
172 self.assertEqual(wcs, self.metadataSkyWcs)
173 self.assertNotEqual(wcs, self.boresightSkyWcs)
175 def test_makeWcs_fail_if_visitInfo_is_None(self):
176 """If VisitInfo is None and metadata failed, raise an exception.
177 """
178 detector = self.formatter.getDetector(1)
179 self.metadata.remove("CTYPE1")
180 with self.warnContext, self.logContext, self.assertRaises(InitialSkyWcsError):
181 self.formatter.makeWcs(None, detector)
183 def test_makeWcs_fail_if_detector_is_bad(self):
184 """If Detector is broken, raise an exception.
185 """
186 # This detector doesn't know about FIELD_ANGLE, so can't be used to
187 # make a SkyWcs.
188 detector = DetectorWrapper().detector
189 with self.assertRaises(InitialSkyWcsError):
190 self.formatter.makeWcs(self.visitInfo, detector)
193class MemoryTester(lsst.utils.tests.MemoryTestCase):
194 pass
197def setup_module(module):
198 lsst.utils.tests.init()
201if __name__ == '__main__': 201 ↛ 202line 201 didn't jump to line 202, because the condition on line 201 was never true
202 lsst.utils.tests.init()
203 unittest.main()