Coverage for tests/test_gen3.py: 34%

79 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2023-02-01 03:14 -0800

1# This file is part of obs_lsst. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (http://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 <http://www.gnu.org/licenses/>. 

21 

22import os 

23import unittest 

24import shutil 

25import tempfile 

26from cProfile import Profile 

27from pstats import Stats 

28 

29import numpy as np 

30 

31from astro_metadata_translator import ObservationInfo 

32from lsst.obs.lsst import (LsstCam, LsstComCam, LsstCamImSim, LsstCamPhoSim, 

33 LsstTS8, LsstTS3, LsstUCDCam, Latiss, readRawFitsHeader) 

34 

35from lsst.daf.butler import ( 

36 Butler, 

37 DatasetType, 

38 StorageClassFactory, 

39) 

40 

41TESTDIR = os.path.abspath(os.path.dirname(__file__)) 

42DATAROOT = os.path.join(TESTDIR, os.path.pardir, "data", "input") 

43 

44# This test is unfortunately slow; leave a profiling option in in case we want 

45# to improve it later. Initial version is about 60% YamlCamera construction 

46# (!) and 40% SQLite operations inside Butler. 

47PRINT_PROFILE = False 

48 

49 

50class TestInstruments(unittest.TestCase): 

51 

52 def setUp(self): 

53 self.root = tempfile.mkdtemp(dir=TESTDIR) 

54 self.rng = np.random.RandomState(50) # arbitrary deterministic seed 

55 

56 @classmethod 

57 def setUpClass(cls): 

58 if PRINT_PROFILE: 

59 cls.profile = Profile() 

60 cls.profile.enable() 

61 

62 def tearDown(self): 

63 if self.root is not None and os.path.exists(self.root): 

64 shutil.rmtree(self.root, ignore_errors=True) 

65 

66 @classmethod 

67 def tearDownClass(cls): 

68 if PRINT_PROFILE: 

69 stats = Stats(cls.profile) 

70 stats.strip_dirs() 

71 stats.sort_stats("cumtime") 

72 stats.print_stats() 

73 

74 def checkInstrumentWithRegistry(self, cls, testRaw): 

75 

76 Butler.makeRepo(self.root) 

77 butler = Butler(self.root, run="tests") 

78 instrument = cls() 

79 scFactory = StorageClassFactory() 

80 

81 # Check instrument class and metadata translator agree on 

82 # instrument name, using readRawFitsHeader to read the metadata. 

83 filename = os.path.join(DATAROOT, testRaw) 

84 md = readRawFitsHeader(filename, translator_class=cls.translatorClass) 

85 obsInfo = ObservationInfo(md, translator_class=cls.translatorClass, filename=filename) 

86 self.assertEqual(instrument.getName(), obsInfo.instrument) 

87 

88 # Add Instrument, Detector, and PhysicalFilter entries to the 

89 # Butler Registry. 

90 instrument.register(butler.registry) 

91 

92 # Define a DatasetType for the cameraGeom.Camera, which can be 

93 # accessed just by identifying its Instrument. 

94 # A real-world Camera DatasetType should be identified by a 

95 # validity range as well. 

96 cameraDatasetType = DatasetType("camera", dimensions=["instrument"], 

97 storageClass=scFactory.getStorageClass("Camera"), 

98 universe=butler.registry.dimensions) 

99 butler.registry.registerDatasetType(cameraDatasetType) 

100 

101 # Define a DatasetType for cameraGeom.Detectors, which can be 

102 # accessed by identifying its Instrument and (Butler) Detector. 

103 # A real-world Detector DatasetType probably doesn't need to exist, 

104 # as it would just duplicate information in the Camera, and 

105 # reading a full Camera just to get a single Detector should be 

106 # plenty efficient. 

107 detectorDatasetType = DatasetType("detector", dimensions=["instrument", "detector"], 

108 storageClass=scFactory.getStorageClass("Detector"), 

109 universe=butler.registry.dimensions) 

110 butler.registry.registerDatasetType(detectorDatasetType) 

111 

112 # Put and get the Camera. 

113 dataId = dict(instrument=instrument.instrument) 

114 butler.put(instrument.getCamera(), "camera", dataId=dataId) 

115 camera = butler.get("camera", dataId) 

116 # Full camera comparisons are *slow*; just compare names. 

117 self.assertEqual(instrument.getCamera().getName(), camera.getName()) 

118 

119 # Put and get a random subset of the Detectors. 

120 allDetectors = list(instrument.getCamera()) 

121 numDetectors = min(3, len(allDetectors)) 

122 someDetectors = [allDetectors[i] for i in self.rng.choice(len(allDetectors), 

123 size=numDetectors, replace=False)] 

124 for cameraGeomDetector in someDetectors: 

125 # Right now we only support integer detector IDs in data IDs; 

126 # support for detector names and groups (i.e. rafts) is 

127 # definitely planned but not yet implemented. 

128 dataId = dict(instrument=instrument.instrument, detector=cameraGeomDetector.getId()) 

129 butler.put(cameraGeomDetector, "detector", dataId=dataId) 

130 cameraGeomDetector2 = butler.get("detector", dataId=dataId) 

131 # Full detector comparisons are *slow*; just compare names and 

132 # serials. 

133 self.assertEqual(cameraGeomDetector.getName(), cameraGeomDetector2.getName()) 

134 self.assertEqual(cameraGeomDetector.getSerial(), cameraGeomDetector2.getSerial()) 

135 

136 def testLsstCam(self): 

137 testFpath = "lsstCam/raw/2019-03-22/3019032200002/3019032200002-R10-S22-det035.fits" 

138 self.checkInstrumentWithRegistry(LsstCam, testFpath) 

139 

140 def testComCam(self): 

141 testFpath = "comCam/raw/2019-05-30/3019053000001/3019053000001-R22-S00-det000.fits" 

142 self.checkInstrumentWithRegistry(LsstComCam, testFpath) 

143 

144 def testImSim(self): 

145 self.checkInstrumentWithRegistry(LsstCamImSim, 

146 "imsim/raw/204595/R11/00204595-R11-S20-det042.fits") 

147 

148 def testPhoSim(self): 

149 self.checkInstrumentWithRegistry(LsstCamPhoSim, 

150 "phosim/raw/204595/R11/00204595-R11-S20-det042.fits") 

151 

152 def testTs8(self): 

153 self.checkInstrumentWithRegistry(LsstTS8, 

154 "ts8/raw/6006D/201807241028453-RTM-010-S11-det067.fits") 

155 

156 def testTs3(self): 

157 self.checkInstrumentWithRegistry(LsstTS3, 

158 "ts3/raw/2016-07-22/201607220607067-R071-S00-det071.fits") 

159 

160 def testUcdCam(self): 

161 self.checkInstrumentWithRegistry(LsstUCDCam, 

162 "ucd/raw/2018-12-05/20181205233148-S00-det000.fits") 

163 

164 def testLatiss(self): 

165 self.checkInstrumentWithRegistry(Latiss, 

166 "latiss/raw/2018-09-20/3018092000065-det000.fits") 

167 

168 

169if __name__ == "__main__": 169 ↛ 170line 169 didn't jump to line 170, because the condition on line 169 was never true

170 unittest.main()