Coverage for tests / test_isrTask.py: 12%

373 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-23 08:35 +0000

1# 

2# LSST Data Management System 

3# Copyright 2008-2017 AURA/LSST. 

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 published by 

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 <https://www.lsstcorp.org/LegalNotices/>. 

21# 

22 

23import unittest 

24import numpy as np 

25 

26import lsst.afw.image as afwImage 

27import lsst.ip.isr.isrMock as isrMock 

28import lsst.utils.tests 

29from lsst.ip.isr.isrTask import (IsrTask, IsrTaskConfig) 

30from lsst.ip.isr.isrQa import IsrQaConfig 

31from lsst.pipe.base import Struct 

32from lsst.ip.isr import PhotonTransferCurveDataset 

33 

34 

35def countMaskedPixels(maskedImage, maskPlane): 

36 """Function to count the number of masked pixels of a given type. 

37 

38 Parameters 

39 ---------- 

40 maskedImage : `lsst.afw.image.MaskedImage` 

41 Image to measure the mask on. 

42 maskPlane : `str` 

43 Name of the mask plane to count 

44 

45 Returns 

46 ------- 

47 nMask : `int` 

48 Number of masked pixels. 

49 """ 

50 bitMask = maskedImage.getMask().getPlaneBitMask(maskPlane) 

51 isBit = maskedImage.getMask().getArray() & bitMask > 0 

52 numBit = np.sum(isBit) 

53 return numBit 

54 

55 

56def computeImageMedianAndStd(image): 

57 """Function to calculate median and std of image data. 

58 

59 Parameters 

60 ---------- 

61 image : `lsst.afw.image.Image` 

62 Image to measure statistics on. 

63 

64 Returns 

65 ------- 

66 median : `float` 

67 Image median. 

68 std : `float` 

69 Image stddev. 

70 """ 

71 median = np.nanmedian(image.getArray()) 

72 std = np.nanstd(image.getArray()) 

73 return (median, std) 

74 

75 

76class IsrTaskTestCases(lsst.utils.tests.TestCase): 

77 """Test IsrTask methods with trimmed raw data. 

78 """ 

79 def setUp(self): 

80 self.config = IsrTaskConfig() 

81 self.config.overscan.doParallelOverscan = True 

82 self.config.qa = IsrQaConfig() 

83 self.task = IsrTask(config=self.config) 

84 self.camera = isrMock.IsrMock().getCamera() 

85 

86 self.inputExp = isrMock.TrimmedRawMock().run() 

87 self.amp = self.inputExp.getDetector()[0] 

88 self.mi = self.inputExp.getMaskedImage() 

89 

90 def validateIsrData(self, results): 

91 """results should be a struct with components that are 

92 not None if included in the configuration file. 

93 """ 

94 self.assertIsInstance(results, Struct) 

95 if self.config.doBias is True: 

96 self.assertIsNotNone(results.bias) 

97 if self.config.doDark is True: 

98 self.assertIsNotNone(results.dark) 

99 if self.config.doFlat is True: 

100 self.assertIsNotNone(results.flat) 

101 if self.config.doFringe is True: 

102 self.assertIsNotNone(results.fringes) 

103 if self.config.doDefect is True: 

104 self.assertIsNotNone(results.defects) 

105 if self.config.doBrighterFatter is True: 

106 self.assertIsNotNone(results.bfKernel) 

107 if self.config.doAttachTransmissionCurve is True: 

108 self.assertIsNotNone(results.opticsTransmission) 

109 self.assertIsNotNone(results.filterTransmission) 

110 self.assertIsNotNone(results.sensorTransmission) 

111 self.assertIsNotNone(results.atmosphereTransmission) 

112 

113 def test_ensureExposure(self): 

114 """Test that an exposure has a usable instance class. 

115 """ 

116 self.assertIsInstance(self.task.ensureExposure(self.inputExp, self.camera, 0), 

117 afwImage.Exposure) 

