Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

# 

# LSST Data Management System 

# Copyright 2008-2016 LSST Corporation. 

# 

# This product includes software developed by the 

# LSST Project (http://www.lsst.org/). 

# 

# This program is free software: you can redistribute it and/or modify 

# it under the terms of the GNU General Public License as published by 

# the Free Software Foundation, either version 3 of the License, or 

# (at your option) any later version. 

# 

# This program is distributed in the hope that it will be useful, 

# but WITHOUT ANY WARRANTY; without even the implied warranty of 

# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

# GNU General Public License for more details. 

# 

# You should have received a copy of the LSST License Statement and 

# the GNU General Public License along with this program. If not, 

# see <http://www.lsstcorp.org/LegalNotices/>. 

# 

""" 

Tests for lsst.afw.table.CoaddInputs 

 

Note: generating the version 1 data requires some complicated machinations 

because CoaddInputRecorderTask had bugs: 

- Setup pipe_tasks 12.1, or a similar version old enough to have version 1 CoaddInput/ExposureTable 

- Edit this file as follows: 

- Set SaveCoadd = True 

- Set self.version to 2 in CoaddInputsTestCase 

- Edit CoaddInputRecorderTask as follows: 

- Apply all fixes to CoaddInputRecorderTask from DM-7976 

- Comment out the line that saves VisitInfo (since version 1 doesn't have it) 

- Edit ups/pipe_tasks.table as follows: 

- Do not import obs_base (since it did not exist at that time) 

- "setup -r . 'j" to setup this version of pipe_tasks 

- "python tests/testCoaddInputs.py" to run this test. 

You will see some errors, but the needed data file will be written: 

tests/data/testCoaddInputs_coadd_with_version_1_data.fits 

- Save the data file to the repository (but do not save any other changes). 

""" 

import os.path 

import unittest 

 

import numpy as np 

 

import lsst.utils.tests 

import lsst.pex.exceptions 

from lsst.daf.base import DateTime 

import lsst.afw.cameraGeom.testUtils 

from lsst.afw.coord import Observatory, Weather 

import lsst.afw.geom 

import lsst.afw.image 

from lsst.afw.detection import GaussianPsf 

from lsst.afw.math import ChebyshevBoundedField 

from lsst.pipe.tasks.coaddInputRecorder import CoaddInputRecorderTask 

 

SaveCoadd = False # if True then save coadd even if test passes (always saved if a test fails) 

 

 

class MockExposure: 

 

"""Factory to make simple mock exposures suitable to put in a coadd 

 

The metadata is set, but not the pixels 

""" 

 

def __init__(self, numExp, coaddInputRecorder, version=2): 

"""Make a MockExposure 

 

@param[in] numExp total number of exposures that will be made 

@param[in] coaddInputRecoder an instance of CoaddInputRecorderTask 

@param[in] version desired version of CoaddInput/ExposureTable; 

1 for no VisitInfo; this will only produce the desired result 

if you run the test with code from before VisitInfo, e.g. version 12.1) 

2 to include VisitInfo 

""" 

self.numExp = int(numExp) 

self.coaddInputRecorder = coaddInputRecorder 

self.version = int(version) 

 

def makeExposure(self, universalId): 

"""Make a tiny exposure with exposure info set, but no pixels 

 

In particular, exposure info is set as a record in a table, so it can be recorded in a coadd 

""" 

inputRecorder = self.coaddInputRecorder.makeCoaddTempExpRecorder(universalId, self.numExp) 

bbox = lsst.afw.geom.Box2I(lsst.afw.geom.Point2I(100, 100), lsst.afw.geom.Extent2I(10, 10)) 

 

detectorName = "detector {}".format(universalId) 

detector = lsst.afw.cameraGeom.testUtils.DetectorWrapper(name=detectorName, id=universalId).detector 

 

exp = lsst.afw.image.ExposureF(bbox) 

exp.setDetector(detector) 

 

expInfo = exp.getInfo() 

scale = 5.1e-5*lsst.afw.geom.degrees 

