Coverage for tests/test_coaddTransmissionCurve.py: 20%

110 statements  

« prev     ^ index     » next       coverage.py v6.4.1, created at 2022-06-18 02:52 -0700

1# 

2# LSST Data Management System 

3# Copyright 2018 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 

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# 

22 

23import numpy as np 

24import unittest 

25 

26import lsst.utils.tests 

27from lsst.pex.exceptions import InvalidParameterError 

28from lsst.geom import Point2D, Extent2D, Point2I, Box2D, Box2I, SpherePoint, degrees 

29from lsst.afw.geom import makeSkyWcs, makeCdMatrix, Polygon 

30from lsst.afw.image import TransmissionCurve 

31from lsst.afw.table import ExposureTable, ExposureCatalog 

32from lsst.meas.algorithms import makeCoaddTransmissionCurve 

33from lsst.meas.algorithms.testUtils import makeRandomTransmissionCurve 

34 

35 

36class CoaddBoundedFieldTestCase(lsst.utils.tests.TestCase): 

37 

38 def setUp(self): 

39 # Test geometry: 

40 # 

41 # -100,99 99,99 

42 # +--------------------+ 

43 # |AAAAAAAAAACCCCCDDDDD| A == only in epoch A 

44 # |AAAAAAAAAACCCCCDDDDD| B == only in epoch B 

45 # |AAAAAAAAAACCCCCDDDDD| C == in both epoch A and epoch B 

46 # |AAAAAAAAAACCCCCDDDDD| D == in epoch A; in B's bbox but outside its ValidPolygon 

47 # |AAAAAAAAAACCCCCDDDDD| 

48 # | BBBBBBBBBB| All WCSs have the same CRVAL and CD. 

49 # | BBBBBBBBBB| 

50 # | BBBBBBBBBB| Coadd has CRPIX=(0, 0) 

51 # | BBBBBBBBBB| Epoch A has CRPIX=(0, -50) 

52 # | BBBBBBBBBB| Epoch B has CRPIX=(-50, 0) 

53 # +--------------------+ 

54 # -100,-100 99,-100 

55 # 

56 self.rng = np.random.RandomState(50) 

57 crval = SpherePoint(45.0, 45.0, degrees) 

58 cdMatrix = makeCdMatrix(scale=5E-5*degrees, flipX=True) 

59 self.wcsCoadd = makeSkyWcs(crpix=Point2D(0.0, 0.0), crval=crval, cdMatrix=cdMatrix) 

60 self.wcsA = makeSkyWcs(crpix=Point2D(0.0, -50.0), crval=crval, cdMatrix=cdMatrix) 

61 self.wcsB = makeSkyWcs(crpix=Point2D(-50.0, 0.0), crval=crval, cdMatrix=cdMatrix) 

62 self.bboxCoadd = Box2I(Point2I(-100, -100), Point2I(99, 99)) 

63 self.bboxA = Box2I(Point2I(-100, -50), Point2I(99, 49)) 

64 self.bboxB = Box2I(Point2I(-50, -100), Point2I(49, 99)) 

65 self.polygonA = None 

66 polygonD = Polygon(Box2D(Box2I(Point2I(0, 0), Point2I(49, 99)))) 

67 self.polygonB, = polygonD.symDifference(Polygon(Box2D(self.bboxB))) 

68 self.curveA = makeRandomTransmissionCurve(self.rng) 

69 self.curveB = makeRandomTransmissionCurve(self.rng) 

70 self.weightA = 0.6 

71 self.weightB = 0.2 

72 schema = ExposureTable.makeMinimalSchema() 

73 weightKey = schema.addField("weight", type=float, doc="relative weight of image in Coadd") 

74 catalog = ExposureCatalog(schema) 

75 recordA = catalog.addNew() 

76 recordA[weightKey] = self.weightA 

77 recordA.setWcs(self.wcsA) 

78 recordA.setValidPolygon(self.polygonA) 

79 recordA.setBBox(self.bboxA) 

80 recordA.setTransmissionCurve(self.curveA) 

81 recordB = catalog.addNew() 

82 recordB[weightKey] = self.weightB 

83 recordB.setWcs(self.wcsB) 

84 recordB.setValidPolygon(self.polygonB) 

85 recordB.setBBox(self.bboxB) 

86 recordB.setTransmissionCurve(self.curveB) 

87 self.curveCoadd = makeCoaddTransmissionCurve(self.wcsCoadd, catalog) 

88 

89 def tearDown(self): 

90 del self.wcsCoadd 

91 del self.wcsA 

92 del self.wcsB 

93 del self.curveCoadd 

94 

95 def makeRandomPoint(self, *args, **kwds): 

96 """Draw a random Point2D within a Box2I. 

97 

98 All arguments are forwarded directly to the Box2I constructor, allowing 

99 the caller to pass a fully-constructed Box2I, a (Point2I, Point2I) pair, 

100 or a (Point2I, Extent2I) pair. 

101 """ 

102 bboxD = Box2D(Box2I(*args, **kwds)) 

103 return bboxD.getMin() + Extent2D(bboxD.getWidth()*self.rng.rand(), 

104 bboxD.getHeight()*self.rng.rand()) 