118 

119 def test_convertItoF(self): 

120 """Test conversion from integer to floating point pixels. 

121 """ 

122 result = self.task.convertIntToFloat(self.inputExp) 

123 self.assertEqual(result.getImage().getArray().dtype, np.dtype("float32")) 

124 self.assertEqual(result, self.inputExp) 

125 

126 def test_updateVariance(self): 

127 """Expect The variance image should have a larger median value after 

128 this operation. 

129 """ 

130 ampName = self.amp.getName() 

131 effectivePtc = PhotonTransferCurveDataset([ampName], "TEST_PTC", 1) 

132 effectivePtc.gain[ampName] = self.amp.getGain() 

133 effectivePtc.noise[ampName] = self.amp.getReadNoise() 

134 statBefore = computeImageMedianAndStd(self.inputExp.variance[self.amp.getBBox()]) 

135 # effectivePtc will have noise and gain. 

136 self.task.updateVariance(self.inputExp, self.amp, effectivePtc) 

137 statAfter = computeImageMedianAndStd(self.inputExp.variance[self.amp.getBBox()]) 

138 self.assertGreater(statAfter[0], statBefore[0]) 

139 self.assertFloatsAlmostEqual(statBefore[0], 0.0, atol=1e-2) 

140 self.assertFloatsAlmostEqual(statAfter[0], 8170.0195, atol=1e-2) 

141 

142 def test_defineEffectivePtc(self): 

143 ampName = self.amp.getName() 

144 inputPtc = PhotonTransferCurveDataset([ampName], "TEST_PTC", 1) 

145 inputPtc.gain[ampName] = 1.2 

146 inputPtc.noise[ampName] = 5 

147 

148 exposureMetadata = self.inputExp.getMetadata() 

149 detector = self.inputExp.getDetector() 

150 overscans = [self.task.overscanCorrection(self.inputExp, self.amp)] 

151 bfGains = {ampName: 1.5} 

152 

153 # Defaults 

154 # doEmpiricalReadNoise = False 

155 # usePtcReadNoise = False 

156 # usePtcGains = False 

157 # doRaiseOnCalibMismatch= False 

158 effectivePtc = self.task.defineEffectivePtc(inputPtc, detector, bfGains, 

159 overscans, 

160 exposureMetadata) 

161 self.assertEqual(effectivePtc.gain[ampName], self.amp.getGain()) 

162 self.assertEqual(effectivePtc.noise[ampName], self.amp.getReadNoise()) 

163 

164 # Use input PTC values 

165 self.config.usePtcGains = True 

166 self.config.usePtcReadNoise = True 

167 effectivePtc = self.task.defineEffectivePtc(inputPtc, detector, bfGains, 

168 overscans, 

169 exposureMetadata) 

170 self.assertEqual(effectivePtc.gain[ampName], inputPtc.gain[ampName]) 

171 self.assertEqual(effectivePtc.noise[ampName], inputPtc.noise[ampName]) 

172 

173 # use empirical readout noise from overscan and PTC gain 

174 self.config.usePtcGains = True 

175 self.config.doEmpiricalReadNoise = True 

176 effectivePtc = self.task.defineEffectivePtc(inputPtc, detector, bfGains, 

177 overscans, 

178 exposureMetadata) 

179 self.assertFloatsAlmostEqual( 

180 effectivePtc.noise[ampName], 

181 39.8794613621691*effectivePtc.gain[ampName], 

182 ) 

183 self.assertEqual(effectivePtc.gain[ampName], inputPtc.gain[ampName]) 

184 

185 # Raise if the PTC and BFK gains don't match 

186 results = None 

187 with self.assertRaises(RuntimeError): 

188 self.config.doRaiseOnCalibMismatch = True 

189 results = self.task.defineEffectivePtc(inputPtc, detector, bfGains, 

190 overscans, 

191 exposureMetadata) 

192 self.assertIsNone(results) 

193 

