Coverage for tests/test_makeRawVisitInfo.py : 13%

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 math
23import unittest
25import astropy.coordinates
26import astropy.units
28import lsst.utils.tests
29import lsst.pex.exceptions
30from lsst.daf.base import DateTime, PropertySet
31from lsst.obs.base import MakeRawVisitInfo
32from lsst.geom import degrees
35class SimpleMakeRawVisitInfo(MakeRawVisitInfo):
37 def getDateAvg(self, md, exposureTime):
38 """Return date at the middle of the exposure"""
39 dateObs = self.popIsoDate(md, "DATE-OBS")
40 return self.offsetDate(dateObs, 0.5*exposureTime)
43def getMetadata(keyValDict):
44 md = PropertySet()
45 for key, val in keyValDict.items():
46 md.set(key, val)
47 return md
50class VisitInfoTestCase(lsst.utils.tests.TestCase):
51 """Test lsst.afw.image.VisitInfo, a simple struct-like class"""
53 def setUp(self):
54 self.makeRawVisitInfo = SimpleMakeRawVisitInfo()
56 def testMakeRawVisitInfo(self):
57 """Test base class functor MakeRawVisitInfo
59 The base class only sets date and exposureTime fields,
60 reads DATE-OBS, TIMESYS and EXPTIME,
61 and deletes DATE-OBS and EXPTIME, but not TIMESYS.
62 """
63 exposureTime = 6.2 # arbitrary value in seconds
64 date = DateTime("2001-01-02T03:04:05.123456789", DateTime.TAI)
65 dateNsec = date.nsecs(DateTime.TAI)
66 startDate = DateTime(dateNsec - int(exposureTime*1e9/2), DateTime.TAI)
68 exposureId = 54321 # an arbitrary value
69 md = getMetadata({
70 "DATE-OBS": startDate.toString(DateTime.UTC),
71 "TIMESYS": "UTC",
72 "EXPTIME": exposureTime,
73 "EXTRA1": "an abitrary key and value",
74 "EXTRA2": 5,
75 })
76 length = len(md)
77 visitInfo = self.makeRawVisitInfo(md=md, exposureId=exposureId)
78 self.assertEqual(visitInfo.getExposureId(), exposureId)
79 self.assertEqual(md.nameCount(), length) # No stripping
80 self.assertEqual(visitInfo.getExposureTime(), exposureTime)
81 self.assertEqual(visitInfo.getDate(), date)
83 # Test stripping keywords
84 visitInfo = SimpleMakeRawVisitInfo(doStripHeader=True)(md=md, exposureId=exposureId)
85 self.assertEqual(md.nameCount(), 3) # TIMESYS and two EXTRAn keywords
87 # try TIMESYS=TAI
88 md = getMetadata({
89 "DATE-OBS": startDate.toString(DateTime.TAI),
90 "TIMESYS": "TAI",
91 "EXPTIME": exposureTime,
92 })
93 length = len(md)
94 visitInfo = self.makeRawVisitInfo(md=md, exposureId=exposureId)
95 self.assertEqual(md.nameCount(), length)
96 self.assertEqual(visitInfo.getExposureTime(), exposureTime)
97 self.assertEqual(visitInfo.getDate(), date)
99 # try omitting TIMESYS, which defaults to UTC
100 md = getMetadata({
101 "DATE-OBS": startDate.toString(DateTime.UTC),
102 "EXPTIME": exposureTime,
103 })
104 length = len(md)
105 visitInfo = self.makeRawVisitInfo(md=md, exposureId=exposureId)
106 self.assertEqual(md.nameCount(), length)
107 self.assertEqual(visitInfo.getExposureTime(), exposureTime)
108 self.assertEqual(visitInfo.getDate(), date)
110 # omit DATE-OBS; date should be default-constructed
111 md = getMetadata({
112 "EXPTIME": exposureTime,
113 })
114 length = len(md)
115 visitInfo = self.makeRawVisitInfo(md=md, exposureId=exposureId)
116 self.assertEqual(md.nameCount(), length)
117 self.assertEqual(visitInfo.getExposureTime(), exposureTime)
118 self.assertEqual(visitInfo.getDate(), DateTime())
120 # omit EXPTIME; date should be start date, not avg date, and exposureTime should be nan
121 md = getMetadata({
122 "DATE-OBS": startDate.toString(DateTime.UTC),
123 })
124 length = len(md)
125 visitInfo = self.makeRawVisitInfo(md=md, exposureId=exposureId)
126 self.assertEqual(md.nameCount(), length)
127 self.assertTrue(math.isnan(visitInfo.getExposureTime()))
128 self.assertEqual(visitInfo.getDate(), startDate)
130 def testPopItem(self):
131 md = getMetadata({
132 "TIMESYS": "UTC",
133 "OTHER": 5,
134 })
135 names = set(md.names())
137 timesys = self.makeRawVisitInfo.popItem(md, "TIMESYS")
138 self.assertEqual(timesys, "UTC")
139 self.assertEqual(set(md.names()), names)
141 defVal = self.makeRawVisitInfo.popItem(md, "BADKEY", default=7)
142 self.assertEqual(set(md.names()), names)
143 self.assertEqual(defVal, 7)
144 missingItem = self.makeRawVisitInfo.popItem(md, "BADKEY")
145 self.assertIsNone(missingItem)
147 # Repeat, with stripping
148 timesys = SimpleMakeRawVisitInfo(doStripHeader=True).popItem(md, "TIMESYS")
149 self.assertEqual(timesys, "UTC")
150 self.assertEqual(set(md.names()), set(["OTHER"]))
152 defVal = SimpleMakeRawVisitInfo(doStripHeader=True).popItem(md, "BADKEY", default=7)
153 self.assertEqual(set(md.names()), set(["OTHER"]))
154 self.assertEqual(defVal, 7)
155 missingItem = SimpleMakeRawVisitInfo(doStripHeader=True).popItem(md, "BADKEY")
156 self.assertIsNone(missingItem)
158 def testPopFloat(self):
159 dataDict = {
160 "FLOAT": 5.5,
161 "INT": 5,
162 "FLOATSTR": "6.1",
163 "INTSTR": "6",
164 "STR": "FOO",
165 }
166 length = len(dataDict)
168 for key, desValue in dataDict.items():
169 if key == "STR":
170 continue
171 md = getMetadata(dataDict)
172 value = self.makeRawVisitInfo.popFloat(md, key)
173 self.assertAlmostEqual(value, float(desValue))
174 self.assertEqual(len(md.names()), length)
176 badFloat = self.makeRawVisitInfo.popFloat(md, "STR")
177 self.assertTrue(math.isnan(badFloat))
179 missingValue = self.makeRawVisitInfo.popFloat(md, "BADKEY")
180 self.assertTrue(math.isnan(missingValue))
182 def testPopAngle(self):
183 dataDict = {
184 "DEG1": 270.5,
185 "DEG2": "45:30",
186 "DEG3": "-310:12:32",
187 "HR_1": -23.5,
188 "HR_2": "23:30",
189 "HR_3": "-13:15:16.7",
190 "STR": "FOO",
191 }
193 for key, desValue in dataDict.items():
194 if key == "STR":
195 continue
196 elif key.startswith("DEG"):
197 units = astropy.units.deg
198 else:
199 units = astropy.units.h
201 desAngleDeg = astropy.coordinates.Angle(desValue, unit=units).deg
202 md = getMetadata(dataDict)
203 angle = self.makeRawVisitInfo.popAngle(md, key, units=units)
204 self.assertAnglesAlmostEqual(angle, desAngleDeg*degrees)
206 badAngle = self.makeRawVisitInfo.popAngle(md, "STR")
207 self.assertTrue(math.isnan(badAngle.asDegrees()))
209 missingAngle = self.makeRawVisitInfo.popAngle(md, "BADKEY")
210 self.assertTrue(math.isnan(missingAngle.asDegrees()))
212 def testPopIsoDate(self):
213 for timesys in (None, "UTC", "TAI"):
214 dataDict = {
215 "DATE1": "2001-02-03T04:05:06.123456789",
216 "DATE2": "2001-02-03T04:05:06.123456789Z", # Z should be ignored
217 "DATE3": "1980-03-04T01:02:03.999999999",
218 "BADISODATE": "51234.354",
219 }
220 if timesys is not None:
221 dataDict["TIMESYS"] = timesys
222 length = len(dataDict)
224 for key, dateStr in dataDict.items():
225 if not key.startswith("DATE"):
226 continue
228 lsstSys = dict(
229 UTC=DateTime.UTC,
230 TAI=DateTime.TAI,
231 ).get(timesys, DateTime.UTC)
233 # lsstDateStr = dateStr with trailing Z if UTC, else no trailing Z,
234 # because lsst.daf.base.DateTime is very picky
235 lsstDateStr = dateStr
236 if lsstSys == DateTime.UTC:
237 if not lsstDateStr.endswith("Z"):
238 lsstDateStr = lsstDateStr + "Z"
239 elif dateStr.endswith("Z"):
240 lsstDateStr = lsstDateStr[0:-1]
241 desDate = DateTime(lsstDateStr, lsstSys)
243 md = getMetadata(dataDict)
244 date = self.makeRawVisitInfo.popIsoDate(md, key, timesys=timesys)
245 self.assertEqual(len(md.names()), length)
246 self.assertEqual(date, desDate)
248 badDate = self.makeRawVisitInfo.popIsoDate(md, "BADISODATE")
249 self.assertEqual(badDate, DateTime())
251 missingDate = self.makeRawVisitInfo.popIsoDate(md, "BADKEY")
252 self.assertEqual(missingDate, DateTime())
254 def testPopMjdDate(self):
255 for timesys in (None, "UTC", "TAI"):
257 dataDict = {
258 "DATE1": 51943.1705801,
259 "DATE2": 44302.0433218,
260 "BADMJDDATE": "2001-02-03T04:05:06.123456789",
261 }
262 if timesys is not None:
263 dataDict["TIMESYS"] = timesys
264 length = len(dataDict)
266 for key, mjdDate in dataDict.items():
267 if not key.startswith("DATE"):
268 continue
270 lsstSys = dict(
271 UTC=DateTime.UTC,
272 TAI=DateTime.TAI,
273 ).get(timesys, DateTime.UTC)
275 desDate = DateTime(mjdDate, DateTime.MJD, lsstSys)
277 md = getMetadata(dataDict)
278 date = self.makeRawVisitInfo.popMjdDate(md, key, timesys=timesys)
279 self.assertEqual(len(md.names()), length)
280 self.assertAlmostEqual(date.get(), desDate.get())
282 badDate = self.makeRawVisitInfo.popMjdDate(md, "BADMJDDATE")
283 self.assertEqual(badDate, DateTime())
285 missingDate = self.makeRawVisitInfo.popMjdDate(md, "BADKEY")
286 self.assertEqual(missingDate, DateTime())
288 def testEraFromLstAndLongitude(self):
289 LST = 90*degrees
290 Longitude = 50*degrees
291 era = self.makeRawVisitInfo.eraFromLstAndLongitude(LST, Longitude)
292 self.assertAnglesAlmostEqual(era, LST-Longitude)
294 def testEraFromLstAndLongitude_float_vs_Angle_fails(self):
295 val1 = 90*degrees
296 val2 = 50.0
297 with self.assertRaises(TypeError):
298 self.makeRawVisitInfo.eraFromLstAndLongitude(val1, val2)
299 with self.assertRaises(TypeError):
300 self.makeRawVisitInfo.eraFromLstAndLongitude(val2, val1)
302 def testAltitudeFromZenithDistance(self):
303 for zdDeg in (0, 35.6, 89.999, 90.0):
304 desAltDeg = 90-zdDeg
305 self.assertAnglesAlmostEqual(
306 desAltDeg*degrees,
307 self.makeRawVisitInfo.altitudeFromZenithDistance(zdDeg*degrees),
308 )
310 def testCentigradeFromKelvin(self):
311 for tempK, desTempC in ( # a few values from http://www.convertunits.com/from/kelvin/to/centigrade
312 (0, -273.15),
313 (301.5, 28.35),
314 ):
315 self.assertAlmostEqual(desTempC, self.makeRawVisitInfo.centigradeFromKelvin(tempK))
317 def testPascalFromMmHg(self):
318 for mmHg, desPascal in ( # a few values from http://www.convertunits.com/from/mm+Hg/to/pascal
319 (1, 133.32239),
320 (0.062, 8.26598818),
321 ):
322 self.assertAlmostEqual(desPascal, self.makeRawVisitInfo.pascalFromMmHg(mmHg), places=5)
325def setup_module(module):
326 lsst.utils.tests.init()
329class MemoryTester(lsst.utils.tests.MemoryTestCase):
330 pass
333if __name__ == "__main__": 333 ↛ 334line 333 didn't jump to line 334, because the condition on line 333 was never true
334 lsst.utils.tests.init()
335 unittest.main()