cdMatrix = lsst.afw.geom.makeCdMatrix(scale=scale) 

wcs = lsst.afw.geom.makeSkyWcs( 

crpix=lsst.afw.geom.Point2D(5, 5), 

crval=lsst.afw.geom.SpherePoint(10, 45, lsst.afw.geom.degrees), 

cdMatrix=cdMatrix, 

) 

expInfo.setWcs(wcs) 

expInfo.setPsf(GaussianPsf(5, 5, 2.5)) 

calib = lsst.afw.image.Calib() 

calib.setFluxMag0(1.1e12, 2.2e10) 

expInfo.setCalib(calib) 

expInfo.setApCorrMap(self.makeApCorrMap()) 

expInfo.setValidPolygon(lsst.afw.geom.Polygon(lsst.afw.geom.Box2D(bbox).getCorners())) 

if self.version > 1: 

expInfo.setVisitInfo(self.makeVisitInfo()) 

 

inputRecorder.addCalExp(calExp=exp, ccdId=universalId, nGoodPix=100) 

inputRecorder.finish(coaddTempExp=exp, nGoodPix=100) 

 

return exp 

 

@staticmethod 

def makeWcs(): 

scale = 5.1e-5*lsst.afw.geom.degrees 

cdMatrix = lsst.afw.geom.makeCdMatrix(scale=scale) 

return lsst.afw.geom.makeSkyWcs( 

crpix=lsst.afw.geom.Point2D(5, 5), 

crval=lsst.afw.geom.SpherePoint(10, 45, lsst.afw.geom.degrees), 

cdMatrix=cdMatrix, 

) 

 

@staticmethod 

def makeVisitInfo(): 

return lsst.afw.image.VisitInfo( 

10313423, 

10.01, 

11.02, 

DateTime(65321.1, DateTime.MJD, DateTime.TAI), 

12345.1, 

45.1*lsst.afw.geom.degrees, 

lsst.afw.geom.SpherePoint(23.1, 73.2, lsst.afw.geom.degrees), 

lsst.afw.geom.SpherePoint(134.5, 33.3, lsst.afw.geom.degrees), 

1.73, 

73.2*lsst.afw.geom.degrees, 

lsst.afw.image.RotType.SKY, 

Observatory(11.1*lsst.afw.geom.degrees, 22.2*lsst.afw.geom.degrees, 0.333), 

Weather(1.1, 2.2, 34.5), 

) 

 

@staticmethod 

def makeApCorrMap(): 

"""Make a trivial ApCorrMap with three elements""" 

bbox = lsst.afw.geom.Box2I(lsst.afw.geom.Point2I(-5, -5), lsst.afw.geom.Point2I(5, 5)) 

apCorrMap = lsst.afw.image.ApCorrMap() 

for name in ("a", "b", "c"): 

apCorrMap.set(name, ChebyshevBoundedField(bbox, np.zeros((3, 3), dtype=float))) 

return apCorrMap 

 

 

class MockCoadd: 

 

"""Class to make a mock coadd 

""" 

 

def __init__(self, numExp, version=2): 

"""Create a coadd with the specified number of exposures. 

 

@param[in] numExp total number of exposures that will be made 

@param[in] version desired version of CoaddInput/ExposureTable; see MockExposure for details 

 

Useful fields include: 

- coadd 

- exposures a list of exposures that went into the coadd 

""" 

coaddInputRecorder = CoaddInputRecorderTask(name="coaddInputRecorder") 

mockExposure = MockExposure(numExp=numExp, coaddInputRecorder=coaddInputRecorder, version=version) 

self.exposures = [mockExposure.makeExposure(i) for i in range(numExp)] 

 

exp0 = self.exposures[0] 

self.coadd = lsst.afw.image.ExposureF(exp0.getBBox()) 

self.coadd.setWcs(exp0.getWcs()) 

 

coaddInputs = coaddInputRecorder.makeCoaddInputs() 

for exp in self.exposures: 