194 def test_darkCorrection(self): 

195 """Expect the median image value should decrease after this operation. 

196 """ 

197 darkIm = isrMock.DarkMock().run() 

198 

199 statBefore = computeImageMedianAndStd(self.inputExp.image[self.amp.getBBox()]) 

200 self.task.darkCorrection(self.inputExp, darkIm) 

201 statAfter = computeImageMedianAndStd(self.inputExp.image[self.amp.getBBox()]) 

202 self.assertLess(statAfter[0], statBefore[0]) 

203 self.assertFloatsAlmostEqual(statBefore[0], 8070.0195, atol=1e-2) 

204 self.assertFloatsAlmostEqual(statAfter[0], 8045.7773, atol=1e-2) 

205 

206 def test_darkCorrection_noVisitInfo(self): 

207 """Expect the median image value should decrease after this operation. 

208 """ 

209 darkIm = isrMock.DarkMock().run() 

210 darkIm.getInfo().setVisitInfo(None) 

211 

212 statBefore = computeImageMedianAndStd(self.inputExp.image[self.amp.getBBox()]) 

213 self.task.darkCorrection(self.inputExp, darkIm) 

214 statAfter = computeImageMedianAndStd(self.inputExp.image[self.amp.getBBox()]) 

215 self.assertLess(statAfter[0], statBefore[0]) 

216 self.assertFloatsAlmostEqual(statBefore[0], 8070.0195, atol=1e-2) 

217 self.assertFloatsAlmostEqual(statAfter[0], 8045.7773, atol=1e-2) 

218 

219 def test_flatCorrection(self): 

220 """Expect the image median should increase (divide by < 1). 

221 """ 

222 flatIm = isrMock.FlatMock().run() 

223 

224 statBefore = computeImageMedianAndStd(self.inputExp.image[self.amp.getBBox()]) 

225 self.task.flatCorrection(self.inputExp, flatIm) 

226 statAfter = computeImageMedianAndStd(self.inputExp.image[self.amp.getBBox()]) 

227 self.assertGreater(statAfter[1], statBefore[1]) 

228 self.assertFloatsAlmostEqual(statAfter[1], 147407.02, atol=1e-2) 

229 self.assertFloatsAlmostEqual(statBefore[1], 147.55304, atol=1e-2) 

230 

231 def test_saturationDetection(self): 

232 """Expect the saturation level detection/masking to scale with 

233 threshold. 

234 """ 

235 ampB = self.amp.rebuild() 

236 ampB.setSaturation(9000.0) 

237 self.task.saturationDetection(self.inputExp, ampB.finish()) 

238 countBefore = countMaskedPixels(self.mi, "SAT") 

239 

240 ampB.setSaturation(8250.0) 

241 self.task.saturationDetection(self.inputExp, ampB.finish()) 

242 countAfter = countMaskedPixels(self.mi, "SAT") 

243 

244 self.assertLessEqual(countBefore, countAfter) 

245 self.assertEqual(countBefore, 43) 

246 self.assertEqual(countAfter, 136) 

247 

248 def test_measureBackground(self): 

249 """Expect the background measurement runs successfully and to save 

250 metadata values. 

251 """ 

252 self.config.qa.flatness.meshX = 20 

253 self.config.qa.flatness.meshY = 20 

254 self.task.measureBackground(self.inputExp, self.config.qa) 

255 self.assertIsNotNone(self.inputExp.getMetadata().getScalar('SKYLEVEL')) 

256 

257 def test_flatContext(self): 

258 """Expect the flat context manager runs successfully (applying both 

259 flat and dark within the context), and results in the same 

260 image data after completion. 

261 """ 

262 darkExp = isrMock.DarkMock().run() 

263 flatExp = isrMock.FlatMock().run() 

264 

265 mi = self.inputExp.getMaskedImage().clone() 

266 with self.task.flatContext(self.inputExp, flatExp, darkExp): 

