Coverage for tests/test_visitInfo.py: 10%
417 statements
« prev ^ index » next coverage.py v6.4.4, created at 2022-09-20 02:20 -0700
« prev ^ index » next coverage.py v6.4.4, created at 2022-09-20 02:20 -0700
1#
2# LSST Data Management System
3# Copyright 2016 LSST Corporation.
4#
5# This product includes software developed by the
6# LSST Project (http://www.lsst.org/).
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the LSST License Statement and
19# the GNU General Public License along with this program. If not,
20# see <http://www.lsstcorp.org/LegalNotices/>.
21#
22import math
23import os
24import unittest
25import collections
26import numpy as np
28import lsst.utils.tests
29import lsst.pex.exceptions
30from lsst.daf.base import DateTime, PropertySet, PropertyList
31from lsst.geom import Angle, degrees, SpherePoint
32from lsst.afw.coord import Observatory, Weather
33import lsst.afw.image as afwImage
35RotTypeEnumNameDict = {
36 afwImage.RotType.UNKNOWN: "UNKNOWN",
37 afwImage.RotType.SKY: "SKY",
38 afwImage.RotType.HORIZON: "HORIZON",
39 afwImage.RotType.MOUNT: "MOUNT",
40}
43def propertySetFromDict(keyValDict):
44 """Make an lsst.daf.base.PropertySet from a dict of key: value"""
45 metadata = PropertySet()
46 for key, val in keyValDict.items():
47 metadata.set(key, val)
48 return metadata
51def makeVisitInfo(data):
52 """Return a VisitInfo constructed from a VisitInfoData namedtuple."""
53 return afwImage.VisitInfo(data.exposureId,
54 data.exposureTime,
55 data.darkTime,
56 data.date,
57 data.ut1,
58 data.era,
59 data.boresightRaDec,
60 data.boresightAzAlt,
61 data.boresightAirmass,
62 data.boresightRotAngle,
63 data.rotType,
64 data.observatory,
65 data.weather,
66 data.instrumentLabel,
67 data.id,
68 data.focusZ,
69 data.observationType,
70 data.scienceProgram,
71 data.observationReason,
72 data.object,
73 data.hasSimulatedContent,
74 )
77class VisitInfoTestCase(lsst.utils.tests.TestCase):
78 """Test lsst.afw.image.VisitInfo, a simple struct-like class"""
80 def setUp(self):
81 self.testDir = os.path.dirname(__file__)
83 def computeLstHA(data):
84 """Return LST, Hour Angle, computed from VisitInfoData."""
85 localEra = data.era + data.observatory.getLongitude()
86 hourAngle = localEra - data.boresightRaDec[0]
87 return localEra, hourAngle
89 fields = ['exposureId',
90 'exposureTime',
91 'darkTime',
92 'date',
93 'ut1',
94 'era',
95 'boresightRaDec',
96 'boresightAzAlt',
97 'boresightAirmass',
98 'boresightRotAngle',
99 'rotType',
100 'observatory',
101 'weather',
102 'instrumentLabel',
103 'id',
104 'focusZ',
105 'observationType',
106 "scienceProgram",
107 "observationReason",
108 "object",
109 "hasSimulatedContent",
110 ]
111 VisitInfoData = collections.namedtuple("VisitInfoData", fields)
112 data1 = VisitInfoData(exposureId=10313423,
113 exposureTime=10.01,
114 darkTime=11.02,
115 date=DateTime(
116 65321.1, DateTime.MJD, DateTime.TAI),
117 ut1=12345.1,
118 era=45.1*degrees,
119 boresightRaDec=SpherePoint(
120 23.1*degrees, 73.2*degrees),
121 boresightAzAlt=SpherePoint(
122 134.5*degrees, 33.3*degrees),
123 boresightAirmass=1.73,
124 boresightRotAngle=73.2*degrees,
125 rotType=afwImage.RotType.SKY,
126 observatory=Observatory(
127 11.1*degrees, 22.2*degrees, 0.333),
128 weather=Weather(1.1, 2.2, 34.5),
129 instrumentLabel="TestCameraOne",
130 id=987654,
131 focusZ=1.5,
132 observationType="flat",
133 scienceProgram="test program",
134 observationReason="test reason",
135 object="test object",
136 hasSimulatedContent=False,
137 )
138 self.data1 = data1
139 self.localEra1, self.hourAngle1 = computeLstHA(data1)
140 data2 = VisitInfoData(exposureId=1,
141 exposureTime=15.5,
142 darkTime=17.8,
143 date=DateTime(
144 55321.2, DateTime.MJD, DateTime.TAI),
145 ut1=312345.1,
146 era=25.1*degrees,
147 boresightRaDec=SpherePoint(
148 2.1*degrees, 33.2*degrees),
149 boresightAzAlt=SpherePoint(13.5*degrees, 83.3*degrees),
150 boresightAirmass=2.05,
151 boresightRotAngle=-53.2*degrees,
152 rotType=afwImage.RotType.HORIZON,
153 observatory=Observatory(
154 22.2*degrees, 33.3*degrees, 0.444),
155 weather=Weather(2.2, 3.3, 44.4),
156 instrumentLabel="TestCameraTwo",
157 id=123456,
158 focusZ=-0.7,
159 observationType="science",
160 scienceProgram="test program 2",
161 observationReason="test reason 2",
162 object="test object 2",
163 hasSimulatedContent=True,
164 )
165 self.data2 = data2
166 self.localEra2, self.hourAngle2 = computeLstHA(data2)
168 def _testValueConstructor(self, data, localEra, hourAngle):
169 visitInfo = makeVisitInfo(data)
170 with self.assertWarns(FutureWarning):
171 self.assertEqual(visitInfo.getExposureId(), data.exposureId)
172 self.assertEqual(visitInfo.getExposureTime(), data.exposureTime)
173 self.assertEqual(visitInfo.getDarkTime(), data.darkTime)
174 self.assertEqual(visitInfo.getDate(), data.date)
175 self.assertEqual(visitInfo.getUt1(), data.ut1)
176 self.assertEqual(visitInfo.getEra(), data.era)
177 self.assertEqual(visitInfo.getBoresightRaDec(), data.boresightRaDec)
178 self.assertEqual(visitInfo.getBoresightAzAlt(), data.boresightAzAlt)
179 self.assertEqual(visitInfo.getBoresightAirmass(),
180 data.boresightAirmass)
181 self.assertEqual(visitInfo.getBoresightRotAngle(),
182 data.boresightRotAngle)
183 self.assertEqual(visitInfo.getRotType(), data.rotType)
184 self.assertEqual(visitInfo.getObservatory(), data.observatory)
185 self.assertEqual(visitInfo.getInstrumentLabel(), data.instrumentLabel)
186 self.assertEqual(visitInfo.getWeather(), data.weather)
187 self.assertEqual(visitInfo.getLocalEra(), localEra)
188 self.assertEqual(visitInfo.getBoresightHourAngle(), hourAngle)
189 self.assertEqual(visitInfo.getId(), data.id)
190 self.assertEqual(visitInfo.getFocusZ(), data.focusZ)
191 self.assertEqual(visitInfo.getObservationType(), data.observationType)
192 self.assertEqual(visitInfo.getScienceProgram(), data.scienceProgram)
193 self.assertEqual(visitInfo.getObservationReason(), data.observationReason)
194 self.assertEqual(visitInfo.getObject(), data.object)
195 self.assertEqual(visitInfo.getHasSimulatedContent(), data.hasSimulatedContent)
197 def _testProperties(self, data, localEra, hourAngle):
198 """Test property attribute accessors."""
199 visitInfo = makeVisitInfo(data)
200 self.assertEqual(visitInfo.exposureTime, data.exposureTime)
201 self.assertEqual(visitInfo.darkTime, data.darkTime)
202 self.assertEqual(visitInfo.date, data.date)
203 self.assertEqual(visitInfo.ut1, data.ut1)
204 self.assertEqual(visitInfo.era, data.era)
205 self.assertEqual(visitInfo.boresightRaDec, data.boresightRaDec)
206 self.assertEqual(visitInfo.boresightAzAlt, data.boresightAzAlt)
207 self.assertEqual(visitInfo.boresightAirmass, data.boresightAirmass)
208 self.assertEqual(visitInfo.boresightRotAngle, data.boresightRotAngle)
209 self.assertEqual(visitInfo.rotType, data.rotType)
210 self.assertEqual(visitInfo.observatory, data.observatory)
211 self.assertEqual(visitInfo.instrumentLabel, data.instrumentLabel)
212 self.assertEqual(visitInfo.weather, data.weather)
213 self.assertEqual(visitInfo.localEra, localEra)
214 self.assertEqual(visitInfo.boresightHourAngle, hourAngle)
215 self.assertEqual(visitInfo.id, data.id)
216 self.assertEqual(visitInfo.focusZ, data.focusZ)
217 self.assertEqual(visitInfo.observationType, data.observationType)
218 self.assertEqual(visitInfo.scienceProgram, data.scienceProgram)
219 self.assertEqual(visitInfo.observationReason, data.observationReason)
220 self.assertEqual(visitInfo.object, data.object)
221 self.assertEqual(visitInfo.hasSimulatedContent, data.hasSimulatedContent)
223 def testValueConstructor_data1(self):
224 self._testValueConstructor(self.data1, self.localEra1, self.hourAngle1)
225 self._testProperties(self.data1, self.localEra1, self.hourAngle1)
227 def testValueConstructor_data2(self):
228 self._testValueConstructor(self.data2, self.localEra2, self.hourAngle2)
229 self._testProperties(self.data2, self.localEra2, self.hourAngle2)
231 def testTablePersistence(self):
232 """Test that VisitInfo can be round-tripped with current code.
233 """
234 for item in (self.data1, self.data2):
235 tablePath = os.path.join(
236 self.testDir, "testVisitInfo_testTablePersistence.fits")
237 v1 = afwImage.VisitInfo(*item)
238 v1.writeFits(tablePath)
239 v2 = afwImage.VisitInfo.readFits(tablePath)
240 self.assertEqual(v1, v2)
241 os.unlink(tablePath)
243 def _testFitsRead(self, data, filePath, version):
244 """Test that old VersionInfo files are read correctly.
246 Parameters
247 ----------
248 data : `VisitInfoData`
249 The values expected to be stored in the file, or a
250 superset thereof.
251 filePath : `str`
252 The file to test.
253 version : `int`
254 The VersionInfo persistence format used in ``filePath``.
255 """
256 visitInfo = afwImage.VisitInfo.readFits(filePath)
258 if version >= 0:
259 with self.assertWarns(FutureWarning):
260 self.assertEqual(visitInfo.getExposureId(), data.exposureId)
261 self.assertEqual(visitInfo.getExposureTime(), data.exposureTime)
262 self.assertEqual(visitInfo.getDarkTime(), data.darkTime)
263 self.assertEqual(visitInfo.getDate(), data.date)
264 self.assertEqual(visitInfo.getUt1(), data.ut1)
265 self.assertEqual(visitInfo.getEra(), data.era)
266 self.assertEqual(visitInfo.getBoresightRaDec(), data.boresightRaDec)
267 self.assertEqual(visitInfo.getBoresightAzAlt(), data.boresightAzAlt)
268 self.assertEqual(visitInfo.getBoresightAirmass(),
269 data.boresightAirmass)
270 self.assertEqual(visitInfo.getBoresightRotAngle(),
271 data.boresightRotAngle)
272 self.assertEqual(visitInfo.getRotType(), data.rotType)
273 self.assertEqual(visitInfo.getObservatory(), data.observatory)
274 self.assertEqual(visitInfo.getWeather(), data.weather)
275 if version >= 1:
276 self.assertEqual(visitInfo.getInstrumentLabel(), data.instrumentLabel)
277 else:
278 self.assertEqual(visitInfo.getInstrumentLabel(), "")
279 if version >= 2:
280 self.assertEqual(visitInfo.getId(), data.id)
281 else:
282 self.assertEqual(visitInfo.getId(), 0)
283 if version >= 3:
284 self.assertEqual(visitInfo.getFocusZ(), data.focusZ)
285 else:
286 self.assertTrue(math.isnan(visitInfo.getFocusZ()))
287 if version >= 4:
288 self.assertEqual(visitInfo.getObservationType(), data.observationType)
289 self.assertEqual(visitInfo.getScienceProgram(), data.scienceProgram)
290 self.assertEqual(visitInfo.getObservationReason(), data.observationReason)
291 self.assertEqual(visitInfo.getObject(), data.object)
292 self.assertEqual(visitInfo.getHasSimulatedContent(), data.hasSimulatedContent)
293 else:
294 self.assertEqual(visitInfo.getObservationType(), "")
295 self.assertEqual(visitInfo.getScienceProgram(), "")
296 self.assertEqual(visitInfo.getObservationReason(), "")
297 self.assertEqual(visitInfo.getObject(), "")
298 self.assertEqual(visitInfo.getHasSimulatedContent(), False)
300 def testPersistenceVersions(self):
301 """Test that older versions are handled appropriately.
302 """
303 dataDir = os.path.join(os.path.dirname(__file__), "data")
305 # All files created by makeVisitInfo(self.data1).writeFits()
306 self._testFitsRead(self.data1, os.path.join(dataDir, "visitInfo-noversion.fits"), 0)
307 self._testFitsRead(self.data1, os.path.join(dataDir, "visitInfo-version-1.fits"), 1)
308 self._testFitsRead(self.data1, os.path.join(dataDir, "visitInfo-version-2.fits"), 2)
309 self._testFitsRead(self.data1, os.path.join(dataDir, "visitInfo-version-3.fits"), 3)
310 self._testFitsRead(self.data1, os.path.join(dataDir, "visitInfo-version-4.fits"), 4)
312 def testSetVisitInfoMetadata(self):
313 for item in (self.data1, self.data2):
314 visitInfo = makeVisitInfo(item)
315 metadata = PropertyList()
316 afwImage.setVisitInfoMetadata(metadata, visitInfo)
317 self.assertEqual(metadata.nameCount(), 28)
318 self.assertEqual(metadata.getScalar("EXPID"), item.exposureId)
319 self.assertEqual(metadata.getScalar("EXPTIME"), item.exposureTime)
320 self.assertEqual(metadata.getScalar("DARKTIME"), item.darkTime)
321 self.assertEqual(metadata.getScalar("DATE-AVG"),
322 item.date.toString(DateTime.TAI))
323 self.assertEqual(metadata.getScalar("TIMESYS"), "TAI")
324 self.assertEqual(metadata.getScalar("MJD-AVG-UT1"), item.ut1)
325 self.assertEqual(metadata.getScalar("AVG-ERA"), item.era.asDegrees())
326 self.assertEqual(metadata.getScalar("BORE-RA"),
327 item.boresightRaDec[0].asDegrees())
328 self.assertEqual(metadata.getScalar("BORE-DEC"),
329 item.boresightRaDec[1].asDegrees())
330 self.assertEqual(metadata.getScalar("BORE-AZ"),
331 item.boresightAzAlt[0].asDegrees())
332 self.assertEqual(metadata.getScalar("BORE-ALT"),
333 item.boresightAzAlt[1].asDegrees())
334 self.assertEqual(metadata.getScalar("BORE-AIRMASS"),
335 item.boresightAirmass)
336 self.assertEqual(metadata.getScalar("BORE-ROTANG"),
337 item.boresightRotAngle.asDegrees())
338 self.assertEqual(metadata.getScalar("ROTTYPE"),
339 RotTypeEnumNameDict[item.rotType])
340 self.assertEqual(metadata.getScalar("OBS-LONG"),
341 item.observatory.getLongitude().asDegrees())
342 self.assertEqual(metadata.getScalar("OBS-LAT"),
343 item.observatory.getLatitude().asDegrees())
344 self.assertEqual(metadata.getScalar("OBS-ELEV"),
345 item.observatory.getElevation())
346 self.assertEqual(metadata.getScalar("AIRTEMP"),
347 item.weather.getAirTemperature())
348 self.assertEqual(metadata.getScalar("AIRPRESS"),
349 item.weather.getAirPressure())
350 self.assertEqual(metadata.getScalar("HUMIDITY"),
351 item.weather.getHumidity())
352 self.assertEqual(metadata.getScalar("INSTRUMENT"),
353 item.instrumentLabel)
354 self.assertEqual(metadata.getScalar("IDNUM"),
355 item.id)
356 self.assertEqual(metadata.getScalar("FOCUSZ"),
357 item.focusZ)
358 self.assertEqual(metadata.getScalar("OBSTYPE"),
359 item.observationType)
360 self.assertEqual(metadata.getScalar("PROGRAM"),
361 item.scienceProgram)
362 self.assertEqual(metadata.getScalar("REASON"),
363 item.observationReason)
364 self.assertEqual(metadata.getScalar("OBJECT"),
365 item.object)
366 self.assertEqual(metadata.getScalar("HAS-SIMULATED-CONTENT"),
367 item.hasSimulatedContent)
369 def testSetVisitInfoMetadataMissingValues(self):
370 """If a value is unknown then it should not be written to the metadata"""
371 # Only rot type and hasSimulatedContent are "known" when default-
372 # constructed, by virtue of having no "null" state.
373 visitInfo = afwImage.VisitInfo()
374 metadata = PropertyList()
375 afwImage.setVisitInfoMetadata(metadata, visitInfo)
376 self.assertEqual(metadata.getScalar("ROTTYPE"),
377 RotTypeEnumNameDict[afwImage.RotType.UNKNOWN])
378 self.assertEqual(metadata.getScalar("HAS-SIMULATED-CONTENT"), False)
379 self.assertEqual(metadata.nameCount(), 2)
381 def testStripVisitInfoKeywords(self):
382 for argList in (self.data1, self.data2):
383 visitInfo = afwImage.VisitInfo(*argList)
384 metadata = PropertyList()
385 afwImage.setVisitInfoMetadata(metadata, visitInfo)
386 # add an extra keyword that will not be stripped
387 metadata.set("EXTRA", 5)
388 self.assertEqual(metadata.nameCount(), 29)
389 afwImage.stripVisitInfoKeywords(metadata)
390 self.assertEqual(metadata.nameCount(), 1)
392 def _testIsEmpty(self, visitInfo):
393 """Test that visitInfo is all NaN, 0, or empty string, as appropriate.
394 """
395 with self.assertWarns(FutureWarning):
396 self.assertEqual(visitInfo.getExposureId(), 0)
397 self.assertTrue(math.isnan(visitInfo.getExposureTime()))
398 self.assertTrue(math.isnan(visitInfo.getDarkTime()))
399 self.assertEqual(visitInfo.getDate(), DateTime())
400 self.assertTrue(math.isnan(visitInfo.getUt1()))
401 self.assertTrue(math.isnan(visitInfo.getEra().asDegrees()))
402 for i in range(2):
403 self.assertTrue(math.isnan(
404 visitInfo.getBoresightRaDec()[i].asDegrees()))
405 self.assertTrue(math.isnan(
406 visitInfo.getBoresightAzAlt()[i].asDegrees()))
407 self.assertTrue(math.isnan(visitInfo.getBoresightAirmass()))
408 self.assertTrue(math.isnan(
409 visitInfo.getBoresightRotAngle().asDegrees()))
410 self.assertEqual(visitInfo.getRotType(), afwImage.RotType.UNKNOWN)
411 self.assertTrue(math.isnan(
412 visitInfo.getObservatory().getLongitude().asDegrees()))
413 self.assertTrue(math.isnan(
414 visitInfo.getObservatory().getLatitude().asDegrees()))
415 self.assertTrue(math.isnan(visitInfo.getObservatory().getElevation()))
416 self.assertTrue(math.isnan(visitInfo.getWeather().getAirTemperature()))
417 self.assertTrue(math.isnan(visitInfo.getWeather().getAirPressure()))
418 self.assertTrue(math.isnan(visitInfo.getWeather().getHumidity()))
419 self.assertTrue(math.isnan(visitInfo.getBoresightHourAngle()))
420 self.assertEqual(visitInfo.getInstrumentLabel(), "")
421 self.assertEqual(visitInfo.getId(), 0)
422 self.assertTrue(math.isnan(visitInfo.getFocusZ()))
423 self.assertEqual(visitInfo.getObservationType(), "")
424 self.assertEqual(visitInfo.getScienceProgram(), "")
425 self.assertEqual(visitInfo.getObservationReason(), "")
426 self.assertEqual(visitInfo.getObject(), "")
427 self.assertEqual(visitInfo.getHasSimulatedContent(), False)
429 def testEquals(self):
430 """Test that identical VisitInfo objects compare equal, even if some fields are NaN.
431 """
432 # objects with "equal state" should be equal
433 self.assertEqual(makeVisitInfo(self.data1), makeVisitInfo(self.data1))
434 self.assertEqual(makeVisitInfo(self.data2), makeVisitInfo(self.data2))
435 self.assertNotEqual(makeVisitInfo(self.data1), makeVisitInfo(self.data2))
436 self.assertEqual(afwImage.VisitInfo(), afwImage.VisitInfo())
438 # equality must be reflexive
439 info = makeVisitInfo(self.data1)
440 self.assertEqual(info, info)
441 info = makeVisitInfo(self.data2)
442 self.assertEqual(info, info)
443 info = afwImage.VisitInfo()
444 self.assertEqual(info, info)
446 # commutativity and transitivity difficult to test with this setup
448 def testMetadataConstructor(self):
449 """Test the metadata constructor
451 This constructor allows missing values
452 """
453 data = self.data1
455 metadata = propertySetFromDict({})
456 visitInfo = afwImage.VisitInfo(metadata)
457 self._testIsEmpty(visitInfo)
459 metadata = propertySetFromDict({"EXPID": data.exposureId})
460 visitInfo = afwImage.VisitInfo(metadata)
461 with self.assertWarns(FutureWarning):
462 self.assertEqual(visitInfo.getExposureId(), data.exposureId)
463 self.assertTrue(math.isnan(visitInfo.getExposureTime()))
465 metadata = propertySetFromDict({"EXPTIME": data.exposureTime})
466 visitInfo = afwImage.VisitInfo(metadata)
467 self.assertEqual(visitInfo.getExposureTime(), data.exposureTime)
469 metadata = propertySetFromDict({"DARKTIME": data.darkTime})
470 visitInfo = afwImage.VisitInfo(metadata)
471 self.assertEqual(visitInfo.getDarkTime(), data.darkTime)
473 metadata = propertySetFromDict(
474 {"DATE-AVG": data.date.toString(DateTime.TAI), "TIMESYS": "TAI"})
475 visitInfo = afwImage.VisitInfo(metadata)
476 self.assertEqual(visitInfo.getDate(), data.date)
478 # TIME-MID in UTC is an acceptable alternative to DATE-AVG
479 metadata = propertySetFromDict(
480 {"TIME-MID": data.date.toString(DateTime.UTC)})
481 visitInfo = afwImage.VisitInfo(metadata)
482 self.assertEqual(visitInfo.getDate(), data.date)
484 # TIME-MID must be in UTC and TIMESYS is ignored
485 metadata = propertySetFromDict({
486 "TIME-MID": data.date.toString(DateTime.TAI) + "Z",
487 "TIMESYS": "TAI",
488 })
489 visitInfo = afwImage.VisitInfo(metadata)
490 self.assertNotEqual(visitInfo.getDate(), data.date)
492 # if both DATE-AVG and TIME-MID provided then use DATE-AVG
493 # use the wrong time system for TIME-MID so if it is used, an error
494 # will result
495 metadata = propertySetFromDict({
496 "DATE-AVG": data.date.toString(DateTime.TAI),
497 "TIMESYS": "TAI",
498 "TIME-MID": data.date.toString(DateTime.TAI) + "Z",
499 })
500 visitInfo = afwImage.VisitInfo(metadata)
501 self.assertEqual(visitInfo.getDate(), data.date)
503 metadata = propertySetFromDict({"MJD-AVG-UT1": data.ut1})
504 visitInfo = afwImage.VisitInfo(metadata)
505 self.assertEqual(visitInfo.getUt1(), data.ut1)
507 metadata = propertySetFromDict({"AVG-ERA": data.era.asDegrees()})
508 visitInfo = afwImage.VisitInfo(metadata)
509 self.assertEqual(visitInfo.getEra(), data.era)
511 for i, key in enumerate(("BORE-RA", "BORE-DEC")):
512 metadata = propertySetFromDict(
513 {key: data.boresightRaDec[i].asDegrees()})
514 visitInfo = afwImage.VisitInfo(metadata)
515 self.assertEqual(visitInfo.getBoresightRaDec()
516 [i], data.boresightRaDec[i])
518 for i, key in enumerate(("BORE-AZ", "BORE-ALT")):
519 metadata = propertySetFromDict(
520 {key: data.boresightAzAlt[i].asDegrees()})
521 visitInfo = afwImage.VisitInfo(metadata)
522 self.assertEqual(visitInfo.getBoresightAzAlt()
523 [i], data.boresightAzAlt[i])
525 metadata = propertySetFromDict({"BORE-AIRMASS": data.boresightAirmass})
526 visitInfo = afwImage.VisitInfo(metadata)
527 self.assertEqual(visitInfo.getBoresightAirmass(),
528 data.boresightAirmass)
530 metadata = propertySetFromDict(
531 {"BORE-ROTANG": data.boresightRotAngle.asDegrees()})
532 visitInfo = afwImage.VisitInfo(metadata)
533 self.assertEqual(visitInfo.getBoresightRotAngle(),
534 data.boresightRotAngle)
536 metadata = propertySetFromDict(
537 {"ROTTYPE": RotTypeEnumNameDict[data.rotType]})
538 visitInfo = afwImage.VisitInfo(metadata)
539 self.assertEqual(visitInfo.getRotType(), data.rotType)
541 metadata = propertySetFromDict(
542 {"OBS-LONG": data.observatory.getLongitude().asDegrees()})
543 visitInfo = afwImage.VisitInfo(metadata)
544 self.assertEqual(visitInfo.getObservatory().getLongitude(),
545 data.observatory.getLongitude())
547 metadata = propertySetFromDict(
548 {"OBS-LAT": data.observatory.getLatitude().asDegrees()})
549 visitInfo = afwImage.VisitInfo(metadata)
550 self.assertEqual(visitInfo.getObservatory().getLatitude(),
551 data.observatory.getLatitude())
553 metadata = propertySetFromDict(
554 {"OBS-ELEV": data.observatory.getElevation()})
555 visitInfo = afwImage.VisitInfo(metadata)
556 self.assertEqual(visitInfo.getObservatory().getElevation(),
557 data.observatory.getElevation())
559 metadata = propertySetFromDict(
560 {"AIRTEMP": data.weather.getAirTemperature()})
561 visitInfo = afwImage.VisitInfo(metadata)
562 self.assertEqual(visitInfo.getWeather().getAirTemperature(),
563 data.weather.getAirTemperature())
565 metadata = propertySetFromDict(
566 {"AIRPRESS": data.weather.getAirPressure()})
567 visitInfo = afwImage.VisitInfo(metadata)
568 self.assertEqual(visitInfo.getWeather().getAirPressure(),
569 data.weather.getAirPressure())
571 metadata = propertySetFromDict(
572 {"HUMIDITY": data.weather.getHumidity()})
573 visitInfo = afwImage.VisitInfo(metadata)
574 self.assertEqual(visitInfo.getWeather().getHumidity(),
575 data.weather.getHumidity())
577 metadata = propertySetFromDict({"INSTRUMENT": data.instrumentLabel})
578 visitInfo = afwImage.VisitInfo(metadata)
579 self.assertEqual(visitInfo.getInstrumentLabel(), data.instrumentLabel)
581 metadata = propertySetFromDict({"IDNUM": data.id})
582 visitInfo = afwImage.VisitInfo(metadata)
583 self.assertEqual(visitInfo.getId(), data.id)
585 metadata = propertySetFromDict({"FOCUSZ": data.focusZ})
586 visitInfo = afwImage.VisitInfo(metadata)
587 self.assertEqual(visitInfo.getFocusZ(), data.focusZ)
589 metadata = propertySetFromDict({"OBSTYPE": data.observationType})
590 visitInfo = afwImage.VisitInfo(metadata)
591 self.assertEqual(visitInfo.getObservationType(), data.observationType)
593 metadata = propertySetFromDict({"PROGRAM": data.scienceProgram})
594 visitInfo = afwImage.VisitInfo(metadata)
595 self.assertEqual(visitInfo.getScienceProgram(), data.scienceProgram)
597 metadata = propertySetFromDict({"REASON": data.observationReason})
598 visitInfo = afwImage.VisitInfo(metadata)
599 self.assertEqual(visitInfo.getObservationReason(), data.observationReason)
601 metadata = propertySetFromDict({"OBJECT": data.object})
602 visitInfo = afwImage.VisitInfo(metadata)
603 self.assertEqual(visitInfo.getObject(), data.object)
605 metadata = propertySetFromDict({"HAS-SIMULATED-CONTENT": data.hasSimulatedContent})
606 visitInfo = afwImage.VisitInfo(metadata)
607 self.assertEqual(visitInfo.getHasSimulatedContent(), data.hasSimulatedContent)
609 def testMetadataConstructorUndefined(self):
610 """Test that we can create VisitInfo using None in metadata."""
612 metadata = propertySetFromDict({
613 # These are examples of generic reader code.
614 "PROGRAM": None, # A string should convert to "".
615 "DARKTIME": None, # A missing float should convert to NaN.
616 # These headers have special logic in the reader.
617 "EXPTIME": None,
618 "IDNUM": None,
619 "DATE-AVG": None,
620 "ROTTYPE": None,
621 "HAS-SIMULATED-CONTENT": None,
622 })
623 visitInfo = afwImage.VisitInfo(metadata)
624 self.assertEqual(visitInfo.getScienceProgram(), "")
625 self.assertTrue(math.isnan(visitInfo.getDarkTime()))
626 self.assertTrue(math.isnan(visitInfo.getExposureTime()))
627 self.assertEqual(visitInfo.getId(), 0)
628 self.assertFalse(visitInfo.getDate().isValid())
630 def testConstructorKeywordArguments(self):
631 """Test VisitInfo with named arguments"""
632 data = self.data1
634 visitInfo = afwImage.VisitInfo()
635 self._testIsEmpty(visitInfo)
637 visitInfo = afwImage.VisitInfo(exposureId=data.exposureId)
638 with self.assertWarns(FutureWarning):
639 self.assertEqual(visitInfo.getExposureId(), data.exposureId)
640 self.assertTrue(math.isnan(visitInfo.getExposureTime()))
642 visitInfo = afwImage.VisitInfo(exposureTime=data.exposureTime)
643 self.assertEqual(visitInfo.getExposureTime(), data.exposureTime)
645 visitInfo = afwImage.VisitInfo(darkTime=data.darkTime)
646 self.assertEqual(visitInfo.getDarkTime(), data.darkTime)
648 visitInfo = afwImage.VisitInfo(date=data.date)
649 self.assertEqual(visitInfo.getDate(), data.date)
651 visitInfo = afwImage.VisitInfo(ut1=data.ut1)
652 self.assertEqual(visitInfo.getUt1(), data.ut1)
654 visitInfo = afwImage.VisitInfo(era=data.era)
655 self.assertEqual(visitInfo.getEra(), data.era)
657 visitInfo = afwImage.VisitInfo(boresightRaDec=data.boresightRaDec)
658 self.assertEqual(visitInfo.getBoresightRaDec(), data.boresightRaDec)
660 visitInfo = afwImage.VisitInfo(boresightAzAlt=data.boresightAzAlt)
661 self.assertEqual(visitInfo.getBoresightAzAlt(), data.boresightAzAlt)
663 visitInfo = afwImage.VisitInfo(boresightAirmass=data.boresightAirmass)
664 self.assertEqual(visitInfo.getBoresightAirmass(),
665 data.boresightAirmass)
667 visitInfo = afwImage.VisitInfo(
668 boresightRotAngle=data.boresightRotAngle)
669 self.assertEqual(visitInfo.getBoresightRotAngle(),
670 data.boresightRotAngle)
672 visitInfo = afwImage.VisitInfo(rotType=data.rotType)
673 self.assertEqual(visitInfo.getRotType(), data.rotType)
675 visitInfo = afwImage.VisitInfo(observatory=data.observatory)
676 self.assertEqual(visitInfo.getObservatory(), data.observatory)
678 visitInfo = afwImage.VisitInfo(weather=data.weather)
679 self.assertEqual(visitInfo.getWeather(), data.weather)
681 visitInfo = afwImage.VisitInfo(instrumentLabel=data.instrumentLabel)
682 self.assertEqual(visitInfo.getInstrumentLabel(), data.instrumentLabel)
684 visitInfo = afwImage.VisitInfo(id=data.id)
685 self.assertEqual(visitInfo.getId(), data.id)
687 visitInfo = afwImage.VisitInfo(focusZ=data.focusZ)
688 self.assertEqual(visitInfo.getFocusZ(), data.focusZ)
690 visitInfo = afwImage.VisitInfo(observationType=data.observationType)
691 self.assertEqual(visitInfo.getObservationType(), data.observationType)
693 visitInfo = afwImage.VisitInfo(scienceProgram=data.scienceProgram)
694 self.assertEqual(visitInfo.getScienceProgram(), data.scienceProgram)
696 visitInfo = afwImage.VisitInfo(observationReason=data.observationReason)
697 self.assertEqual(visitInfo.getObservationReason(), data.observationReason)
699 visitInfo = afwImage.VisitInfo(object=data.object)
700 self.assertEqual(visitInfo.getObject(), data.object)
702 visitInfo = afwImage.VisitInfo(hasSimulatedContent=data.hasSimulatedContent)
703 self.assertEqual(visitInfo.getHasSimulatedContent(), data.hasSimulatedContent)
705 def testGoodRotTypes(self):
706 """Test round trip of all valid rot types"""
707 for rotType in RotTypeEnumNameDict:
708 metadata = propertySetFromDict(
709 {"ROTTYPE": RotTypeEnumNameDict[rotType]})
710 visitInfo = afwImage.VisitInfo(metadata)
711 self.assertEqual(visitInfo.getRotType(), rotType)
713 def testBadRotTypes(self):
714 """Test that invalid rot type names cannot be used to construct a VisitInfo"""
715 for badRotTypeName in (
716 "unknown", # must be all uppercase
717 "sky", # must be all uppercase
718 "Sky", # must be all uppercase
719 "SKY1", # extra chars
720 "HORIZONTAL", # extra chars
721 ):
722 metadata = propertySetFromDict({"ROTTYPE": badRotTypeName})
723 with self.assertRaises(lsst.pex.exceptions.RuntimeError):
724 afwImage.VisitInfo(metadata)
726 def test_str(self):
727 """Check that we get something reasonable for str()"""
728 visitInfo = makeVisitInfo(self.data1)
729 string = str(visitInfo)
730 self.assertEqual(string,
731 "VisitInfo(exposureId=10313423, exposureTime=10.01, darkTime=11.02, "
732 "date=2037-09-20T02:24:00.000000000, UT1=12345.1, ERA=0.787143 rad, "
733 "boresightRaDec=(23.1000000000, +73.2000000000), "
734 "boresightAzAlt=(134.5000000000, +33.3000000000), boresightAirmass=1.73, "
735 "boresightRotAngle=1.27758 rad, rotType=1, observatory=22.2N, 11.1E 0.333, "
736 "weather=Weather(1.1, 2.2, 34.5), instrumentLabel='TestCameraOne', "
737 "id=987654, focusZ=1.5, observationType='flat', scienceProgram='test program', "
738 "observationReason='test reason', object='test object', hasSimulatedContent=false)")
740 def testParallacticAngle(self):
741 """Check that we get the same precomputed values for parallactic angle."""
742 parallacticAngle = [141.39684140703142*degrees, 76.99982166973487*degrees]
743 for item, parAngle in zip((self.data1, self.data2), parallacticAngle):
744 visitInfo = afwImage.VisitInfo(era=item.era,
745 boresightRaDec=item.boresightRaDec,
746 observatory=item.observatory,
747 )
748 self.assertAnglesAlmostEqual(visitInfo.getBoresightParAngle(), parAngle)
750 def testParallacticAngleNorthMeridian(self):
751 """An observation on the Meridian that is North of zenith has a parallactic angle of pi radians."""
752 meridianBoresightRA = self.data1.era + self.data1.observatory.getLongitude()
753 northBoresightDec = self.data1.observatory.getLatitude() + 10.*degrees
754 visitInfo = afwImage.VisitInfo(era=self.data1.era,
755 boresightRaDec=SpherePoint(meridianBoresightRA,
756 northBoresightDec),
757 observatory=self.data1.observatory,
758 )
759 self.assertAnglesAlmostEqual(visitInfo.getBoresightParAngle(), Angle(np.pi))
761 def testParallacticAngleSouthMeridian(self):
762 """An observation on the Meridian that is South of zenith has a parallactic angle of zero."""
763 meridianBoresightRA = self.data1.era + self.data1.observatory.getLongitude()
764 southBoresightDec = self.data1.observatory.getLatitude() - 10.*degrees
765 visitInfo = afwImage.VisitInfo(era=self.data1.era,
766 boresightRaDec=SpherePoint(meridianBoresightRA,
767 southBoresightDec),
768 observatory=self.data1.observatory,
769 )
770 self.assertAnglesAlmostEqual(visitInfo.getBoresightParAngle(), Angle(0.))
773def setup_module(module):
774 lsst.utils.tests.init()
777class MemoryTester(lsst.utils.tests.MemoryTestCase):
778 pass
781if __name__ == "__main__": 781 ↛ 782line 781 didn't jump to line 782, because the condition on line 781 was never true
782 lsst.utils.tests.init()
783 unittest.main()