105 

106 def testSampleAt(self): 

107 """Test the behavior of TransmissionCurve.sampleAt on the subclass 

108 returned by makeCoaddTransmissionCurve. 

109 """ 

110 wavelengths = np.linspace(4000, 7000, 200) 

111 

112 # Points in coadd coordinates in each of the distinct regions 

113 point0 = self.makeRandomPoint(Point2I(-100, -100), Point2I(-1, -1)) 

114 pointA = self.makeRandomPoint(Point2I(-100, 0), Point2I(-1, 99)) 

115 pointB = self.makeRandomPoint(Point2I(0, -100), Point2I(99, -1)) 

116 pointC = self.makeRandomPoint(Point2I(0, 0), Point2I(49, 99)) 

117 pointD = self.makeRandomPoint(Point2I(50, 0), Point2I(99, 99)) 

118 points = [point0, pointA, pointB, pointC, pointD] 

119 

120 # The same points, in sky coordinates 

121 coords = [self.wcsCoadd.pixelToSky(point) for point in points] 

122 

123 # The same points, in Epoch A's coordinates 

124 point0A, pointAA, pointBA, pointCA, pointDA = [self.wcsA.skyToPixel(coord) for coord in coords] 

125 self.assertFalse(Box2D(self.bboxA).contains(point0A)) 

126 self.assertTrue(Box2D(self.bboxA).contains(pointAA)) 

127 self.assertFalse(Box2D(self.bboxA).contains(pointBA)) 

128 self.assertTrue(Box2D(self.bboxA).contains(pointCA)) 

129 self.assertTrue(Box2D(self.bboxA).contains(pointDA)) 

130 

131 # The same points, in Epoch B's coordinates 

132 point0B, pointAB, pointBB, pointCB, pointDB = [self.wcsB.skyToPixel(coord) for coord in coords] 

133 self.assertFalse(Box2D(self.bboxB).contains(point0B)) 

134 self.assertFalse(Box2D(self.bboxB).contains(pointAB)) 

135 self.assertTrue(Box2D(self.bboxB).contains(pointBB)) 

136 self.assertTrue(Box2D(self.bboxB).contains(pointCB)) 

137 self.assertTrue(Box2D(self.bboxB).contains(pointDB)) 

138 self.assertTrue(self.polygonB.contains(pointBB)) 

139 self.assertTrue(self.polygonB.contains(pointCB)) 

140 self.assertFalse(self.polygonB.contains(pointDB)) 

141 

142 # Test that we can't compute throughputs in region 0 (where there are no inputs) 

143 self.assertRaises(InvalidParameterError, self.curveCoadd.sampleAt, point0, wavelengths) 

144 

145 # Test throughputs in region A (only Epoch A contributes) 

146 throughputA1 = self.curveCoadd.sampleAt(pointA, wavelengths) 

147 throughputA2 = self.curveA.sampleAt(pointAA, wavelengths) 

148 self.assertFloatsAlmostEqual(throughputA1, throughputA2) 

149 

150 # Test throughputs in region B (only Epoch B contributes) 

151 throughputB1 = self.curveCoadd.sampleAt(pointB, wavelengths) 

152 throughputB2 = self.curveB.sampleAt(pointBB, wavelengths) 

153 self.assertFloatsAlmostEqual(throughputB1, throughputB2) 

154 

155 # Test throughputs in region C (both epochs contribute) 

156 throughputC1 = self.curveCoadd.sampleAt(pointC, wavelengths) 

157 throughputC2 = self.curveA.sampleAt(pointCA, wavelengths) 

158 throughputC3 = self.curveB.sampleAt(pointCB, wavelengths) 

159 self.assertFloatsAlmostEqual(throughputC1, throughputC2*0.75 + throughputC3*0.25) 

160 

161 # Test throughputs in region D (only Epoch A contributes) 

162 throughputD1 = self.curveCoadd.sampleAt(pointD, wavelengths) 

163 throughputD2 = self.curveA.sampleAt(pointDA, wavelengths) 

164 self.assertFloatsAlmostEqual(throughputD1, throughputD2) 

165 

166 def testPersistence(self): 

167 wavelengths = np.linspace(4000, 7000, 200) 

168 with lsst.utils.tests.getTempFilePath(".fits") as filename: 

169 self.curveCoadd.writeFits(filename) 

170 roundtripped = TransmissionCurve.readFits(filename) 

171 for i in range(10): 

172 point = self.makeRandomPoint(self.bboxCoadd) 

173 try: 

174 throughput1 = self.curveCoadd.sampleAt(point, wavelengths) 

175 except InvalidParameterError: 

176 self.assertRaises(InvalidParameterError, roundtripped.sampleAt, point, wavelengths) 

177 else: 

178 throughput2 = roundtripped.sampleAt(point, wavelengths) 

179 self.assertFloatsAlmostEqual(throughput1, throughput2, atol=1e-10) 

180 

181 

182class TestMemory(lsst.utils.tests.MemoryTestCase): 

183 pass 

184 

185 

186def setup_module(module): 

187 lsst.utils.tests.init() 

188 

189 

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

191 lsst.utils.tests.init() 

192 unittest.main()