267 contextStat = computeImageMedianAndStd(self.inputExp.getMaskedImage().getImage()) 

268 self.assertFloatsAlmostEqual(contextStat[0], 37165.594, atol=1e-2) 

269 

270 self.assertMaskedImagesAlmostEqual(mi, self.inputExp.getMaskedImage()) 

271 

272 

273class IsrTaskUnTrimmedTestCases(lsst.utils.tests.TestCase): 

274 """Test IsrTask methods using untrimmed raw data. 

275 """ 

276 def setUp(self): 

277 self.config = IsrTaskConfig() 

278 self.config.overscan.doParallelOverscan = True 

279 self.config.qa = IsrQaConfig() 

280 self.task = IsrTask(config=self.config) 

281 

282 self.mockConfig = isrMock.IsrMockConfig() 

283 self.mockConfig.isTrimmed = False 

284 self.doGenerateImage = True 

285 self.dataContainer = isrMock.MockDataContainer(config=self.mockConfig) 

286 self.camera = isrMock.IsrMock(config=self.mockConfig).getCamera() 

287 

288 self.inputExp = isrMock.RawMock(config=self.mockConfig).run() 

289 self.amp = self.inputExp.getDetector()[0] 

290 self.mi = self.inputExp.getMaskedImage() 

291 

292 def batchSetConfiguration(self, value): 

293 """Set the configuration state to a consistent value. 

294 

295 Disable options we do not need as well. 

296 

297 Parameters 

298 ---------- 

299 value : `bool` 

300 Value to switch common ISR configuration options to. 

301 """ 

302 self.config.qa.flatness.meshX = 20 

303 self.config.qa.flatness.meshY = 20 

304 self.config.doWrite = False 

305 self.config.doLinearize = False 

306 self.config.doCrosstalk = False 

307 

308 self.config.doConvertIntToFloat = value 

309 self.config.doSaturation = value 

310 self.config.doSuspect = value 

311 self.config.doSetBadRegions = value 

312 self.config.doOverscan = value 

313 self.config.doBias = value 

314 self.config.doVariance = value 

315 self.config.doWidenSaturationTrails = value 

316 self.config.doBrighterFatter = value 

317 self.config.doDefect = value 

318 self.config.doSaturationInterpolation = value 

319 self.config.doDark = value 

320 self.config.doStrayLight = value 

321 self.config.doFlat = value 

322 self.config.doFringe = value 

323 self.config.doMeasureBackground = value 

324 self.config.doVignette = value 

325 self.config.doAttachTransmissionCurve = value 

326 self.config.doUseOpticsTransmission = value 

327 self.config.doUseFilterTransmission = value 

328 self.config.doUseSensorTransmission = value 

329 self.config.doUseAtmosphereTransmission = value 

330 self.config.qa.saveStats = value 

331 self.config.qa.doThumbnailOss = value 

332 self.config.qa.doThumbnailFlattened = value 

333 

334 self.config.doApplyGains = not value 

335 self.config.doCameraSpecificMasking = value 

336 

337 def validateIsrResults(self): 

338 """results should be a struct with components that are 

339 not None if included in the configuration file. 

340 

341 Returns 

342 ------- 

343 results : `pipeBase.Struct` 

344 Results struct generated from the current ISR configuration. 

345 """ 

346 self.task = IsrTask(config=self.config) 

347 results = self.task.run(self.inputExp, 

348 camera=self.camera, 

349 bias=self.dataContainer.get("bias"), 

350 dark=self.dataContainer.get("dark"), 

351 flat=self.dataContainer.get("flat"), 

352 bfKernel=self.dataContainer.get("bfKernel"), 

353 defects=self.dataContainer.get("defects"), 

354 fringes=Struct(fringes=self.dataContainer.get("fringe"), seed=1234), 

355 opticsTransmission=self.dataContainer.get("transmission_"), 

356 filterTransmission=self.dataContainer.get("transmission_"), 

357 sensorTransmission=self.dataContainer.get("transmission_"), 

358 atmosphereTransmission=self.dataContainer.get("transmission_") 

359 ) 