coaddInputRecorder.addVisitToCoadd(coaddInputs=coaddInputs, coaddTempExp=exp, weight=1.0/numExp) 

self.coadd.getInfo().setCoaddInputs(coaddInputs) 

 

 

class CoaddInputsTestCase(lsst.utils.tests.TestCase): 

 

def setUp(self): 

self.version = 2 # desired version of ExposureTable/CoaddInput 

self.numExp = 3 

mockCoadd = MockCoadd(numExp=self.numExp, version=self.version) 

self.coadd = mockCoadd.coadd 

self.exposures = mockCoadd.exposures 

self.dataDir = os.path.join(os.path.dirname(__file__), "data") 

 

def tearDown(self): 

del self.coadd 

del self.exposures 

 

def assertPsfsAlmostEqual(self, psf1, psf2): 

im1 = psf1.computeImage() 

im2 = psf2.computeImage() 

self.assertImagesAlmostEqual(im1, im2) 

 

def getCoaddPath(self, version): 

return os.path.join(self.dataDir, 

"testCoaddInputs_coadd_with_version_{}_data.fits".format(version)) 

 

def testPersistence(self): 

"""Read and write a coadd and check the CoaddInputs""" 

coaddPath = self.getCoaddPath(version=self.version) 

self.coadd.writeFits(coaddPath) 

coadd = lsst.afw.image.ExposureF(coaddPath) 

coaddInputs = coadd.getInfo().getCoaddInputs() 

self.assertCoaddInputsOk(coaddInputs, version=self.version) 

if not SaveCoadd: 

os.unlink(coaddPath) 

else: 

print("SaveCoadd true; saved coadd as: %r" % (coaddPath,)) 

 

def testReadV1Coadd(self): 

"""Read a coadd that contains version 1 CoaddInputs 

 

The test code in question has FK5 WCS 

""" 

coaddPath = self.getCoaddPath(version=1) 

print("coaddPath=", coaddPath) 

coadd = lsst.afw.image.ExposureF(coaddPath) 

coaddWcs = coadd.getWcs() 

# the exposure in question uses FK5 for its WCS so update the exposures 

for exposure in self.exposures: 

exposure.setWcs(coaddWcs) 

coaddInputs = coadd.getInfo().getCoaddInputs() 

self.assertCoaddInputsOk(coaddInputs, version=1) 

 

def assertCoaddInputsOk(self, coaddInputs, version): 

self.assertIsNotNone(coaddInputs) 

for expTable in (coaddInputs.ccds, coaddInputs.visits): 

self.assertEqual(len(expTable), 3) 

for i, expRec in enumerate(expTable): 

exp = self.exposures[i] 

expInfo = exp.getInfo() 

self.assertEqual(expRec.getId(), i) 

self.assertEqual(expRec.getBBox(), exp.getBBox()) 

self.assertWcsAlmostEqualOverBBox(expRec.getWcs(), expInfo.getWcs(), expRec.getBBox()) 

self.assertPsfsAlmostEqual(expRec.getPsf(), exp.getPsf()) 

self.assertPairsAlmostEqual(expRec.getCalib().getFluxMag0(), (1.1e12, 2.2e10)) 

self.assertEqual(len(expRec.getApCorrMap()), 3) 

self.assertEqual(set(expRec.getApCorrMap().keys()), set(expInfo.getApCorrMap().keys())) 

self.assertFloatsAlmostEqual(np.array(expRec.getValidPolygon().getVertices()), 

np.array(expInfo.getValidPolygon().getVertices())) 

if version > 1: 

self.assertEqual(expRec.getVisitInfo(), expInfo.getVisitInfo()) 

else: 

self.assertIsNone(expRec.getVisitInfo()) 

 

 

class MemoryTester(lsst.utils.tests.MemoryTestCase): 

pass 

 

 

def setup_module(module): 

lsst.utils.tests.init() 

 

 

266 ↛ 267line 266 didn't jump to line 267, because the condition on line 266 was never trueif __name__ == "__main__": 

lsst.utils.tests.init() 

unittest.main()