Coverage for tests/test_gen3.py: 37%

82 statements  

« prev     ^ index     » next       coverage.py v7.4.3, created at 2024-02-25 09:36 +0000

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, LsstComCamSim, 

34 readRawFitsHeader) 

35 

36from lsst.daf.butler import ( 

37 Butler, 

38 DatasetType, 

39 StorageClassFactory, 

40) 

41 

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

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

44 

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

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

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

48PRINT_PROFILE = False 

49 

50 

51class TestInstruments(unittest.TestCase): 

52 

53 def setUp(self): 

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

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

56 

57 @classmethod 

58 def setUpClass(cls): 

59 if PRINT_PROFILE: 

60 cls.profile = Profile() 

61 cls.profile.enable() 

62 

63 def tearDown(self): 

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

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

66 

67 @classmethod 

68 def tearDownClass(cls): 

69 if PRINT_PROFILE: 

70 stats = Stats(cls.profile) 

71 stats.strip_dirs() 

72 stats.sort_stats("cumtime") 

73 stats.print_stats() 

74 

75 def checkInstrumentWithRegistry(self, cls, testRaw): 

76 

77 Butler.makeRepo(self.root) 

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

79 instrument = cls() 

80 scFactory = StorageClassFactory() 

81 

82 # Check instrument class and metadata translator agree on 

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

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

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

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

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

88 

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

90 # Butler Registry. 

91 instrument.register(butler.registry) 

92 

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

94 # accessed just by identifying its Instrument. 

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

96 # validity range as well. 

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

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

99 universe=butler.dimensions) 

100 butler.registry.registerDatasetType(cameraDatasetType) 

101 

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

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

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

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

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

107 # plenty efficient. 

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

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

110 universe=butler.dimensions) 

111 butler.registry.registerDatasetType(detectorDatasetType) 

112 

113 # Put and get the Camera. 

114 dataId = dict(instrument=instrument.instrument) 

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

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

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

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

119 

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

121 allDetectors = list(instrument.getCamera()) 

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

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

124 size=numDetectors, replace=False)] 

125 for cameraGeomDetector in someDetectors: 

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

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

128 # definitely planned but not yet implemented. 

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

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

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

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

133 # serials. 

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

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

136 

137 def testLsstCam(self): 

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

139 self.checkInstrumentWithRegistry(LsstCam, testFpath) 

140 

141 def testComCam(self): 

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

143 self.checkInstrumentWithRegistry(LsstComCam, testFpath) 

144 

145 def testComCamSim(self): 

146 testFpath = "comCamSim/raw/2024-03-21/7024032100720/7024032100720-R22-S11-det004.fits.fz" 

147 self.checkInstrumentWithRegistry(LsstComCamSim, testFpath) 

148 

149 def testImSim(self): 

150 self.checkInstrumentWithRegistry(LsstCamImSim, 

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

152 

153 def testPhoSim(self): 

154 self.checkInstrumentWithRegistry(LsstCamPhoSim, 

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

156 

157 def testTs8(self): 

158 self.checkInstrumentWithRegistry(LsstTS8, 

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

160 

161 def testTs3(self): 

162 self.checkInstrumentWithRegistry(LsstTS3, 

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

164 

165 def testUcdCam(self): 

166 self.checkInstrumentWithRegistry(LsstUCDCam, 

167 "ucd/raw/2023-10-31/2023103100227-R21-S01-det010.fits") 

168 

169 def testLatiss(self): 

170 self.checkInstrumentWithRegistry(Latiss, 

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

172 

173 

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

175 unittest.main()