360 

361 self.assertIsInstance(results, Struct) 

362 self.assertIsInstance(results.exposure, afwImage.Exposure) 

363 return results 

364 

365 def test_run_allTrue(self): 

366 """Expect successful run with expected outputs when all non-exclusive 

367 configuration options are on. 

368 

369 Output results should be tested more precisely by the 

370 individual function tests. 

371 

372 """ 

373 self.batchSetConfiguration(True) 

374 self.validateIsrResults() 

375 

376 def test_run_allFalse(self): 

377 """Expect successful run with expected outputs when all non-exclusive 

378 configuration options are off. 

379 

380 Output results should be tested more precisely by the 

381 individual function tests. 

382 

383 """ 

384 self.batchSetConfiguration(False) 

385 self.validateIsrResults() 

386 

387 def test_failCases(self): 

388 """Expect failure with crosstalk enabled. 

389 

390 Output results should be tested more precisely by the 

391 individual function tests. 

392 """ 

393 self.batchSetConfiguration(True) 

394 

395 # This breaks it 

396 self.config.doCrosstalk = True 

397 

398 with self.assertRaises(RuntimeError): 

399 self.validateIsrResults() 

400 

401 def test_maskingCase_negativeVariance(self): 

402 """Test masking cases of configuration parameters. 

403 """ 

404 self.batchSetConfiguration(True) 

405 self.config.overscan.doParallelOverscan = False 

406 self.config.overscan.fitType = "POLY" 

407 self.config.overscan.order = 1 

408 

409 self.config.doSaturation = False 

410 self.config.doWidenSaturationTrails = False 

411 self.config.doSaturationInterpolation = False 

412 self.config.doSuspect = False 

413 self.config.doSetBadRegions = False 

414 self.config.doDefect = False 

415 self.config.doBrighterFatter = False 

416 

417 self.config.maskNegativeVariance = True 

418 self.config.doInterpolate = False 

419 

420 results = self.validateIsrResults() 

421 

422 self.assertEqual(countMaskedPixels(results.exposure, "SAT"), 0) 

423 self.assertEqual(countMaskedPixels(results.exposure, "INTRP"), 0) 

424 self.assertEqual(countMaskedPixels(results.exposure, "SUSPECT"), 0) 

425 self.assertEqual(countMaskedPixels(results.exposure, "BAD"), 40800) 

426 

427 def test_maskingCase_noMasking(self): 

428 """Test masking cases of configuration parameters. 

429 """ 

430 self.batchSetConfiguration(True) 

431 self.config.overscan.fitType = "POLY" 

432 self.config.overscan.order = 1 

433 

434 self.config.doSaturation = False 

435 self.config.doWidenSaturationTrails = False 

436 self.config.doSaturationInterpolation = False 

437 self.config.doSuspect = False 

438 self.config.doSetBadRegions = False 

439 self.config.doDefect = False 

440 self.config.doBrighterFatter = False 

441 

442 self.config.maskNegativeVariance = False 

443 self.config.doInterpolate = False 

444 

445 results = self.validateIsrResults() 

446 

447 self.assertEqual(countMaskedPixels(results.exposure, "SAT"), 0) 

448 self.assertEqual(countMaskedPixels(results.exposure, "INTRP"), 0) 

449 self.assertEqual(countMaskedPixels(results.exposure, "SUSPECT"), 0) 

450 self.assertEqual(countMaskedPixels(results.exposure, "BAD"), 0) 

451 

452 def test_maskingCase_satMasking(self): 

453 """Test masking cases of configuration parameters. 

454 """ 

455 self.batchSetConfiguration(True) 

456 self.config.overscan.fitType = "POLY" 

457 self.config.overscan.order = 1 

458 

459 self.config.saturation = 20000.0 

460 self.config.doSaturation = True 

