Coverage for python / lsst / obs / base / tests.py: 24%

39 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-01-09 01:26 -0800

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/>. 

21 

22""" 

23Test utilities for obs_base and concrete obs* packages. 

24""" 

25 

26__all__ = ( 

27 "ObsTests", 

28 "make_ramp_array", 

29 "make_ramp_exposure_trimmed", 

30 "make_ramp_exposure_untrimmed", 

31) 

32 

33import logging 

34 

35import numpy as np 

36 

37from lsst.afw.cameraGeom.utils import calcRawCcdBBox 

38from lsst.afw.image import Exposure 

39 

40from . import butler_tests, camera_tests 

41 

42 

43class ObsTests(butler_tests.ButlerGetTests, camera_tests.CameraTests): 

44 """Aggregator class for all of the obs_* test classes. 

45 

46 Inherit from this class, then lsst.utils.tests.TestCase, in that order. 

47 

48 Example subclass: 

49 

50 .. code-block:: python 

51 

52 class TestObs( 

53 lsst.obs.base.tests.ObsTests, lsst.utils.tests.TestCase 

54 ): 

55 def setUp(self): 

56 self.setUp_tests(...) 

57 self.setUp_butler_get(...) 

58 self.setUp_camera(...) 

59 

60 Notes 

61 ----- 

62 The intention is for each obs package to have a single test class that 

63 inherits from this collector class, thus "automatically" getting all new 

64 tests. If those tests require setup that isn't defined in a given obs 

65 package, that obs package will be broken until updated. This is 

66 intentional, as a way to prevent obs packages from falling behind out of 

67 neglect. 

68 """ 

69 

70 def setUp_tests(self, butler, dataIds): 

71 """Set up the necessary shared variables used by multiple tests. 

72 

73 Parameters 

74 ---------- 

75 butler: `lsst.daf.butler.Butler` 

76 A butler object, instantiated on the testdata repository for the 

77 obs package being tested. 

78 dataIds: `dict` 

79 dictionary of (exposure name): (dataId of that exposure in the 

80 testdata repository), with unittest.SkipTest as the value for any 

81 exposures you do not have/do not want to test. It must contain a 

82 valid 'raw' dataId, in addition to 'bias','flat','dark', which may 

83 be set to SkipTest. For example:: 

84 

85 self.dataIds = { 

86 "raw": {"visit": 1, "filter": "g"}, 

87 "bias": {"visit": 1}, 

88 "flat": {"visit": 1}, 

89 "dark": unittest.SkipTest, 

90 } 

91 """ 

92 self.butler = butler 

93 self.dataIds = dataIds 

94 self.log = logging.getLogger(__name__) 

95 

96 def tearDown(self): 

97 del self.butler 

98 super().tearDown() 

99 

100 

101def make_ramp_array(bbox, pedestal): 

102 """Make a 2-d ramp array. 

103 

104 Parameters 

105 ---------- 

106 bbox : `lsst.geom.Box2I` 

107 Bounding box for the array. 

108 pedestal : `int` 

109 Minimum value for the ramp. 

110 

111 Returns 

112 ------- 

113 ramp : `numpy.ndarray` 

114 A 2-d array with shape ``(bbox.getHeight(), bbox.getWidth())``. 

115 end : `int` 

116 One past the maximum value in the ramp (for use as the 

117 pedestal for another box). 

118 """ 

119 end = pedestal + bbox.getArea() 

120 return np.arange(pedestal, end).reshape(bbox.getHeight(), bbox.getWidth()), end 

121 

122 

123def make_ramp_exposure_untrimmed(detector, dtype=None): 

124 """Create an untrimmed, assembled exposure with different ramps for 

125 each sub-amplifier region. 

126 

127 Parameters 

128 ---------- 

129 detector : `lsst.afw.cameraGeom.Detector` 

130 Detector object that the new exposure should match. Must have all amp 

131 flips and offsets set to False/zero (i.e. represent an already- 

132 assembled image). 

133 dtype : `numpy.dtype`, optional 

134 Type of the new exposure. Defaults to ``int32``. 

135 

136 Returns 

137 ------- 

138 exposure : `lsst.afw.image.Exposure` 

139 New exposure with the given detector attached. 

140 """ 

141 if dtype is None: 

142 dtype = np.dtype(np.int32) 

143 ramp_exposure = Exposure(calcRawCcdBBox(detector), dtype=np.dtype(dtype)) 

144 ramp_exposure.setDetector(detector) 

145 pedestal = 0 

146 for amp in detector: 

147 for name in ("HorizontalOverscan", "VerticalOverscan", "Prescan", "Data"): 

148 bbox = getattr(amp, f"getRaw{name}BBox")() 

149 ramp, pedestal = make_ramp_array(bbox, pedestal) 

150 ramp_exposure.image[bbox].array[:, :] = ramp 

151 return ramp_exposure 

152 

153 

154def make_ramp_exposure_trimmed(detector, dtype=None): 

155 """Create a trimmed, assembled exposure with different ramps for 

156 each amplifier region. 

157 

158 Parameters 

159 ---------- 

160 detector : `lsst.afw.cameraGeom.Detector` 

161 Detector object that the new exposure should match. 

162 dtype : `numpy.dtype`, optional 

163 Type of the new exposure. Defaults to ``int32``. 

164 

165 Returns 

166 ------- 

167 exposure : `lsst.afw.image.Exposure` 

168 New exposure with the given detector attached. 

169 """ 

170 if dtype is None: 

171 dtype = np.dtype(np.int32) 

172 ramp_exposure = Exposure(detector.getBBox(), dtype=np.dtype(dtype)) 

173 ramp_exposure.setDetector(detector) 

174 pedestal = 0 

175 for amp in detector: 

176 ramp, pedestal = make_ramp_array(amp.getBBox(), pedestal) 

177 ramp_exposure.image[amp.getBBox()].array[:, :] = ramp 

178 return ramp_exposure