461 self.config.doWidenSaturationTrails = True 

462 

463 self.config.doSaturationInterpolation = False 

464 self.config.doSuspect = False 

465 self.config.doSetBadRegions = False 

466 self.config.doDefect = False 

467 self.config.doBrighterFatter = False 

468 

469 self.config.maskNegativeVariance = False # These are mock images. 

470 

471 results = self.validateIsrResults() 

472 

473 self.assertEqual(countMaskedPixels(results.exposure, "SAT"), 0) 

474 self.assertEqual(countMaskedPixels(results.exposure, "INTRP"), 0) 

475 self.assertEqual(countMaskedPixels(results.exposure, "SUSPECT"), 0) 

476 self.assertEqual(countMaskedPixels(results.exposure, "BAD"), 0) 

477 

478 def test_maskingCase_satMaskingAndInterp(self): 

479 """Test masking cases of configuration parameters. 

480 """ 

481 self.batchSetConfiguration(True) 

482 self.config.overscan.fitType = "POLY" 

483 self.config.overscan.order = 1 

484 

485 self.config.saturation = 20000.0 

486 self.config.doSaturation = True 

487 self.config.doWidenSaturationTrails = True 

488 self.config.doSaturationInterpolation = True 

489 

490 self.config.doSuspect = False 

491 self.config.doSetBadRegions = False 

492 self.config.doDefect = False 

493 self.config.doBrighterFatter = False 

494 

495 self.config.maskNegativeVariance = False # These are mock images. 

496 

497 results = self.validateIsrResults() 

498 

499 self.assertEqual(countMaskedPixels(results.exposure, "SAT"), 0) 

500 self.assertEqual(countMaskedPixels(results.exposure, "INTRP"), 0) 

501 self.assertEqual(countMaskedPixels(results.exposure, "SUSPECT"), 0) 

502 self.assertEqual(countMaskedPixels(results.exposure, "BAD"), 0) 

503 

504 def test_maskingCase_throughEdge(self): 

505 """Test masking cases of configuration parameters. 

506 """ 

507 self.batchSetConfiguration(True) 

508 self.config.overscan.fitType = "POLY" 

509 self.config.overscan.order = 1 

510 

511 self.config.saturation = 20000.0 

512 self.config.doSaturation = True 

513 self.config.doWidenSaturationTrails = True 

514 self.config.doSaturationInterpolation = True 

515 self.config.numEdgeSuspect = 5 

516 self.config.doSuspect = True 

517 

518 self.config.doSetBadRegions = False 

519 self.config.doDefect = False 

520 self.config.doBrighterFatter = False 

521 

522 self.config.maskNegativeVariance = False # These are mock images. 

523 

524 results = self.validateIsrResults() 

525 

526 self.assertEqual(countMaskedPixels(results.exposure, "SAT"), 0) 

527 self.assertEqual(countMaskedPixels(results.exposure, "INTRP"), 0) 

528 self.assertEqual(countMaskedPixels(results.exposure, "SUSPECT"), 0) 

529 self.assertEqual(countMaskedPixels(results.exposure, "BAD"), 0) 

530 

531 def test_maskingCase_throughDefects(self): 

532 """Test masking cases of configuration parameters. 

533 """ 

534 self.batchSetConfiguration(True) 

535 self.config.overscan.fitType = "POLY" 

536 self.config.overscan.order = 1 

537 

538 self.config.saturation = 20000.0 

539 self.config.doSaturation = True 

540 self.config.doWidenSaturationTrails = True 

541 self.config.doSaturationInterpolation = True 

542 self.config.numEdgeSuspect = 5 

543 self.config.doSuspect = True 

544 self.config.doDefect = True 

545 

546 self.config.doSetBadRegions = False 

547 self.config.doBrighterFatter = False 

548 

549 self.config.maskNegativeVariance = False # These are mock images. 

550 

551 results = self.validateIsrResults() 

552 

553 self.assertEqual(countMaskedPixels(results.exposure, "SAT"), 0) 

554 self.assertEqual(countMaskedPixels(results.exposure, "INTRP"), 2000) 

555 self.assertEqual(countMaskedPixels(results.exposure, "SUSPECT"), 3940) 

556 self.assertEqual(countMaskedPixels(results.exposure, "BAD"), 2000) 

557 

558 def test_maskingCase_throughDefectsAmpEdges(self): 

559 """Test masking cases of configuration parameters. 

560 """ 

561 self.batchSetConfiguration(True) 

562 self.config.overscan.fitType = "POLY" 

563 self.config.overscan.order = 1 

564 

565 self.config.saturation = 20000.0 

566 self.config.doSaturation = True 

567 self.config.doWidenSaturationTrails = True 

568 self.config.doSaturationInterpolation = True 

569 self.config.numEdgeSuspect = 5 

570 self.config.doSuspect = True 

571 self.config.doDefect = True 

572 self.config.edgeMaskLevel = 'AMP' 

573 

574 self.config.doSetBadRegions = False 

575 self.config.doBrighterFatter = False 

576 

577 self.config.maskNegativeVariance = False # These are mock images. 

578 

579 results = self.validateIsrResults() 

580 

581 self.assertEqual(countMaskedPixels(results.exposure, "SAT"), 0) 

582 self.assertEqual(countMaskedPixels(results.exposure, "INTRP"), 2000) 

583 self.assertEqual(countMaskedPixels(results.exposure, "SUSPECT"), 11280) 

584 self.assertEqual(countMaskedPixels(results.exposure, "BAD"), 2000) 

585 

586 def test_maskingCase_throughBad(self): 

587 """Test masking cases of configuration parameters. 

588 """ 

589 self.batchSetConfiguration(True) 

590 self.config.overscan.fitType = "POLY" 

591 self.config.overscan.order = 1 

592 

593 self.config.saturation = 20000.0 

594 self.config.doSaturation = True 

595 self.config.doWidenSaturationTrails = True 

596 self.config.doSaturationInterpolation = True 

597 

598 self.config.doSuspect = True 

599 self.config.doDefect = True 

600 self.config.doSetBadRegions = True 

601 self.config.doBrighterFatter = False 

602 

603 self.config.maskNegativeVariance = False # These are mock images. 

604 

605 results = self.validateIsrResults() 

606 

607 self.assertEqual(countMaskedPixels(results.exposure, "SAT"), 0) 

608 self.assertEqual(countMaskedPixels(results.exposure, "INTRP"), 2000) 

609 self.assertEqual(countMaskedPixels(results.exposure, "SUSPECT"), 0) 

610 self.assertEqual(countMaskedPixels(results.exposure, "BAD"), 2000) 

611 

612 def test_binnedExposures(self): 

613 """Ensure that binned exposures have correct sizes.""" 

614 self.batchSetConfiguration(True) 

615 self.config.doBinnedExposures = True 

616 self.config.binFactor1 = 8 

617 self.config.binFactor2 = 64 

618 

619 results = self.validateIsrResults() 

620 

621 original = results.exposure.image.array.shape 

622 bin1 = results.outputBin1Exposure.image.array.shape 

623 bin2 = results.outputBin2Exposure.image.array.shape 

624 

625 # Binning truncates, so check that the original and obtained 

626 # binned images have the correct offset. 

627 self.assertEqual(original[0] - bin1[0] * 8, 4) 

628 self.assertEqual(original[1] - bin1[1] * 8, 0) 

629 self.assertEqual(original[0] - bin2[0] * 64, 12) 

630 self.assertEqual(original[1] - bin2[1] * 64, 8) 

631 

632 

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

634 pass 

635 

636 

637def setup_module(module): 

638 lsst.utils.tests.init() 

639 

640 

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

642 lsst.utils.tests.init() 

643 unittest.main(failfast=True)