Coverage for tests / test_ptc.py: 6%

568 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-05-01 08:54 +0000

1#!/usr/bin/env python 

2 

3# 

4# LSST Data Management System 

5# 

6# Copyright 2008-2017 AURA/LSST. 

7# 

8# This product includes software developed by the 

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

10# 

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

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

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

14# (at your option) any later version. 

15# 

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

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

18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

19# GNU General Public License for more details. 

20# 

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

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

23# see <https://www.lsstcorp.org/LegalNotices/>. 

24# 

25"""Test cases for cp_pipe.""" 

26 

27import unittest 

28import numpy as np 

29import copy 

30import tempfile 

31import logging 

32import warnings 

33 

34import lsst.log 

35import lsst.utils 

36import lsst.utils.tests 

37 

38import lsst.cp.pipe as cpPipe 

39import lsst.ip.isr.isrMock as isrMock 

40from lsst.ip.isr import PhotonTransferCurveDataset, PhotodiodeCalib, AmpOffsetTask 

41from lsst.cp.pipe.utils import makeMockFlats, ampOffsetGainRatioFixup 

42 

43from lsst.pipe.base import InMemoryDatasetHandle 

44 

45 

46class FakeCamera(list): 

47 def getName(self): 

48 return "FakeCam" 

49 

50 

51class PretendRef: 

52 "A class to act as a mock exposure reference" 

53 

54 def __init__(self, exposure): 

55 self.exp = exposure 

56 

57 def get(self, component=None): 

58 if component == "visitInfo": 

59 return self.exp.info.getVisitInfo() 

60 elif component == "detector": 

61 return self.exp.getDetector() 

62 elif component == "metadata": 

63 return self.exp.getMetadata() 

64 else: 

65 return self.exp 

66 

67 

68class MeasurePhotonTransferCurveTaskTestCase(lsst.utils.tests.TestCase): 

69 """A test case for the PTC tasks.""" 

70 

71 def setUp(self): 

72 self.defaultConfigExtract = ( 

73 cpPipe.ptc.PhotonTransferCurveExtractPairTask.ConfigClass() 

74 ) 

75 self.defaultTaskExtract = cpPipe.ptc.PhotonTransferCurveExtractTask( 

76 config=self.defaultConfigExtract 

77 ) 

78 

79 self.defaultConfigSolve = cpPipe.ptc.PhotonTransferCurveSolveTask.ConfigClass() 

80 self.defaultTaskSolve = cpPipe.ptc.PhotonTransferCurveSolveTask( 

81 config=self.defaultConfigSolve 

82 ) 

83 

84 self.flatMean = 2000 

85 self.readNoiseAdu = 10 

86 mockImageConfig = isrMock.IsrMock.ConfigClass() 

87 

88 # flatDrop is not really relevant as we replace the data 

89 # but good to note it in case we change how this image is made 

90 mockImageConfig.flatDrop = 0.99999 

91 mockImageConfig.isTrimmed = True 

92 

93 self.flatExp1 = isrMock.FlatMock(config=mockImageConfig).run() 

94 self.flatExp2 = self.flatExp1.clone() 

95 (shapeY, shapeX) = self.flatExp1.getDimensions() 

96 

97 self.flatWidth = np.sqrt(self.flatMean) + self.readNoiseAdu 

98 

99 self.rng1 = np.random.RandomState(1984) 

100 flatData1 = self.rng1.normal(self.flatMean, self.flatWidth, (shapeX, shapeY)) 

101 self.rng2 = np.random.RandomState(666) 

102 flatData2 = self.rng2.normal(self.flatMean, self.flatWidth, (shapeX, shapeY)) 

103 

104 self.flatExp1.image.array[:] = flatData1 

105 self.flatExp2.image.array[:] = flatData2 

106 

107 # create fake PTC data to see if fit works, for one amp ('amp') 

108 self.flux = 1000.0 # ADU/sec 

109 self.timeVec = np.arange(1.0, 101.0, 5) 

110 self.k2NonLinearity = -5e-6 

111 # quadratic signal-chain non-linearity 

112 muVec = self.flux * self.timeVec + self.k2NonLinearity * self.timeVec**2 

113 self.gain = 0.75 # e-/ADU 

114 self.c1 = 1.0 / self.gain 

115 self.noiseSq = 2 * self.gain # 7.5 (e-)^2 

116 self.a00 = -1.2e-6 

117 self.c2 = -1.5e-6 

118 self.c3 = -4.7e-12 # tuned so that it turns over for 200k mean 

119 self.photoCharges = np.linspace(1e-8, 1e-5, len(self.timeVec)) 

120 

121 self.ampNames = [ 

122 amp.getName() for amp in self.flatExp1.getDetector().getAmplifiers() 

123 ] 

124 self.dataset = PhotonTransferCurveDataset(self.ampNames, ptcFitType="PARTIAL") 

125 self.covariancesSqrtWeights = {} 

126 for ( 

127 ampName 

128 ) in self.ampNames: # just the expTimes and means here - vars vary per function 

129 self.dataset.rawExpTimes[ampName] = self.timeVec 

130 self.dataset.rawMeans[ampName] = muVec 

131 self.dataset.covariancesSqrtWeights[ampName] = np.zeros( 

132 (1, self.dataset.covMatrixSide, self.dataset.covMatrixSide) 

133 ) 

134 

135 def test_covAstier(self): 

136 """Test to check getCovariancesAstier 

137 

138 We check that the gain is the same as the input gain from the 

139 mock data, that the covariances via FFT (as it is in 

140 MeasurePhotonTransferCurveTask when doCovariancesAstier=True) 

141 are the same as calculated in real space, and that Cov[0, 0] 

142 (i.e., the variances) are similar to the variances calculated 

143 with the standard method (when doCovariancesAstier=false), 

144 

145 """ 

146 extractConfig = self.defaultConfigExtract 

147 extractConfig.minNumberGoodPixelsForCovariance = 5000 

148 extractConfig.detectorMeasurementRegion = "FULL" 

149 extractConfig.doExtractPhotodiodeData = True 

150 extractConfig.doKsHistMeasurement = True 

151 extractConfig.auxiliaryHeaderKeys = ["CCOBCURR", "CCDTEMP"] 

152 extractPairTask = cpPipe.ptc.PhotonTransferCurveExtractPairTask(config=extractConfig) 

153 

154 # Create solve task config 

155 solveConfig = self.defaultConfigSolve 

156 # Cut off the low-flux point which is a bad fit, and this 

157 # also exercises this functionality and makes the tests 

158 # run a lot faster. 

159 solveConfig.minMeanSignal["ALL_AMPS"] = 2000.0 

160 # Set the outlier fit threshold higher than the default appropriate 

161 # for this test dataset. 

162 solveConfig.maxSignalInitialPtcOutlierFit = 90000.0 

163 # Given the limited nature of the test data, we can only 

164 # reliably fit out to a 3x3 covariance matrix. 

165 # Improvements will be investigated on DM-46131. 

166 solveConfig.maximumRangeCovariancesAstierFullCovFit = 3 

167 

168 inputGain = self.gain 

169 

170 muStandard, varStandard = {}, {} 

171 nPixelCovarianceStandard = {} 

172 expHandles = [] 

173 expIds = [] 

174 pdHandles = [] 

175 idCounter = 0 

176 for i, expTime in enumerate(self.timeVec): 

177 mockExp1, mockExp2 = makeMockFlats( 

178 expTime, 

179 gain=inputGain, 

180 readNoiseElectrons=3, 

181 expId1=idCounter, 

182 expId2=idCounter + 1, 

183 ampNames=self.ampNames, 

184 ) 

185 for mockExp in [mockExp1, mockExp2]: 

186 md = mockExp.getMetadata() 

187 # These values are chosen to be easily compared after 

188 # processing for correct ordering. 

189 md['CCOBCURR'] = float(idCounter) 

190 md['CCDTEMP'] = float(idCounter + 1) 

191 mockExp.setMetadata(md) 

192 md['SEQFILE'] = 'a_seqfile' 

193 md['SEQNAME'] = 'a_seqfile' 

194 md['SEQCKSUM'] = 'deadbeef' 

195 

196 mockExpRef1 = PretendRef(mockExp1) 

197 mockExpRef2 = PretendRef(mockExp2) 

198 expHandles.extend((mockExpRef1, mockExpRef2)) 

199 expIds.append(idCounter) 

200 expIds.append(idCounter + 1) 

201 maskValue = mockExp1.mask.getPlaneBitMask(extractPairTask.config.maskNameList) 

202 for ampNumber, ampName in enumerate(self.ampNames): 

203 # cov has (i, j, var, cov, npix) 

204 ( 

205 im1Area, 

206 im2Area, 

207 imStatsCtrl, 

208 mu1, 

209 mu2, 

210 ) = extractPairTask.getImageAreasMasksStats(mockExp1, mockExp2) 

211 nPixelCovariance = ((im1Area.mask.array & maskValue) == 0).sum() 

212 nPixelCovarianceStandard.setdefault(ampName, []).append(nPixelCovariance) 

213 muDiff, varDiff, covAstier, rowMeanVariance = extractPairTask.measureMeanVarCov( 

214 im1Area, im2Area, imStatsCtrl, mu1, mu2 

215 ) 

216 muStandard.setdefault(ampName, []).append(muDiff) 

217 varStandard.setdefault(ampName, []).append(varDiff) 

218 

219 # Make a photodiode dataset to integrate. 

220 timeSamples = np.linspace(0, 20.0, 100) 

221 currentSamples1 = np.zeros(100) 

222 currentSamples1[50] = -1.0*self.photoCharges[i] 

223 currentSamples2 = np.zeros(100) 

224 currentSamples2[50] = -1.0*(self.photoCharges[i] + 1e-12) 

225 

226 pdCalib1 = PhotodiodeCalib(timeSamples=timeSamples, currentSamples=currentSamples1) 

227 pdCalib1.currentScale = -1.0 

228 pdCalib1.integrationMethod = "CHARGE_SUM" 

229 

230 pdCalib2 = PhotodiodeCalib(timeSamples=timeSamples, currentSamples=currentSamples2) 

231 pdCalib2.currentScale = -1.0 

232 pdCalib2.integrationMethod = "CHARGE_SUM" 

233 

234 pdHandles.append( 

235 InMemoryDatasetHandle( 

236 pdCalib1, 

237 dataId={"exposure": idCounter}, 

238 ) 

239 ) 

240 pdHandles.append( 

241 InMemoryDatasetHandle( 

242 pdCalib2, 

243 dataId={"exposure": idCounter + 1}, 

244 ) 

245 ) 

246 idCounter += 2 

247 

248 # Divide out the pairs. 

249 outputCovariances = [] 

250 for i in range(len(expHandles) // 2): 

251 inputExp = [expHandles[2*i], expHandles[2*i + 1]] 

252 inputDims = [expIds[2*i], expIds[2*i + 1]] 

253 inputPhotodiodeData = [pdHandles[2*i], pdHandles[2*i + 1]] 

254 results = extractPairTask.run( 

255 inputExp=inputExp, 

256 inputDims=inputDims, 

257 inputPhotodiodeData=inputPhotodiodeData, 

258 ) 

259 outputCovariances.append(results.outputCovariance) 

260 

261 # Force the last PTC dataset to have a NaN, and ensure that the 

262 # task runs (DM-38029). This is a minor perturbation and does not 

263 # affect the output comparison. 

264 outputCovariances[-1].rawMeans["C:0,0"] = np.array([np.nan]) 

265 outputCovariances[-1].rawVars["C:0,0"] = np.array([np.nan]) 

266 

267 # Force the next-to-last PTC dataset to have a decreased variance to 

268 # ensure that the outlier fit rejection works. 

269 rawVar = outputCovariances[-2].rawVars["C:0,0"] 

270 outputCovariances[-2].rawVars["C:0,0"] = rawVar * 0.9 

271 

272 # Reorganize the outputCovariances so we can confirm they come 

273 # out sorted afterwards. 

274 outputCovariancesRev = outputCovariances[::-1] 

275 

276 # Some expected values for noise matrix, just to check that 

277 # it was calculated. 

278 expectedNoiseMatrix = { 

279 "FULLCOVARIANCE": np.array( 

280 [[8.99474598, 9.94916264, -27.90587299], 

281 [-2.95079527, -17.11827641, -47.88156244], 

282 [5.24915021, -3.25786165, 26.09634067]], 

283 ), 

284 "FULLCOVARIANCE_NO_B": np.array( 

285 [[8.71049338, 12.48584043, -37.06585088], 

286 [-4.80523971, -23.29102809, -66.37815343], 

287 [7.48654766, -4.10168337, 35.64469824]], 

288 ), 

289 } 

290 

291 for fitType in ["FULLCOVARIANCE", "FULLCOVARIANCE_NO_B"]: 

292 solveConfig.ptcFitType = fitType 

293 solveTask = cpPipe.ptc.PhotonTransferCurveSolveTask(config=solveConfig) 

294 

295 # Ensure no warnings re: read noise mismatches are logged. 

296 with self.assertNoLogs(level=logging.WARNING): 

297 resultsSolve = solveTask.run( 

298 outputCovariancesRev, camera=FakeCamera([self.flatExp1.getDetector()]) 

299 ) 

300 

301 ptc = resultsSolve.outputPtcDataset 

302 

303 # Confirm that metadata keywords are set. 

304 for key in ["SEQFILE", "SEQNAME", "SEQCKSUM"]: 

305 self.assertEqual(ptc.metadata[key], expHandles[0].get().metadata[key]) 

306 self.assertEqual(ptc.metadata["INSTRUME"], FakeCamera().getName()) 

307 det = expHandles[0].get().getDetector() 

308 self.assertEqual(ptc.metadata["DETECTOR"], det.getId()) 

309 self.assertEqual(ptc.metadata["DET_NAME"], det.getName()) 

310 self.assertEqual(ptc.metadata["DET_SER"], det.getSerial()) 

311 

312 for amp in self.ampNames: 

313 self.assertAlmostEqual(ptc.gain[amp], inputGain, places=2) 

314 self.assertFloatsAlmostEqual( 

315 np.asarray(varStandard[amp])[ptc.expIdMask[amp]] / ptc.finalVars[amp][ptc.expIdMask[amp]], 

316 1.0, 

317 rtol=1e-4, 

318 ) 

319 np.testing.assert_array_equal(ptc.nPixelCovariances[amp], nPixelCovarianceStandard[amp][0]) 

320 

321 # Check that the PTC turnoff is correctly computed. 

322 # This will be different for the C:0,0 amp. 

323 if amp == "C:0,0": 

324 self.assertAlmostEqual(ptc.ptcTurnoff[amp], ptc.rawMeans[amp][-3]) 

325 else: 

326 self.assertAlmostEqual(ptc.ptcTurnoff[amp], ptc.rawMeans[amp][-1]) 

327 

328 # Test that all the quantities are correctly ordered and 

329 # have not accidentally been masked. 

330 for i, extractPtc in enumerate(outputCovariances): 

331 self.assertFloatsAlmostEqual( 

332 extractPtc.rawExpTimes[ampName][0], 

333 ptc.rawExpTimes[ampName][i], 

334 ) 

335 self.assertFloatsAlmostEqual( 

336 extractPtc.rawMeans[ampName][0], 

337 ptc.rawMeans[ampName][i], 

338 ) 

339 self.assertFloatsAlmostEqual( 

340 extractPtc.rawVars[ampName][0], 

341 ptc.rawVars[ampName][i], 

342 ) 

343 self.assertFloatsAlmostEqual( 

344 extractPtc.rawDeltas[ampName][0], 

345 ptc.rawDeltas[ampName][i], 

346 ) 

347 # Ensure these are set to a non-zero value. 

348 self.assertFloatsNotEqual( 

349 extractPtc.rawDeltas[ampName][0], 

350 0.0, 

351 ) 

352 self.assertFloatsAlmostEqual( 

353 extractPtc.photoCharges[ampName][0], 

354 ptc.photoCharges[ampName][i], 

355 ) 

356 self.assertFloatsAlmostEqual( 

357 extractPtc.photoChargeDeltas[ampName][0], 

358 ptc.photoChargeDeltas[ampName][i], 

359 ) 

360 # Ensure these are set to a non-zero value. 

361 self.assertFloatsNotEqual( 

362 extractPtc.photoChargeDeltas[ampName][0], 

363 0.0, 

364 ) 

365 self.assertFloatsAlmostEqual( 

366 extractPtc.histVars[ampName][0], 

367 ptc.histVars[ampName][i], 

368 ) 

369 self.assertFloatsAlmostEqual( 

370 extractPtc.histChi2Dofs[ampName][0], 

371 ptc.histChi2Dofs[ampName][i], 

372 ) 

373 self.assertFloatsAlmostEqual( 

374 extractPtc.kspValues[ampName][0], 

375 ptc.kspValues[ampName][i], 

376 ) 

377 self.assertFloatsAlmostEqual( 

378 extractPtc.covariances[ampName][0], 

379 ptc.covariances[ampName][i], 

380 ) 

381 self.assertFloatsAlmostEqual( 

382 extractPtc.covariancesSqrtWeights[ampName][0], 

383 ptc.covariancesSqrtWeights[ampName][i], 

384 ) 

385 self.assertFloatsAlmostEqual( 

386 ptc.noiseMatrix[ampName], 

387 expectedNoiseMatrix[fitType], 

388 atol=1e-8, 

389 rtol=None, 

390 ) 

391 self.assertFloatsAlmostEqual( 

392 ptc.ampOffsets[ampName], 

393 0.0, 

394 ) 

395 self.assertFloatsAlmostEqual( 

396 ptc.noise[ampName], 

397 np.nanmedian(ptc.noiseList[ampName]) * ptc.gain[ampName], 

398 rtol=0.05, 

399 ) 

400 # If the noise error is greater than the noise, 

401 # something is seriously wrong. Possibly some 

402 # kind of gain application mismatch. 

403 self.assertLess( 

404 ptc.noiseErr[ampName], 

405 ptc.noise[ampName], 

406 ) 

407 

408 mask = ptc.getGoodPoints(amp) 

409 

410 values = ( 

411 ptc.covariancesModel[amp][mask, 0, 0] - ptc.covariances[amp][mask, 0, 0] 

412 ) / ptc.covariancesModel[amp][mask, 0, 0] 

413 np.testing.assert_array_less(np.abs(values), 2e-3) 

414 

415 if ptc.ptcFitType == "FULLCOVARIANCE": 

416 values = ( 

417 ptc.covariancesModel[amp][mask, 0, 1] - ptc.covariances[amp][mask, 0, 1] 

418 ) / ptc.covariancesModel[amp][mask, 0, 1] 

419 np.testing.assert_array_less(np.abs(values), 0.3) 

420 

421 values = ( 

422 ptc.covariancesModel[amp][mask, 1, 0] - ptc.covariances[amp][mask, 1, 0] 

423 ) / ptc.covariancesModel[amp][mask, 1, 0] 

424 np.testing.assert_array_less(np.abs(values), 0.3) 

425 

426 # And test that the auxiliary values are there and 

427 # correctly ordered. 

428 self.assertIn('CCOBCURR', ptc.auxValues) 

429 self.assertIn('CCDTEMP', ptc.auxValues) 

430 firstExpIds = np.array([i for i, _ in ptc.inputExpIdPairs['C:0,0']], dtype=np.float64) 

431 self.assertFloatsAlmostEqual(ptc.auxValues['CCOBCURR'], firstExpIds) 

432 self.assertFloatsAlmostEqual(ptc.auxValues['CCDTEMP'], firstExpIds + 1) 

433 

434 expIdsUsed = ptc.getExpIdsUsed("C:0,0") 

435 # Check that these are the same as the inputs, paired up, with the 

436 # first two (low flux) and final four (outliers, nans) removed. 

437 self.assertTrue( 

438 np.all(expIdsUsed == np.array(expIds).reshape(len(expIds) // 2, 2)[1:-2]) 

439 ) 

440 

441 goodAmps = ptc.getGoodAmps() 

442 self.assertEqual(goodAmps, self.ampNames) 

443 

444 # Check that every possibly modified field has the same length. 

445 covShape = None 

446 covSqrtShape = None 

447 covModelShape = None 

448 

449 for ampName in self.ampNames: 

450 if covShape is None: 

451 covShape = ptc.covariances[ampName].shape 

452 covSqrtShape = ptc.covariancesSqrtWeights[ampName].shape 

453 covModelShape = ptc.covariancesModel[ampName].shape 

454 else: 

455 self.assertEqual(ptc.covariances[ampName].shape, covShape) 

456 self.assertEqual( 

457 ptc.covariancesSqrtWeights[ampName].shape, covSqrtShape 

458 ) 

459 self.assertEqual(ptc.covariancesModel[ampName].shape, covModelShape) 

460 

461 # Check if evalPtcModel produces expected values 

462 nanMask = ~np.isnan(ptc.finalMeans[ampName]) 

463 means = ptc.finalMeans[ampName][nanMask] 

464 covModel = ptc.covariancesModel[ampName][nanMask] 

465 covariancesModel = ptc.evalPtcModel(means)[ampName] 

466 self.assertFloatsAlmostEqual(covariancesModel, covModel, atol=1e-12) 

467 

468 # And check that this is serializable 

469 with tempfile.NamedTemporaryFile(suffix=".fits") as f: 

470 usedFilename = ptc.writeFits(f.name) 

471 fromFits = PhotonTransferCurveDataset.readFits(usedFilename) 

472 self.assertEqual(fromFits, ptc) 

473 

474 def ptcFitAndCheckPtc( 

475 self, 

476 fitType=None, 

477 doFitBootstrap=False, 

478 ): 

479 localDataset = copy.deepcopy(self.dataset) 

480 localDataset.ptcFitType = fitType 

481 configSolve = copy.copy(self.defaultConfigSolve) 

482 if doFitBootstrap: 

483 configSolve.doFitBootstrap = True 

484 

485 if fitType == "EXPAPPROXIMATION": 

486 g = self.gain 

487 for ampName in self.ampNames: 

488 localDataset.rawVars[ampName] = [ 

489 ( 

490 0.5 / (self.a00 * g**2) * (np.exp(2 * self.a00 * mu * g) - 1) 

491 + self.noiseSq / (g * g) 

492 ) 

493 for mu in localDataset.rawMeans[ampName] 

494 ] 

495 else: 

496 raise RuntimeError( 

497 "Fit type must be 'EXPAPPROXIMATION'" 

498 ) 

499 

500 # Initialize mask and covariance weights that will be used in fits. 

501 # Covariance weights values empirically determined from one of 

502 # the cases in test_covAstier. 

503 matrixSize = localDataset.covMatrixSide 

504 maskLength = len(localDataset.rawMeans[ampName]) 

505 for ampName in self.ampNames: 

506 localDataset.expIdMask[ampName] = np.repeat(True, maskLength) 

507 localDataset.covariancesSqrtWeights[ampName] = np.repeat( 

508 np.ones((matrixSize, matrixSize)), maskLength 

509 ).reshape((maskLength, matrixSize, matrixSize)) 

510 localDataset.covariancesSqrtWeights[ampName][:, 0, 0] = [ 

511 0.07980188, 

512 0.01339653, 

513 0.0073118, 

514 0.00502802, 

515 0.00383132, 

516 0.00309475, 

517 0.00259572, 

518 0.00223528, 

519 0.00196273, 

520 0.00174943, 

521 0.00157794, 

522 0.00143707, 

523 0.00131929, 

524 0.00121935, 

525 0.0011334, 

526 0.00105893, 

527 0.00099357, 

528 0.0009358, 

529 0.00088439, 

530 0.00083833, 

531 ] 

532 

533 solveTask = cpPipe.ptc.PhotonTransferCurveSolveTask(config=configSolve) 

534 

535 if fitType == "EXPAPPROXIMATION": 

536 localDataset = solveTask.fitPtc(localDataset) 

537 else: 

538 localDataset = solveTask.fitDataFullCovariance(localDataset) 

539 

540 # Check entries in localDataset, which was modified by the function 

541 for ampName in self.ampNames: 

542 self.assertEqual(fitType, localDataset.ptcFitType) 

543 self.assertAlmostEqual(self.gain, localDataset.gain[ampName]) 

544 if fitType == "EXPAPPROXIMATION": 

545 self.assertAlmostEqual( 

546 self.a00, localDataset.ptcFitPars[ampName][0] 

547 ) 

548 # Noise already in electrons 

549 self.assertAlmostEqual( 

550 np.sqrt(self.noiseSq), localDataset.noise[ampName] 

551 ) 

552 # If the noise error is greater than the noise, something 

553 # is seriously wrong. Possibly some kind of gain application 

554 # mismatch. 

555 self.assertLess( 

556 localDataset.noiseErr[ampName], 

557 np.sqrt(self.noiseSq) 

558 ) 

559 

560 # Check if evalColModel produces expected values 

561 if not doFitBootstrap: 

562 nanMask = ~np.isnan(localDataset.finalMeans[ampName]) 

563 means = localDataset.finalMeans[ampName][nanMask] 

564 model = localDataset.finalModelVars[ampName][nanMask] 

565 evalVarModel = localDataset.evalPtcModel(means)[ampName] 

566 self.assertFloatsEqual(evalVarModel, model) 

567 

568 def test_lsstcam_samples(self): 

569 for dense in [False, True]: 

570 for mode in ["normal", "upturn", "dip"]: 

571 for doModelPtcRolloff in [False, True]: 

572 rawMeans, rawVars, ptcTurnoff = self._getSampleMeanAndVar(dense=dense, mode=mode) 

573 

574 # We only need a single amp. 

575 ampName = self.ampNames[0] 

576 dataset = PhotonTransferCurveDataset([ampName], ptcFitType="EXPAPPROXIMATION") 

577 dataset.rawExpTimes[ampName] = np.arange(len(rawMeans), dtype=np.float64) + 1.0 

578 dataset.rawMeans[ampName] = rawMeans 

579 dataset.rawVars[ampName] = rawVars 

580 dataset.covariancesSqrtWeights[ampName] = np.repeat( 

581 np.ones((dataset.covMatrixSide, dataset.covMatrixSide)), len(rawMeans) 

582 ).reshape((len(rawMeans), dataset.covMatrixSide, dataset.covMatrixSide)) 

583 dataset.covariancesSqrtWeights[ampName][:, 0, 0] = np.sqrt(rawVars) 

584 mask = np.ones(len(rawMeans), dtype=np.bool_) 

585 mask[~np.isfinite(rawMeans) | ~np.isfinite(rawVars)] = False 

586 dataset.expIdMask[ampName] = mask 

587 

588 configSolve = copy.copy(self.defaultConfigSolve) 

589 configSolve.doModelPtcRolloff = doModelPtcRolloff 

590 configSolve.doFitBootstrap = False 

591 

592 solveTask = cpPipe.ptc.PhotonTransferCurveSolveTask(config=configSolve) 

593 

594 initialFitDataset = solveTask.fitPtc(dataset, computePtcTurnoff=True) 

595 

596 # Model the PTC rolloff 

597 if doModelPtcRolloff: 

598 initialFitDataset = solveTask.fitPtcRolloff(initialFitDataset) 

599 

600 solvedDataset = solveTask.fitPtc(initialFitDataset, computePtcTurnoff=False) 

601 # Check that the ptcTurnoff is what is expected. 

602 self.assertFloatsAlmostEqual( 

603 solvedDataset.ptcTurnoff[ampName], 

604 ptcTurnoff, 

605 msg=( 

606 f"Dense: {dense}; Mode: {mode}, " 

607 f"doModelPtcRolloff: {doModelPtcRolloff}; Amp: {ampName}" 

608 ), 

609 ) 

610 

611 # Check that no values above the 

612 # turnoff/rolloff are "good". 

613 maxMean = solvedDataset.ptcTurnoff[ampName] 

614 if doModelPtcRolloff: 

615 # Check that the PTC rolloff is less 

616 # than the PTC turnoff and within 10% 

617 # of the turnoff. 

618 if dense: 

619 # Check that 

620 self.assertLess( 

621 solvedDataset.ptcRolloff[ampName], 

622 solvedDataset.ptcTurnoff[ampName], 

623 msg=( 

624 f"Dense: {dense}; Mode: {mode}, " 

625 f"doModelPtcRolloff: {doModelPtcRolloff}; " 

626 f"Amp: {ampName}" 

627 ), 

628 ) 

629 self.assertFloatsAlmostEqual( 

630 solvedDataset.ptcRolloff[ampName], 

631 solvedDataset.ptcTurnoff[ampName], 

632 atol=0.1 * solvedDataset.ptcTurnoff[ampName], 

633 msg=( 

634 f"Dense: {dense}; Mode: {mode}, " 

635 f"doModelPtcRolloff: {doModelPtcRolloff}; " 

636 f"Amp: {ampName}" 

637 ), 

638 ) 

639 else: 

640 # In all other cases, it should not be able to 

641 # find points beyond the turnoff, and the 

642 # rolloff should be set to the PTC turnoff. 

643 self.assertEqual( 

644 solvedDataset.ptcRolloff[ampName], 

645 solvedDataset.ptcTurnoff[ampName], 

646 msg=( 

647 f"Dense: {dense}; Mode: {mode}, " 

648 f"doModelPtcRolloff: {doModelPtcRolloff}; " 

649 f"Amp: {ampName}" 

650 ), 

651 ) 

652 

653 # If that passes set the maxMean to the PTC Rolloff 

654 maxMean = solvedDataset.ptcRolloff[ampName] 

655 

656 above = (solvedDataset.finalMeans[ampName] > maxMean) 

657 self.assertEqual( 

658 np.sum(above), 

659 0, 

660 msg=( 

661 f"Dense: {dense}; Mode: {mode}, " 

662 f"doModelPtcRolloff: {doModelPtcRolloff}; Amp: {ampName}" 

663 ), 

664 ) 

665 

666 # Check the sampling error on the turnoff. 

667 turnoffIdx = np.argwhere( 

668 solvedDataset.rawMeans[ampName] == solvedDataset.ptcTurnoff[ampName] 

669 ) 

670 samplingError = (rawMeans[turnoffIdx + 1] - rawMeans[turnoffIdx - 1])/2. 

671 self.assertFloatsAlmostEqual( 

672 solvedDataset.ptcTurnoffSamplingError[ampName], 

673 samplingError, 

674 msg=f"Dense: {dense}; Mode: {mode}", 

675 ) 

676 

677 def test_ptcFit(self): 

678 for fitType in ["EXPAPPROXIMATION"]: 

679 self.ptcFitAndCheckPtc( 

680 fitType=fitType 

681 ) 

682 

683 def test_meanVarMeasurement(self): 

684 task = self.defaultTaskExtract 

685 im1Area, im2Area, imStatsCtrl, mu1, mu2 = task.getImageAreasMasksStats( 

686 self.flatExp1, self.flatExp2 

687 ) 

688 mu, varDiff, _, _ = task.measureMeanVarCov(im1Area, im2Area, imStatsCtrl, mu1, mu2) 

689 

690 self.assertLess(self.flatWidth - np.sqrt(varDiff), 1) 

691 self.assertLess(self.flatMean - mu, 1) 

692 

693 def test_meanVarMeasurementWithNans(self): 

694 task = self.defaultTaskExtract 

695 

696 flatExp1 = self.flatExp1.clone() 

697 flatExp2 = self.flatExp2.clone() 

698 

699 flatExp1.image.array[20:30, :] = np.nan 

700 flatExp2.image.array[20:30, :] = np.nan 

701 

702 im1Area, im2Area, imStatsCtrl, mu1, mu2 = task.getImageAreasMasksStats( 

703 flatExp1, flatExp2 

704 ) 

705 mu, varDiff, _, _ = task.measureMeanVarCov(im1Area, im2Area, imStatsCtrl, mu1, mu2) 

706 

707 expectedMu1 = np.nanmean(flatExp1.image.array) 

708 expectedMu2 = np.nanmean(flatExp2.image.array) 

709 expectedMu = 0.5 * (expectedMu1 + expectedMu2) 

710 

711 # Now the variance of the difference. First, create the diff image. 

712 im1 = flatExp1.maskedImage 

713 im2 = flatExp2.maskedImage 

714 

715 temp = im2.clone() 

716 temp *= expectedMu1 

717 diffIm = im1.clone() 

718 diffIm *= expectedMu2 

719 diffIm -= temp 

720 diffIm /= expectedMu 

721 

722 # Divide by two as it is what measureMeanVarCov returns 

723 # (variance of difference) 

724 expectedVar = 0.5 * np.nanvar(diffIm.image.array) 

725 

726 # Check that the standard deviations and the emans agree to 

727 # less than 1 ADU 

728 self.assertLess(np.sqrt(expectedVar) - np.sqrt(varDiff), 1) 

729 self.assertLess(expectedMu - mu, 1) 

730 

731 def test_meanVarMeasurementAllNan(self): 

732 task = self.defaultTaskExtract 

733 flatExp1 = self.flatExp1.clone() 

734 flatExp2 = self.flatExp2.clone() 

735 

736 flatExp1.image.array[:, :] = np.nan 

737 flatExp2.image.array[:, :] = np.nan 

738 

739 im1Area, im2Area, imStatsCtrl, mu1, mu2 = task.getImageAreasMasksStats( 

740 flatExp1, flatExp2 

741 ) 

742 mu, varDiff, covDiff, rowMeanVariance = task.measureMeanVarCov( 

743 im1Area, im2Area, imStatsCtrl, mu1, mu2 

744 ) 

745 

746 self.assertTrue(np.isnan(mu)) 

747 self.assertTrue(np.isnan(varDiff)) 

748 self.assertTrue(covDiff is None) 

749 self.assertTrue(np.isnan(rowMeanVariance)) 

750 

751 def test_meanVarMeasurementTooFewPixels(self): 

752 task = self.defaultTaskExtract 

753 flatExp1 = self.flatExp1.clone() 

754 flatExp2 = self.flatExp2.clone() 

755 

756 flatExp1.image.array[0:190, :] = np.nan 

757 flatExp2.image.array[0:190, :] = np.nan 

758 

759 bit = flatExp1.mask.getMaskPlaneDict()["NO_DATA"] 

760 flatExp1.mask.array[0:190, :] &= 2**bit 

761 flatExp2.mask.array[0:190, :] &= 2**bit 

762 

763 im1Area, im2Area, imStatsCtrl, mu1, mu2 = task.getImageAreasMasksStats( 

764 flatExp1, flatExp2 

765 ) 

766 with self.assertLogs(level=logging.WARNING) as cm: 

767 mu, varDiff, covDiff, rowMeanVariance = task.measureMeanVarCov( 

768 im1Area, im2Area, imStatsCtrl, mu1, mu2 

769 ) 

770 self.assertIn("Number of good points", cm.output[0]) 

771 

772 self.assertTrue(np.isnan(mu)) 

773 self.assertTrue(np.isnan(varDiff)) 

774 self.assertTrue(covDiff is None) 

775 self.assertTrue(np.isnan(rowMeanVariance)) 

776 

777 def test_meanVarMeasurementTooNarrowStrip(self): 

778 # We need a new config to make sure the second covariance cut is 

779 # triggered. 

780 config = cpPipe.ptc.PhotonTransferCurveExtractTask.ConfigClass() 

781 config.minNumberGoodPixelsForCovariance = 10 

782 task = cpPipe.ptc.PhotonTransferCurveExtractTask(config=config) 

783 flatExp1 = self.flatExp1.clone() 

784 flatExp2 = self.flatExp2.clone() 

785 

786 flatExp1.image.array[0:195, :] = np.nan 

787 flatExp2.image.array[0:195, :] = np.nan 

788 flatExp1.image.array[:, 0:195] = np.nan 

789 flatExp2.image.array[:, 0:195] = np.nan 

790 

791 bit = flatExp1.mask.getMaskPlaneDict()["NO_DATA"] 

792 flatExp1.mask.array[0:195, :] &= 2**bit 

793 flatExp2.mask.array[0:195, :] &= 2**bit 

794 flatExp1.mask.array[:, 0:195] &= 2**bit 

795 flatExp2.mask.array[:, 0:195] &= 2**bit 

796 

797 im1Area, im2Area, imStatsCtrl, mu1, mu2 = task.getImageAreasMasksStats( 

798 flatExp1, flatExp2 

799 ) 

800 with self.assertLogs(level=logging.WARNING) as cm: 

801 mu, varDiff, covDiff, rowMeanVariance = task.measureMeanVarCov( 

802 im1Area, im2Area, imStatsCtrl, mu1, mu2 

803 ) 

804 self.assertIn("Not enough pixels", cm.output[0]) 

805 

806 self.assertTrue(np.isnan(mu)) 

807 self.assertTrue(np.isnan(varDiff)) 

808 self.assertTrue(covDiff is None) 

809 self.assertTrue(np.isnan(rowMeanVariance)) 

810 

811 def test_makeZeroSafe(self): 

812 noZerosArray = [1.0, 20, -35, 45578.98, 90.0, 897, 659.8] 

813 someZerosArray = [1.0, 20, 0, 0, 90, 879, 0] 

814 allZerosArray = [0.0, 0.0, 0, 0, 0.0, 0, 0] 

815 

816 substituteValue = 1e-10 

817 

818 expectedSomeZerosArray = [ 

819 1.0, 

820 20, 

821 substituteValue, 

822 substituteValue, 

823 90, 

824 879, 

825 substituteValue, 

826 ] 

827 expectedAllZerosArray = np.repeat(substituteValue, len(allZerosArray)) 

828 

829 measuredSomeZerosArray = self.defaultTaskSolve._makeZeroSafe( 

830 someZerosArray, substituteValue=substituteValue 

831 ) 

832 measuredAllZerosArray = self.defaultTaskSolve._makeZeroSafe( 

833 allZerosArray, substituteValue=substituteValue 

834 ) 

835 measuredNoZerosArray = self.defaultTaskSolve._makeZeroSafe( 

836 noZerosArray, substituteValue=substituteValue 

837 ) 

838 

839 for exp, meas in zip(expectedSomeZerosArray, measuredSomeZerosArray): 

840 self.assertEqual(exp, meas) 

841 for exp, meas in zip(expectedAllZerosArray, measuredAllZerosArray): 

842 self.assertEqual(exp, meas) 

843 for exp, meas in zip(noZerosArray, measuredNoZerosArray): 

844 self.assertEqual(exp, meas) 

845 

846 def runGetGainFromFlatPair(self, correctionType="NONE"): 

847 extractConfig = self.defaultConfigExtract 

848 extractConfig.gainCorrectionType = correctionType 

849 extractConfig.minNumberGoodPixelsForCovariance = 5000 

850 extractTask = cpPipe.ptc.PhotonTransferCurveExtractTask(config=extractConfig) 

851 

852 expDict = {} 

853 expIds = [] 

854 idCounter = 0 

855 inputGain = self.gain # 1.5 e/ADU 

856 for expTime in self.timeVec: 

857 # Approximation works better at low flux, e.g., < 10000 ADU 

858 mockExp1, mockExp2 = makeMockFlats( 

859 expTime, 

860 gain=inputGain, 

861 readNoiseElectrons=np.sqrt(self.noiseSq), 

862 fluxElectrons=100, 

863 expId1=idCounter, 

864 expId2=idCounter + 1, 

865 ampNames=self.ampNames, 

866 ) 

867 mockExpRef1 = PretendRef(mockExp1) 

868 mockExpRef2 = PretendRef(mockExp2) 

869 expDict[expTime] = ((mockExpRef1, idCounter), (mockExpRef2, idCounter + 1)) 

870 expIds.append(idCounter) 

871 expIds.append(idCounter + 1) 

872 idCounter += 2 

873 

874 # This will test the full extract task. 

875 resultsExtract = extractTask.run( 

876 inputExp=expDict, 

877 inputDims=expIds, 

878 ) 

879 for exposurePair in resultsExtract.outputCovariances: 

880 for ampName in self.ampNames: 

881 if exposurePair.gain[ampName] is np.nan: 

882 continue 

883 self.assertAlmostEqual( 

884 exposurePair.gain[ampName], inputGain, delta=0.04 

885 ) 

886 

887 # Run through the solver and check that the gains from flat pairs 

888 # are recorded in the gainList. 

889 solveConfig = self.defaultConfigSolve 

890 solveConfig.ptcFitType = "EXPAPPROXIMATION" 

891 solveTask = cpPipe.ptc.PhotonTransferCurveSolveTask(config=solveConfig) 

892 

893 resultsSolve = solveTask.run( 

894 resultsExtract.outputCovariances, 

895 camera=FakeCamera([self.flatExp1.getDetector()]), 

896 ) 

897 ptc = resultsSolve.outputPtcDataset 

898 

899 for i in range(len(ptc.inputExpIdPairs)): 

900 for ampName in self.ampNames: 

901 if np.isnan(ptc.gainList[ampName][i]): 

902 continue 

903 self.assertAlmostEqual( 

904 ptc.gainList[ampName][i], inputGain, delta=0.04, 

905 ) 

906 self.assertAlmostEqual( 

907 ptc.noiseList[ampName][i], np.sqrt(self.noiseSq) / self.gain, 

908 ) 

909 

910 def test_getGainFromFlatPair(self): 

911 for gainCorrectionType in [ 

912 "NONE", 

913 "SIMPLE", 

914 "FULL", 

915 ]: 

916 self.runGetGainFromFlatPair(gainCorrectionType) 

917 

918 def test_ptcFitBootstrap(self): 

919 """Test the bootstrap fit option for the PTC""" 

920 for fitType in ['EXPAPPROXIMATION']: 

921 self.ptcFitAndCheckPtc(fitType=fitType, doFitBootstrap=True) 

922 

923 def test_ampOffsetGainRatioFixup(self): 

924 """Test the ampOffsetGainRatioFixup code via 

925 PhotonTransferCurveFixupGainRatiosTask.""" 

926 # TODO DM-52883: Remove tests for deprecated task. 

927 rng = np.random.RandomState(12345) 

928 

929 gainsTruth = rng.normal(loc=1.7, scale=0.05, size=len(self.ampNames)) 

930 gainsMedian = np.median(gainsTruth) 

931 

932 gainsMeasured = rng.normal(loc=gainsTruth, scale=0.02, size=len(self.ampNames)) 

933 

934 # Make one of the measured gains a much larger outlier to ensure 

935 # the code can handle a wacky measurement. 

936 weird_amp_index = 1 

937 gainsMeasured[weird_amp_index] = 1.2 

938 

939 # We have a perfectly flat illuminated detector (in electrons) 

940 nFlat = 20 

941 meansElectron = gainsMedian * np.linspace(500.0, 30000.0, nFlat) 

942 

943 # Set up the fixup task. 

944 with warnings.catch_warnings(): 

945 warnings.simplefilter("ignore") 

946 fixupConfig = cpPipe.ptc.PhotonTransferCurveFixupGainRatiosConfig() 

947 fixupConfig.ampOffsetGainRatioMinAdu = 1000.0 

948 fixupConfig.ampOffsetGainRatioMaxAdu = 20000.0 

949 fixupTask = cpPipe.ptc.PhotonTransferCurveFixupGainRatiosTask(config=fixupConfig) 

950 

951 for testMode in ["full", "badamp"]: 

952 badAmp = None 

953 

954 ptc = PhotonTransferCurveDataset(self.ampNames, ptcFitType="FULLCOVARIANCE") 

955 

956 # Build the PTC to test amp offsets. 

957 for i, ampName in enumerate(self.ampNames): 

958 ptc.gain[ampName] = gainsMeasured[i] 

959 ptc.gainUnadjusted[ampName] = gainsMeasured[i] 

960 

961 if testMode == "badamp" and i == 3: 

962 ptc.gain[ampName] = np.nan 

963 ptc.gainUnadjusted[ampName] = np.nan 

964 badAmp = ampName 

965 

966 # The measured amp means are given by the true gains. 

967 ptc.finalMeans[ampName] = meansElectron / gainsTruth[i] 

968 ptc.expIdMask[ampName] = np.ones(nFlat, dtype=np.bool_) 

969 

970 # Fill the amp offsets temporarily. 

971 ptc.ampOffsets[ampName] = np.zeros(len(meansElectron)) 

972 

973 # Build each toy flat and measure the amp offsets. 

974 config = AmpOffsetTask.ConfigClass() 

975 config.ampEdgeMaxOffset = 100000.0 

976 config.ampEdgeWidth = 16 

977 config.ampEdgeInset = 10 

978 config.doBackground = False 

979 config.doDetection = False 

980 config.doApplyAmpOffset = False 

981 

982 ampOffset = AmpOffsetTask(config=config) 

983 

984 detector = self.flatExp1.getDetector() 

985 metadatas = [] 

986 for i in range(nFlat): 

987 exp = self.flatExp1.clone() 

988 for amp in detector: 

989 amp_name = amp.getName() 

990 exp[amp.getBBox()].image.array[:, :] = ptc.finalMeans[amp_name][i] 

991 md = exp.metadata 

992 

993 md[f"LSST ISR FINAL MEDIAN {amp_name}"] = ptc.finalMeans[amp_name][i] 

994 md[f"LSST ISR FINAL STDEV {amp_name}"] = np.sqrt(ptc.finalMeans[amp_name][i]) 

995 md[f"LSST ISR READNOISE {amp_name}"] = 0.0 

996 

997 ampOffset.run(exp) 

998 metadatas.append(exp.metadata) 

999 

1000 result = fixupTask.run(inputPtc=ptc, exposureMetadata=metadatas) 

1001 ptc = result.outputPtc 

1002 

1003 # Check that the flats are flat after adjustment. 

1004 for i in range(nFlat): 

1005 for j, amp in enumerate(detector): 

1006 gain = ptc.gain[amp.getName()] 

1007 exp[amp.getBBox()].image.array[:, :] = ptc.finalMeans[amp.getName()][i] * gain 

1008 

1009 testImage = exp.image.array / np.nanmedian(exp.image.array) 

1010 if testMode == "badamp": 

1011 # Force the bad values to 1.0 

1012 testImage[~np.isfinite(testImage)] = 1.0 

1013 

1014 self.assertFloatsAlmostEqual(testImage.ravel(), 1.0, rtol=1e-6) 

1015 

1016 # Confirm that the median gain is reasonably unchanged. 

1017 gainsAdjusted = np.array([ptc.gain[ampName] for ampName in self.ampNames]) 

1018 self.assertFloatsAlmostEqual(np.nanmedian(gainsAdjusted), np.nanmedian(gainsMeasured), rtol=0.007) 

1019 

1020 # Confirm that the median of the corrections is 1.0 

1021 gainCorrections = np.array([ptc.gain[ampName]/ptc.gainUnadjusted[ampName] 

1022 for ampName in self.ampNames]) 

1023 self.assertFloatsAlmostEqual(np.nanmedian(gainCorrections), 1.0, rtol=1e-7) 

1024 

1025 # Check that the gain ratios are matched as expected. 

1026 for i, ampName1 in enumerate(self.ampNames): 

1027 for j, ampName2 in enumerate(self.ampNames): 

1028 ratioTruth = gainsTruth[i] / gainsTruth[j] 

1029 ratio = ptc.gain[ampName1] / ptc.gain[ampName2] 

1030 

1031 if ampName1 != badAmp and ampName2 != badAmp: 

1032 self.assertFloatsAlmostEqual(ratio, ratioTruth, rtol=1e-7) 

1033 

1034 # Check that everything is logged correctly when things are very bad. 

1035 for ampName in self.ampNames[2:]: 

1036 ptc.ampOffsets[ampName][:] = np.nan 

1037 

1038 with self.assertLogs(level=logging.WARNING) as cm: 

1039 ampOffsetGainRatioFixup(ptc, 1000.0, 20000.0) 

1040 self.assertIn("Not enough good amp offset measurements", cm.output[0]) 

1041 

1042 for ampName in self.ampNames[1:]: 

1043 ptc.gain[ampName] = np.nan 

1044 

1045 with self.assertLogs(level=logging.WARNING) as cm: 

1046 ampOffsetGainRatioFixup(ptc, 1000.0, 20000.0) 

1047 self.assertIn("Cannot apply ampOffsetGainRatioFixup", cm.output[0]) 

1048 

1049 def test_maskVignetteFunctionRegion(self): 

1050 # The function coefficients are chosen to trigger on some amps. 

1051 # The amps with no masked pixels are C:1,0 and C:1,3 due to the 

1052 # curvature. 

1053 extractConfig = self.defaultConfigExtract 

1054 extractConfig.doVignetteFunctionRegionSelection = True 

1055 extractConfig.vignetteFunctionPolynomialCoeffs = [-100.0, -18.0, 1.0] 

1056 extractConfig.vignetteFunctionRegionSelectionMinimumPixels = 2_000 

1057 

1058 task = cpPipe.ptc.PhotonTransferCurveExtractPairTask(config=extractConfig) 

1059 exposures = [self.flatExp1, self.flatExp2] 

1060 with self.assertNoLogs(level=logging.WARNING): 

1061 task._maskVignetteFunctionRegion(exposures) 

1062 

1063 bitmask = self.flatExp1.mask.getPlaneBitMask("SUSPECT") 

1064 for amp in self.flatExp1.getDetector(): 

1065 bbox = amp.getBBox() 

1066 nMasked = ((self.flatExp1.mask[bbox].array & bitmask) > 0).sum() 

1067 if amp.getName() not in ["C:1,0", "C:1,3"]: 

1068 self.assertGreater(nMasked, 0, msg=f"Missing masked pixels in {amp.getName()}") 

1069 else: 

1070 self.assertEqual(nMasked, 0, msg=f"Unexpected masked pixels in {amp.getName()}") 

1071 

1072 # Check what happens if we ask for too many pixels. 

1073 extractConfig = self.defaultConfigExtract 

1074 extractConfig.doVignetteFunctionRegionSelection = True 

1075 extractConfig.vignetteFunctionPolynomialCoeffs = [-100.0, -18.0, 1.0] 

1076 extractConfig.vignetteFunctionRegionSelectionMinimumPixels = 10_000 

1077 

1078 self.flatExp1.mask.array[:, :] = 0 

1079 self.flatExp2.mask.array[:, :] = 0 

1080 task = cpPipe.ptc.PhotonTransferCurveExtractPairTask(config=extractConfig) 

1081 exposures = [self.flatExp1, self.flatExp2] 

1082 with self.assertLogs(level=logging.WARNING): 

1083 task._maskVignetteFunctionRegion(exposures) 

1084 

1085 # This should not have any masked pixels because we essentially 

1086 # insisted that the full amp be selected. 

1087 for amp in self.flatExp1.getDetector(): 

1088 self.assertEqual(nMasked, 0, msg=f"Unexpected masked pixels in {amp.getName()}") 

1089 

1090 def _getSampleMeanAndVar(self, dense=False, mode="normal"): 

1091 """Get sample mean/var vectors and ptcTurnoff from LSSTCam data. 

1092 

1093 The ptcTurnoff values here were obtained by looking at the data 

1094 and what the code does. These may be changed in the future if 

1095 we decide on a different way of computing the turnoff. 

1096 

1097 Parameters 

1098 ---------- 

1099 dense : `bool`, optional 

1100 Return a dense PTC? 

1101 mode : `str`, optional 

1102 The ptc type, should be "normal", "upturn", or "dip". 

1103 

1104 Returns 

1105 ------- 

1106 rawMeans : `np.ndarray` 

1107 Array of raw mean values. 

1108 rawVars : `np.ndarray` 

1109 Array of raw variance values. 

1110 ptcTurnoff : `float` 

1111 PTC turnoff determined from fitting by eye. 

1112 """ 

1113 if dense and mode == "normal": 

1114 # Taken from dense run 13591, detector 94, amplifier C02 

1115 ptcTurnoff = 92239.4794 

1116 rawMeans = np.array([ 

1117 3.72806883e+01, 3.86850679e+01, 4.09319941e+01, 4.30288886e+01, 

1118 4.59546561e+01, 4.77510985e+01, 5.06130505e+01, 5.35060747e+01, 

1119 5.61016577e+01, 5.95244630e+01, 6.21722799e+01, 6.59958508e+01, 

1120 7.32513785e+01, 7.91695151e+01, 8.19214651e+01, 8.66175502e+01, 

1121 9.06656207e+01, 9.57917501e+01, 1.00925700e+02, 1.07661026e+02, 

1122 1.12211207e+02, 1.18038278e+02, 1.24776787e+02, 1.33127394e+02, 

1123 1.39086972e+02, 1.47962442e+02, 1.55007859e+02, 1.64972119e+02, 

1124 1.72224552e+02, 1.81663660e+02, 1.92083706e+02, 2.01818483e+02, 

1125 2.12893098e+02, 2.25865898e+02, 2.36777769e+02, 2.50805751e+02, 

1126 2.63582968e+02, 2.78848126e+02, 2.93430577e+02, 3.10974538e+02, 

1127 3.28617662e+02, 3.44447122e+02, 3.63779087e+02, 3.85447934e+02, 

1128 4.04865571e+02, 4.26619625e+02, 4.50642349e+02, 4.75572605e+02, 

1129 5.00924590e+02, 5.29463072e+02, 5.56894775e+02, 5.89400667e+02, 

1130 6.22194672e+02, 6.55411968e+02, 6.90233178e+02, 7.28617776e+02, 

1131 7.70386654e+02, 8.11275732e+02, 8.56899058e+02, 9.04075885e+02, 

1132 9.53041280e+02, 1.00428165e+03, 1.05984066e+03, 1.11936964e+03, 

1133 1.17993499e+03, 1.24493657e+03, 1.31333429e+03, 1.38477571e+03, 

1134 1.46288220e+03, 1.54131684e+03, 1.62718454e+03, 1.71685496e+03, 

1135 1.91104434e+03, 1.91128408e+03, 2.01496942e+03, 2.01510504e+03, 

1136 2.12643136e+03, 2.12665024e+03, 2.24351981e+03, 2.36534141e+03, 

1137 2.49658670e+03, 2.77859948e+03, 2.92932915e+03, 3.21897902e+03, 

1138 3.39732732e+03, 3.58413491e+03, 3.78057120e+03, 3.98731229e+03, 

1139 4.20691253e+03, 4.43947873e+03, 4.68353906e+03, 4.94068272e+03, 

1140 5.20957520e+03, 5.21201592e+03, 5.49832249e+03, 5.80143284e+03, 

1141 6.12091976e+03, 6.81333865e+03, 7.18560833e+03, 7.76381518e+03, 

1142 8.33998116e+03, 8.91777512e+03, 9.49514657e+03, 1.00697547e+04, 

1143 1.06495655e+04, 1.12197718e+04, 1.18024551e+04, 1.23803888e+04, 

1144 1.29546730e+04, 1.35302383e+04, 1.41095292e+04, 1.46864242e+04, 

1145 1.52554127e+04, 1.58424382e+04, 1.64174609e+04, 1.69934436e+04, 

1146 1.75654540e+04, 1.81523967e+04, 1.87298339e+04, 1.93014337e+04, 

1147 2.04450305e+04, 2.10377447e+04, 2.16102067e+04, 2.16123196e+04, 

1148 2.21851791e+04, 2.21921696e+04, 2.33433082e+04, 2.39171545e+04, 

1149 2.44958327e+04, 2.50717007e+04, 2.56486425e+04, 2.62185599e+04, 

1150 2.68048566e+04, 2.73814219e+04, 2.79519282e+04, 2.85325879e+04, 

1151 2.91077169e+04, 2.96844973e+04, 3.02554411e+04, 3.14125545e+04, 

1152 3.25683638e+04, 3.31324135e+04, 3.33243063e+04, 3.38868072e+04, 

1153 3.44574798e+04, 3.50295131e+04, 3.55959947e+04, 3.61681182e+04, 

1154 3.67288051e+04, 3.73019527e+04, 3.78659087e+04, 3.84175071e+04, 

1155 3.90035052e+04, 3.95715617e+04, 4.06979100e+04, 4.12778387e+04, 

1156 4.18444142e+04, 4.24067921e+04, 4.29743477e+04, 4.35479754e+04, 

1157 4.41086362e+04, 4.46748906e+04, 4.57912581e+04, 4.63620286e+04, 

1158 4.69293084e+04, 4.80512660e+04, 4.86149041e+04, 4.91798146e+04, 

1159 5.03083769e+04, 5.08678825e+04, 5.14329108e+04, 5.20101245e+04, 

1160 5.25674618e+04, 5.31040686e+04, 5.36908774e+04, 5.42697605e+04, 

1161 5.47843148e+04, 5.53743324e+04, 5.59452125e+04, 5.70753786e+04, 

1162 5.76356662e+04, 5.81990397e+04, 5.87644952e+04, 5.98894309e+04, 

1163 6.04630169e+04, 6.10270338e+04, 6.15960865e+04, 6.21427559e+04, 

1164 6.27197146e+04, 6.32781202e+04, 6.38170695e+04, 6.44264810e+04, 

1165 6.49720024e+04, 6.55524996e+04, 6.66814853e+04, 6.72313467e+04, 

1166 6.78274362e+04, 6.83859289e+04, 6.89427312e+04, 6.95198678e+04, 

1167 7.00847030e+04, 7.06620283e+04, 7.12327432e+04, 7.17769841e+04, 

1168 7.23610736e+04, 7.29237272e+04, 7.34938353e+04, 7.40400864e+04, 

1169 7.46399787e+04, 7.52085787e+04, 7.57175033e+04, 7.63346271e+04, 

1170 7.69141477e+04, 7.74690838e+04, 7.80403707e+04, 7.85672045e+04, 

1171 7.91728742e+04, 7.97519543e+04, 8.03063026e+04, 8.08869068e+04, 

1172 8.14577271e+04, 8.20105730e+04, 8.25824739e+04, 8.31490218e+04, 

1173 8.37308110e+04, 8.42758180e+04, 8.48493221e+04, 8.54126656e+04, 

1174 8.59826959e+04, 8.65501659e+04, 8.70696403e+04, 8.76932979e+04, 

1175 8.82464074e+04, 8.93795020e+04, 8.99537321e+04, 9.05097100e+04, 

1176 9.10881246e+04, 9.22394794e+04, 9.27870984e+04, 9.33315296e+04, 

1177 9.39230922e+04, 9.44926266e+04, 9.56192429e+04, 9.61483057e+04, 

1178 9.72621754e+04, 9.78325850e+04, 9.83972793e+04, 9.89552969e+04, 

1179 9.94332509e+04, 1.00047506e+05, 1.00569417e+05, 1.01105830e+05, 

1180 1.01634936e+05, 1.02121705e+05, 1.02641415e+05, 1.03123767e+05, 

1181 1.03599733e+05, 1.04062370e+05, 1.04907216e+05, 1.05256436e+05, 

1182 1.05665701e+05, 1.06007083e+05, 1.06318115e+05, 1.06593953e+05, 

1183 1.06893542e+05, 1.07121150e+05, 1.07346243e+05, 1.07625934e+05, 

1184 1.08044429e+05, 1.08167080e+05, 1.08308995e+05, 1.08399830e+05, 

1185 1.08526582e+05, 1.08620505e+05, 1.08713803e+05, 1.08784455e+05, 

1186 1.08862350e+05, 1.08937801e+05, 1.08989964e+05, 1.09060085e+05, 

1187 1.09162026e+05, 1.09220593e+05, 1.09273416e+05, 1.09333464e+05, 

1188 1.09372863e+05, 1.09468530e+05, 1.09513735e+05, 1.09553322e+05, 

1189 1.09594566e+05, 1.09641845e+05, 1.09679236e+05, 1.09723860e+05, 

1190 1.09753056e+05, 1.09826579e+05, 1.09872135e+05, 1.09895670e+05, 

1191 1.09902080e+05, 1.09943174e+05, 1.10002465e+05, 1.10019329e+05, 

1192 1.10068730e+05, 1.10095848e+05, 1.10145789e+05, 1.10193658e+05, 

1193 1.10213581e+05, 1.10248075e+05, 1.10291320e+05, 1.10316883e+05, 

1194 1.10358975e+05, 1.10350689e+05, 1.10391552e+05, 1.10400507e+05, 

1195 1.10409523e+05, 1.10409459e+05, 1.10412119e+05, 1.10409689e+05, 

1196 1.10414648e+05, 1.10391061e+05, 1.10420513e+05, 1.10424437e+05, 

1197 1.10435588e+05, 1.10438362e+05, 1.10443905e+05, 1.10450180e+05, 

1198 1.10452714e+05, 1.10449100e+05, 1.10466222e+05, 1.10458324e+05, 

1199 1.10478871e+05, 1.10486620e+05, 1.10485105e+05, 1.10489515e+05, 

1200 1.10491243e+05, 1.10499598e+05, 1.10501449e+05, 1.10501009e+05, 

1201 1.10515083e+05, 1.10533044e+05, 1.10531740e+05, 1.10548636e+05, 

1202 1.10558815e+05, 1.10560570e+05, 1.10569349e+05, 1.10572778e+05, 

1203 1.10588800e+05, 1.10593287e+05, 1.10596037e+05, 1.10584233e+05, 

1204 1.10611084e+05, 1.10616525e+05, 1.10621289e+05, 1.10631455e+05, 

1205 1.10639320e+05, 1.10647906e+05, 1.10646043e+05, 1.10635789e+05, 

1206 1.10635305e+05, 1.10652093e+05, 1.10638755e+05, 1.10655426e+05, 

1207 1.10651182e+05, 1.10653604e+05, 1.10665648e+05, 1.10655049e+05, 

1208 1.10650105e+05, 1.10655658e+05, 1.10660937e+05, 1.10673337e+05, 

1209 1.10673003e+05, 1.10655815e+05, 1.10661151e+05, 1.10662036e+05, 

1210 1.10676951e+05, 1.10667334e+05, 1.10679642e+05, 1.10678497e+05]) 

1211 rawVars = np.array([ 

1212 4.47787277e+01, 4.64353847e+01, 4.85247580e+01, 4.93948408e+01, 

1213 5.15948411e+01, 5.30389406e+01, 5.58813000e+01, 5.88525810e+01, 

1214 6.11585484e+01, 6.41104167e+01, 6.56152371e+01, 6.82093774e+01, 

1215 7.14063291e+01, 7.45066055e+01, 7.64755940e+01, 7.93540481e+01, 

1216 8.18907727e+01, 8.66402959e+01, 8.97887750e+01, 9.68782459e+01, 

1217 9.95221383e+01, 1.02767714e+02, 1.08068716e+02, 1.16108758e+02, 

1218 1.20246097e+02, 1.26018524e+02, 1.30397686e+02, 1.36138570e+02, 

1219 1.41942986e+02, 1.46772865e+02, 1.53919845e+02, 1.60521709e+02, 

1220 1.68353264e+02, 1.78909843e+02, 1.88788533e+02, 2.00792706e+02, 

1221 2.07611019e+02, 2.16057203e+02, 2.26987335e+02, 2.39701806e+02, 

1222 2.51287870e+02, 2.64963149e+02, 2.81918185e+02, 2.93010615e+02, 

1223 3.04772726e+02, 3.21723049e+02, 3.43194608e+02, 3.60791523e+02, 

1224 3.72312673e+02, 3.92534946e+02, 4.18291901e+02, 4.40825475e+02, 

1225 4.58818537e+02, 4.88340078e+02, 5.12852998e+02, 5.35522179e+02, 

1226 5.69935148e+02, 5.92975103e+02, 6.31052929e+02, 6.61056947e+02, 

1227 6.95541286e+02, 7.33787875e+02, 7.74291674e+02, 8.19211863e+02, 

1228 8.62765375e+02, 8.98546352e+02, 9.55344080e+02, 1.00237170e+03, 

1229 1.05926161e+03, 1.10844186e+03, 1.17604012e+03, 1.24027865e+03, 

1230 1.37334609e+03, 1.37631570e+03, 1.44433952e+03, 1.44613237e+03, 

1231 1.53642103e+03, 1.53144123e+03, 1.60103165e+03, 1.69486912e+03, 

1232 1.79228744e+03, 1.97807118e+03, 2.08913779e+03, 2.29127569e+03, 

1233 2.41035376e+03, 2.54559185e+03, 2.68285671e+03, 2.82061302e+03, 

1234 2.98565936e+03, 3.13680879e+03, 3.29910967e+03, 3.48157975e+03, 

1235 3.66147828e+03, 3.67694292e+03, 3.84787540e+03, 4.07925681e+03, 

1236 4.28699288e+03, 4.75578456e+03, 5.00956756e+03, 5.39321737e+03, 

1237 5.79686635e+03, 6.17477624e+03, 6.55132737e+03, 6.93000705e+03, 

1238 7.31757235e+03, 7.68650298e+03, 8.05377657e+03, 8.42789583e+03, 

1239 8.77475510e+03, 9.17341164e+03, 9.54927300e+03, 9.89596158e+03, 

1240 1.02637150e+04, 1.06167914e+04, 1.09873368e+04, 1.13685550e+04, 

1241 1.17026479e+04, 1.20765605e+04, 1.23946750e+04, 1.27577017e+04, 

1242 1.34485509e+04, 1.37927193e+04, 1.42006355e+04, 1.41857628e+04, 

1243 1.44769908e+04, 1.45162172e+04, 1.51614067e+04, 1.55571196e+04, 

1244 1.58809609e+04, 1.61752079e+04, 1.65104318e+04, 1.68369000e+04, 

1245 1.71408213e+04, 1.75355600e+04, 1.78226398e+04, 1.81932474e+04, 

1246 1.84482292e+04, 1.88389901e+04, 1.91150651e+04, 1.97375210e+04, 

1247 2.03591057e+04, 2.07155451e+04, 2.07138350e+04, 2.11073361e+04, 

1248 2.13837002e+04, 2.16588926e+04, 2.19612146e+04, 2.22753789e+04, 

1249 2.25303517e+04, 2.27928117e+04, 2.31125410e+04, 2.33679689e+04, 

1250 2.37393625e+04, 2.40488975e+04, 2.45764011e+04, 2.48064050e+04, 

1251 2.50721617e+04, 2.53965873e+04, 2.56131331e+04, 2.59277943e+04, 

1252 2.61709392e+04, 2.64119896e+04, 2.68955682e+04, 2.72267063e+04, 

1253 2.74887295e+04, 2.79083033e+04, 2.82310485e+04, 2.84366770e+04, 

1254 2.90226269e+04, 2.92324828e+04, 2.94521967e+04, 2.97949458e+04, 

1255 2.99735234e+04, 3.02749574e+04, 3.05427850e+04, 3.07518546e+04, 

1256 3.09317879e+04, 3.12692332e+04, 3.15643550e+04, 3.21293639e+04, 

1257 3.24007437e+04, 3.26147619e+04, 3.28979579e+04, 3.34807881e+04, 

1258 3.37109710e+04, 3.40246283e+04, 3.43898469e+04, 3.45302267e+04, 

1259 3.47818944e+04, 3.51593681e+04, 3.52477656e+04, 3.56490287e+04, 

1260 3.59240161e+04, 3.61669226e+04, 3.66423677e+04, 3.68827117e+04, 

1261 3.71622239e+04, 3.74768274e+04, 3.76872328e+04, 3.79405515e+04, 

1262 3.81364527e+04, 3.84119822e+04, 3.86423009e+04, 3.88877574e+04, 

1263 3.91248488e+04, 3.92990610e+04, 3.96215459e+04, 3.98297091e+04, 

1264 4.00712366e+04, 4.04322148e+04, 4.05178037e+04, 4.07431736e+04, 

1265 4.10193223e+04, 4.11740695e+04, 4.13790755e+04, 4.14632263e+04, 

1266 4.18525778e+04, 4.20979322e+04, 4.23130642e+04, 4.24582022e+04, 

1267 4.24946930e+04, 4.27860167e+04, 4.30933820e+04, 4.32894483e+04, 

1268 4.33858206e+04, 4.34411628e+04, 4.36629531e+04, 4.39919091e+04, 

1269 4.40293360e+04, 4.42002784e+04, 4.42310862e+04, 4.45443328e+04, 

1270 4.45481958e+04, 4.48604145e+04, 4.48891948e+04, 4.48416001e+04, 

1271 4.50553039e+04, 4.50927543e+04, 4.51136486e+04, 4.51126520e+04, 

1272 4.49857031e+04, 4.48705631e+04, 4.46276191e+04, 4.43327388e+04, 

1273 4.37938194e+04, 4.32211550e+04, 4.27332194e+04, 4.23177306e+04, 

1274 4.14539982e+04, 4.06974694e+04, 3.96551098e+04, 3.82440396e+04, 

1275 3.67165456e+04, 3.47661502e+04, 3.28393493e+04, 3.02395522e+04, 

1276 2.76939927e+04, 2.48272541e+04, 1.92526286e+04, 1.63986811e+04, 

1277 1.42095886e+04, 1.22350406e+04, 1.06293553e+04, 9.24838723e+03, 

1278 8.09429377e+03, 7.27582028e+03, 6.47441127e+03, 5.21985266e+03, 

1279 4.36279092e+03, 4.00953782e+03, 3.69585190e+03, 3.43405611e+03, 

1280 3.18567804e+03, 3.01195379e+03, 2.89123841e+03, 2.68282359e+03, 

1281 2.60091022e+03, 2.51301062e+03, 2.43890788e+03, 2.35838231e+03, 

1282 2.26256855e+03, 2.21204078e+03, 2.20282902e+03, 2.18205860e+03, 

1283 2.15007675e+03, 2.08949483e+03, 2.10732780e+03, 2.09600072e+03, 

1284 2.07407783e+03, 2.11741997e+03, 2.08083045e+03, 2.06397688e+03, 

1285 2.04765529e+03, 2.05836012e+03, 2.04093663e+03, 1.98334647e+03, 

1286 2.01999612e+03, 1.99394914e+03, 1.96972450e+03, 1.88216817e+03, 

1287 1.86902307e+03, 1.98290800e+03, 1.94714119e+03, 1.92046621e+03, 

1288 1.83796316e+03, 1.87468459e+03, 1.89491779e+03, 1.83110571e+03, 

1289 1.75025929e+03, 1.66067524e+03, 1.68052010e+03, 1.67404206e+03, 

1290 1.65221787e+03, 1.63380745e+03, 1.61258211e+03, 1.57173282e+03, 

1291 1.55635385e+03, 1.59914440e+03, 1.63280915e+03, 1.62416209e+03, 

1292 1.55550327e+03, 1.59790786e+03, 1.63913552e+03, 1.62123248e+03, 

1293 1.59571147e+03, 1.48508783e+03, 1.60763833e+03, 1.60573267e+03, 

1294 1.66286509e+03, 1.56023986e+03, 1.60226461e+03, 1.62178972e+03, 

1295 1.63248481e+03, 1.63982132e+03, 1.67350316e+03, 1.62120745e+03, 

1296 1.69261497e+03, 1.67835970e+03, 1.71259617e+03, 1.66567572e+03, 

1297 1.73107044e+03, 1.60808418e+03, 1.62957233e+03, 1.65949976e+03, 

1298 1.62773379e+03, 1.74438786e+03, 1.61948665e+03, 1.83335873e+03, 

1299 1.65774501e+03, 1.65605436e+03, 1.72054542e+03, 1.68968657e+03, 

1300 1.73787963e+03, 1.74437326e+03, 1.71408015e+03, 1.93871967e+03, 

1301 1.87508731e+03, 1.70631906e+03, 1.92219749e+03, 1.72410949e+03, 

1302 1.86172638e+03, 1.88692937e+03, 1.77337717e+03, 1.95303579e+03, 

1303 1.86292107e+03, 1.87948406e+03, 1.91966097e+03, 1.76238101e+03, 

1304 1.59694869e+03, 1.89306746e+03, 1.84068186e+03, 1.86018512e+03, 

1305 1.81578862e+03, 1.83413719e+03, 1.80771751e+03, 1.79214601e+03]) 

1306 elif dense and mode == "upturn": 

1307 # Taken from dense run 13591, detector 73, amplifier C07 

1308 ptcTurnoff = 86917.0045 

1309 rawMeans = np.array([ 

1310 2.87448603e+01, 3.03861239e+01, 3.20301466e+01, 3.35831624e+01, 

1311 3.51161960e+01, 3.69857753e+01, 3.91580507e+01, 4.12179225e+01, 

1312 4.36662086e+01, 4.58399375e+01, 4.80202775e+01, 5.10071275e+01, 

1313 5.68263968e+01, 5.99352524e+01, 6.34210182e+01, 6.68834309e+01, 

1314 7.01195882e+01, 7.43313750e+01, 7.80758357e+01, 8.27309929e+01, 

1315 8.73124933e+01, 9.17856382e+01, 9.70086101e+01, 1.02546128e+02, 

1316 1.08169091e+02, 1.13738150e+02, 1.20058621e+02, 1.26792703e+02, 

1317 1.33422104e+02, 1.40893068e+02, 1.48727555e+02, 1.56662520e+02, 

1318 1.65129261e+02, 1.74130948e+02, 1.83878223e+02, 1.93976598e+02, 

1319 2.04599993e+02, 2.16044601e+02, 2.27838642e+02, 2.40360862e+02, 

1320 2.53772624e+02, 2.67443055e+02, 2.82013487e+02, 2.97705423e+02, 

1321 3.14297001e+02, 3.31260825e+02, 3.49758342e+02, 3.68963998e+02, 

1322 3.88634613e+02, 4.10112249e+02, 4.32301833e+02, 4.56407219e+02, 

1323 4.81690100e+02, 5.08370293e+02, 5.35921852e+02, 5.65828928e+02, 

1324 5.96685398e+02, 6.29615188e+02, 6.64802708e+02, 7.00563142e+02, 

1325 7.39711995e+02, 7.79679559e+02, 8.22530629e+02, 8.67814522e+02, 

1326 9.15951880e+02, 9.65946953e+02, 1.01948611e+03, 1.07504268e+03, 

1327 1.13509200e+03, 1.19727942e+03, 1.26351949e+03, 1.33211624e+03, 

1328 1.48320209e+03, 1.48384430e+03, 1.56467822e+03, 1.56485206e+03, 

1329 1.65060918e+03, 1.65147654e+03, 1.74229201e+03, 1.83706229e+03, 

1330 1.93811946e+03, 2.15719262e+03, 2.27546155e+03, 2.50056748e+03, 

1331 2.63872700e+03, 2.78379012e+03, 2.93745238e+03, 3.09833186e+03, 

1332 3.27013288e+03, 3.44990418e+03, 3.63968250e+03, 3.83921968e+03, 

1333 4.04711266e+03, 4.05013387e+03, 4.27266981e+03, 4.50809670e+03, 

1334 4.75635569e+03, 5.29310771e+03, 5.58427306e+03, 6.03306708e+03, 

1335 6.48160541e+03, 6.92983470e+03, 7.37874615e+03, 7.82619855e+03, 

1336 8.27493037e+03, 8.72049208e+03, 9.17227788e+03, 9.62234260e+03, 

1337 1.00674503e+04, 1.05166951e+04, 1.09652006e+04, 1.14145457e+04, 

1338 1.18581337e+04, 1.23138210e+04, 1.27597933e+04, 1.32094995e+04, 

1339 1.36537794e+04, 1.41079990e+04, 1.45579666e+04, 1.50042564e+04, 

1340 1.58932106e+04, 1.63527856e+04, 1.67995854e+04, 1.68014549e+04, 

1341 1.72456751e+04, 1.72511595e+04, 1.81472850e+04, 1.85967925e+04, 

1342 1.90437339e+04, 1.94933795e+04, 1.99423590e+04, 2.03854630e+04, 

1343 2.08408610e+04, 2.12909264e+04, 2.17356857e+04, 2.21873924e+04, 

1344 2.26346682e+04, 2.30822802e+04, 2.35248689e+04, 2.44292445e+04, 

1345 2.53306721e+04, 2.57709779e+04, 2.59292740e+04, 2.63672474e+04, 

1346 2.68118979e+04, 2.72586202e+04, 2.76977437e+04, 2.81455545e+04, 

1347 2.85840092e+04, 2.90309073e+04, 2.94738200e+04, 2.99007273e+04, 

1348 3.03581316e+04, 3.08035397e+04, 3.16820715e+04, 3.21348581e+04, 

1349 3.25795035e+04, 3.30160938e+04, 3.34614077e+04, 3.39098464e+04, 

1350 3.43488841e+04, 3.47938018e+04, 3.56683528e+04, 3.61120617e+04, 

1351 3.65571740e+04, 3.74373798e+04, 3.78795706e+04, 3.83213509e+04, 

1352 3.92106205e+04, 3.96436191e+04, 4.00888939e+04, 4.05395713e+04, 

1353 4.09729696e+04, 4.13953138e+04, 4.18558141e+04, 4.23098575e+04, 

1354 4.27184098e+04, 4.31754813e+04, 4.36191519e+04, 4.45068672e+04, 

1355 4.49463419e+04, 4.53858299e+04, 4.58261673e+04, 4.67014085e+04, 

1356 4.71515103e+04, 4.75882657e+04, 4.80322253e+04, 4.84586953e+04, 

1357 4.89039488e+04, 4.93442503e+04, 4.97561230e+04, 5.02341725e+04, 

1358 5.06588581e+04, 5.11035621e+04, 5.19836216e+04, 5.24056394e+04, 

1359 5.28686518e+04, 5.33018757e+04, 5.37265598e+04, 5.41807663e+04, 

1360 5.46136176e+04, 5.50609130e+04, 5.55007300e+04, 5.59337737e+04, 

1361 5.63788843e+04, 5.68094757e+04, 5.72570533e+04, 5.76741866e+04, 

1362 5.81383020e+04, 5.85826153e+04, 5.89753856e+04, 5.94617576e+04, 

1363 5.99083532e+04, 6.03419978e+04, 6.07815876e+04, 6.11916990e+04, 

1364 6.16679074e+04, 6.21070006e+04, 6.25498996e+04, 6.30000329e+04, 

1365 6.34432415e+04, 6.38632967e+04, 6.43145751e+04, 6.47608638e+04, 

1366 6.52134266e+04, 6.56348895e+04, 6.60841662e+04, 6.65220989e+04, 

1367 6.69687269e+04, 6.74171257e+04, 6.78295038e+04, 6.83037417e+04, 

1368 6.87381890e+04, 6.96234966e+04, 7.00749883e+04, 7.05130803e+04, 

1369 7.09702156e+04, 7.18669367e+04, 7.23008238e+04, 7.27326728e+04, 

1370 7.31879639e+04, 7.36444652e+04, 7.45313822e+04, 7.49512933e+04, 

1371 7.58422569e+04, 7.63002282e+04, 7.67542279e+04, 7.71971910e+04, 

1372 7.75899806e+04, 7.80880043e+04, 7.85207688e+04, 7.89717058e+04, 

1373 7.94257076e+04, 7.98485141e+04, 8.03023282e+04, 8.07414358e+04, 

1374 8.11910981e+04, 8.16398955e+04, 8.25250712e+04, 8.29401845e+04, 

1375 8.34236581e+04, 8.38641888e+04, 8.42971844e+04, 8.47295006e+04, 

1376 8.52114910e+04, 8.56328503e+04, 8.60862279e+04, 8.69170045e+04, 

1377 8.78165034e+04, 8.82689547e+04, 8.87058177e+04, 8.90804208e+04, 

1378 8.95362169e+04, 8.99496410e+04, 9.03236457e+04, 9.06958198e+04, 

1379 9.11193888e+04, 9.14557890e+04, 9.17189073e+04, 9.21437093e+04, 

1380 9.28449356e+04, 9.31434208e+04, 9.33064667e+04, 9.34994900e+04, 

1381 9.37926812e+04, 9.41725477e+04, 9.45383949e+04, 9.46575696e+04, 

1382 9.49209096e+04, 9.49952393e+04, 9.50539106e+04, 9.52347786e+04, 

1383 9.52460768e+04, 9.54989344e+04, 9.56298553e+04, 9.58490767e+04, 

1384 9.62648021e+04, 9.61075892e+04, 9.63538129e+04, 9.63559508e+04, 

1385 9.64708846e+04, 9.64756350e+04, 9.66256538e+04, 9.64809810e+04, 

1386 9.65366387e+04, 9.68214859e+04, 9.69137722e+04, 9.68210311e+04, 

1387 9.71873201e+04, 9.71342102e+04, 9.71078451e+04, 9.71069892e+04, 

1388 9.75296912e+04, 9.74999383e+04, 9.73480623e+04, 9.76524037e+04, 

1389 9.74981803e+04, 9.76922174e+04, 9.76337785e+04, 9.75835125e+04, 

1390 9.75674694e+04, 9.75367570e+04, 9.77438281e+04, 9.76871410e+04, 

1391 9.78773702e+04, 9.78321613e+04, 9.77808877e+04, 9.77359422e+04, 

1392 9.79278808e+04, 9.79329075e+04, 9.77675254e+04, 9.78952318e+04, 

1393 9.77270368e+04, 9.79509533e+04, 9.77760093e+04, 9.80460286e+04, 

1394 9.81360499e+04, 9.79637125e+04, 9.79664967e+04, 9.78575509e+04, 

1395 9.80556911e+04, 9.81417648e+04, 9.80352945e+04, 9.81329700e+04, 

1396 9.81188437e+04, 9.79678779e+04, 9.79598626e+04, 9.80560275e+04, 

1397 9.79542087e+04, 9.79987939e+04, 9.81534114e+04, 9.83899105e+04, 

1398 9.84065000e+04, 9.82811922e+04, 9.82840840e+04, 9.82784134e+04, 

1399 9.82871998e+04, 9.84461381e+04, 9.84682635e+04, 9.85020571e+04, 

1400 np.nan, np.nan, np.nan, np.nan, 

1401 np.nan, np.nan, np.nan, np.nan, 

1402 np.nan, np.nan, np.nan, np.nan, 

1403 np.nan, np.nan, np.nan, np.nan]) 

1404 rawVars = np.array([ 

1405 4.87069525e+01, 4.96960311e+01, 5.04910053e+01, 5.17128726e+01, 

1406 5.25955479e+01, 5.38353690e+01, 5.53191132e+01, 5.66941478e+01, 

1407 5.82926522e+01, 5.98938552e+01, 6.12951161e+01, 6.37287578e+01, 

1408 6.80636332e+01, 7.04028909e+01, 7.29998462e+01, 7.48586667e+01, 

1409 7.66622012e+01, 7.82391455e+01, 7.99899592e+01, 8.21891213e+01, 

1410 8.44852817e+01, 8.74729321e+01, 9.05085253e+01, 9.45153523e+01, 

1411 9.84325033e+01, 1.02490363e+02, 1.05547104e+02, 1.08782968e+02, 

1412 1.12593458e+02, 1.17458820e+02, 1.22086446e+02, 1.27863525e+02, 

1413 1.34404768e+02, 1.42189276e+02, 1.48361964e+02, 1.52241417e+02, 

1414 1.56903695e+02, 1.63487388e+02, 1.71250175e+02, 1.79776726e+02, 

1415 1.87500190e+02, 1.95127335e+02, 2.05237738e+02, 2.17941739e+02, 

1416 2.27601893e+02, 2.34445474e+02, 2.46136553e+02, 2.58638437e+02, 

1417 2.70612240e+02, 2.88057360e+02, 3.01436607e+02, 3.11174829e+02, 

1418 3.27060261e+02, 3.47777215e+02, 3.68419809e+02, 3.80518820e+02, 

1419 3.97377177e+02, 4.25381795e+02, 4.42049448e+02, 4.59452324e+02, 

1420 4.92530031e+02, 5.14495733e+02, 5.34196108e+02, 5.72228281e+02, 

1421 5.92914611e+02, 6.29229419e+02, 6.63254402e+02, 7.10047069e+02, 

1422 7.31110299e+02, 7.74635732e+02, 8.06624321e+02, 8.55180585e+02, 

1423 9.44435441e+02, 9.43183163e+02, 1.00413513e+03, 9.99872981e+02, 

1424 1.05311443e+03, 1.05562621e+03, 1.10199374e+03, 1.15531802e+03, 

1425 1.22522414e+03, 1.36520090e+03, 1.42667128e+03, 1.56495960e+03, 

1426 1.65397576e+03, 1.74424087e+03, 1.84231293e+03, 1.94740328e+03, 

1427 2.03765806e+03, 2.14414450e+03, 2.27212692e+03, 2.38935653e+03, 

1428 2.50602833e+03, 2.51661588e+03, 2.64775661e+03, 2.78538088e+03, 

1429 2.93987651e+03, 3.26826498e+03, 3.44330599e+03, 3.69978469e+03, 

1430 3.97061173e+03, 4.24728849e+03, 4.50971380e+03, 4.77595875e+03, 

1431 5.05755732e+03, 5.30327839e+03, 5.58773282e+03, 5.81966058e+03, 

1432 6.10932503e+03, 6.36332817e+03, 6.61863136e+03, 6.90433479e+03, 

1433 7.13413117e+03, 7.43562156e+03, 7.66582807e+03, 7.94754672e+03, 

1434 8.18686206e+03, 8.45779399e+03, 8.71402609e+03, 8.95964156e+03, 

1435 9.47591061e+03, 9.76959463e+03, 9.95917651e+03, 9.97584309e+03, 

1436 1.02555717e+04, 1.02417814e+04, 1.07674493e+04, 1.09981921e+04, 

1437 1.12352859e+04, 1.15551940e+04, 1.17333125e+04, 1.19690736e+04, 

1438 1.22534101e+04, 1.24640828e+04, 1.27500496e+04, 1.29625045e+04, 

1439 1.32703257e+04, 1.34926746e+04, 1.37251524e+04, 1.42302648e+04, 

1440 1.46793658e+04, 1.49722647e+04, 1.49709034e+04, 1.52549107e+04, 

1441 1.55088982e+04, 1.57314736e+04, 1.59816003e+04, 1.61640169e+04, 

1442 1.64548981e+04, 1.66413940e+04, 1.68686050e+04, 1.71125336e+04, 

1443 1.73511674e+04, 1.75817535e+04, 1.80470011e+04, 1.82624491e+04, 

1444 1.84524739e+04, 1.87019552e+04, 1.89575762e+04, 1.91930866e+04, 

1445 1.94004074e+04, 1.96460005e+04, 2.00479314e+04, 2.02955099e+04, 

1446 2.04822881e+04, 2.09531956e+04, 2.11697303e+04, 2.13633602e+04, 

1447 2.18346507e+04, 2.19539919e+04, 2.22252821e+04, 2.25155821e+04, 

1448 2.26702123e+04, 2.28414558e+04, 2.30830649e+04, 2.32726468e+04, 

1449 2.34988786e+04, 2.37395021e+04, 2.39101878e+04, 2.43317884e+04, 

1450 2.45771060e+04, 2.47054420e+04, 2.49622825e+04, 2.52797662e+04, 

1451 2.55292494e+04, 2.57138336e+04, 2.59366428e+04, 2.61122036e+04, 

1452 2.63896695e+04, 2.64562386e+04, 2.66907602e+04, 2.69102279e+04, 

1453 2.71833821e+04, 2.73303887e+04, 2.77661838e+04, 2.79006930e+04, 

1454 2.81874904e+04, 2.83607526e+04, 2.86045106e+04, 2.87425416e+04, 

1455 2.89632711e+04, 2.91293885e+04, 2.93514145e+04, 2.96850582e+04, 

1456 2.98715928e+04, 3.01274873e+04, 3.03033141e+04, 3.04572121e+04, 

1457 3.07470469e+04, 3.10501508e+04, 3.11450218e+04, 3.14122871e+04, 

1458 3.16022955e+04, 3.18325755e+04, 3.21339141e+04, 3.23047828e+04, 

1459 3.24219992e+04, 3.28022196e+04, 3.30193533e+04, 3.32907509e+04, 

1460 3.34017470e+04, 3.36009585e+04, 3.39733107e+04, 3.40535547e+04, 

1461 3.42458795e+04, 3.44664410e+04, 3.47643491e+04, 3.50165080e+04, 

1462 3.51727941e+04, 3.53854796e+04, 3.55711407e+04, 3.58190707e+04, 

1463 3.60454029e+04, 3.63969548e+04, 3.66329292e+04, 3.68771986e+04, 

1464 3.71032547e+04, 3.73983989e+04, 3.76425541e+04, 3.79247481e+04, 

1465 3.80882104e+04, 3.82317170e+04, 3.86471187e+04, 3.89086176e+04, 

1466 3.92339037e+04, 3.95436246e+04, 3.96460919e+04, 3.98028414e+04, 

1467 3.99125771e+04, 4.01715067e+04, 4.03722901e+04, 4.05626968e+04, 

1468 4.06933838e+04, 4.10184964e+04, 4.11922744e+04, 4.13557454e+04, 

1469 4.16157584e+04, 4.16356931e+04, 4.21157583e+04, 4.21816345e+04, 

1470 4.24543184e+04, 4.26313857e+04, 4.27797954e+04, 4.29586701e+04, 

1471 4.31317246e+04, 4.31196229e+04, 4.30508028e+04, 4.29439940e+04, 

1472 4.14814510e+04, 4.17104998e+04, 4.12950588e+04, 4.00762620e+04, 

1473 3.95745952e+04, 3.79603760e+04, 3.68764412e+04, 3.59324071e+04, 

1474 3.41774826e+04, 3.35146378e+04, 3.01416949e+04, 3.10962443e+04, 

1475 2.93723225e+04, 2.88267934e+04, 2.93057515e+04, 2.78885387e+04, 

1476 2.97481790e+04, 2.89003096e+04, 2.98475325e+04, 3.15227067e+04, 

1477 3.15157345e+04, 3.32593077e+04, 3.30733852e+04, 3.37623662e+04, 

1478 3.58784503e+04, 3.75160267e+04, 3.82803313e+04, 3.89001912e+04, 

1479 4.17283047e+04, 4.20086699e+04, 4.22993774e+04, 4.34867653e+04, 

1480 4.17054368e+04, 4.52190044e+04, 4.55586401e+04, 4.39034690e+04, 

1481 4.49939183e+04, 4.75700720e+04, 4.78978238e+04, 4.62120749e+04, 

1482 4.85317658e+04, 4.97305999e+04, 4.70691830e+04, 4.77667215e+04, 

1483 5.19257836e+04, 5.01885056e+04, 4.83671721e+04, 5.21924342e+04, 

1484 5.10329762e+04, 5.25552111e+04, 5.17040972e+04, 5.11958488e+04, 

1485 5.19165668e+04, 4.88842210e+04, 5.17286013e+04, 5.13182361e+04, 

1486 5.16342048e+04, 5.17850241e+04, 5.16475818e+04, 5.00165868e+04, 

1487 5.19391672e+04, 5.21771011e+04, 5.01633917e+04, 5.19270231e+04, 

1488 4.93839429e+04, 4.96516804e+04, 4.93706114e+04, 5.25025570e+04, 

1489 5.43045043e+04, 5.27477605e+04, 5.23609667e+04, 4.89296194e+04, 

1490 5.26232764e+04, 5.24395882e+04, 4.90790820e+04, 5.19268918e+04, 

1491 5.21608822e+04, 4.89292620e+04, 4.86074588e+04, 4.93274381e+04, 

1492 4.84901815e+04, 4.91868029e+04, 5.25082453e+04, 5.44279458e+04, 

1493 5.55797293e+04, 5.20003094e+04, 5.19304424e+04, 5.17391458e+04, 

1494 5.24042964e+04, 5.53566164e+04, 5.53202737e+04, 5.58931187e+04, 

1495 np.nan, np.nan, np.nan, np.nan, 

1496 np.nan, np.nan, np.nan, np.nan, 

1497 np.nan, np.nan, np.nan, np.nan, 

1498 np.nan, np.nan, np.nan, np.nan]) 

1499 elif dense and mode == "dip": 

1500 # Taken from dense run 13591, detector 46, amplifier C16 

1501 ptcTurnoff = 78592.643 

1502 rawMeans = np.array( 

1503 [3.46319253e+01, 3.66430301e+01, 3.86622690e+01, 4.05725802e+01, 

1504 4.25802432e+01, 4.40269809e+01, 4.80275071e+01, 5.05005628e+01, 

1505 5.24638704e+01, 5.51726716e+01, 5.80431294e+01, 6.18363693e+01, 

1506 6.76872491e+01, 7.54744430e+01, 7.59445874e+01, 8.07200670e+01, 

1507 8.39801977e+01, 8.89822266e+01, 9.34165914e+01, 1.00259640e+02, 

1508 1.04115753e+02, 1.09746401e+02, 1.16495426e+02, 1.24702365e+02, 

1509 1.29617918e+02, 1.38517235e+02, 1.44598282e+02, 1.55474182e+02, 

1510 1.60372893e+02, 1.68952583e+02, 1.79169853e+02, 1.87803850e+02, 

1511 1.97901901e+02, 2.12236200e+02, 2.20703858e+02, 2.33721460e+02, 

1512 2.45632287e+02, 2.60078861e+02, 2.73309812e+02, 2.91303550e+02, 

1513 3.08138900e+02, 3.20634527e+02, 3.39157572e+02, 3.61285287e+02, 

1514 3.77306857e+02, 3.97532592e+02, 4.19725123e+02, 4.42637799e+02, 

1515 4.66432222e+02, 4.92760774e+02, 5.18439719e+02, 5.49043359e+02, 

1516 5.80725784e+02, 6.10607872e+02, 6.42130865e+02, 6.78015970e+02, 

1517 7.19634201e+02, 7.56125967e+02, 7.97647549e+02, 8.44250515e+02, 

1518 8.88164221e+02, 9.35554605e+02, 9.87551014e+02, 1.04304478e+03, 

1519 1.09859274e+03, 1.15934514e+03, 1.22290957e+03, 1.28928061e+03, 

1520 1.36205339e+03, 1.43517932e+03, 1.51527821e+03, 1.59829513e+03, 

1521 1.77964089e+03, 1.78170273e+03, 1.87682761e+03, 1.87684189e+03, 

1522 1.98075997e+03, 1.98113130e+03, 2.08945214e+03, 2.20305152e+03, 

1523 2.32556464e+03, 2.58962409e+03, 2.72814882e+03, 2.99794092e+03, 

1524 3.16447505e+03, 3.33946592e+03, 3.52147949e+03, 3.71394579e+03, 

1525 3.91907040e+03, 4.13438382e+03, 4.36189594e+03, 4.60043753e+03, 

1526 4.85130253e+03, 4.85473652e+03, 5.12061926e+03, 5.40324180e+03, 

1527 5.70061253e+03, 6.34723550e+03, 6.69436828e+03, 7.23257375e+03, 

1528 7.76958269e+03, 8.30697359e+03, 8.84549436e+03, 9.38149894e+03, 

1529 9.92214412e+03, 1.04540863e+04, 1.09984280e+04, 1.15336125e+04, 

1530 1.20730516e+04, 1.26066598e+04, 1.31475457e+04, 1.36835704e+04, 

1531 1.42142220e+04, 1.47607783e+04, 1.52995772e+04, 1.58349683e+04, 

1532 1.63699779e+04, 1.69169118e+04, 1.74527183e+04, 1.79882677e+04, 

1533 1.90590055e+04, 1.96042099e+04, 2.01412931e+04, 2.01415525e+04, 

1534 2.06773002e+04, 2.06836599e+04, 2.17563308e+04, 2.22945949e+04, 

1535 2.28326494e+04, 2.33730224e+04, 2.39083711e+04, 2.44415981e+04, 

1536 2.49887745e+04, 2.55254849e+04, 2.60582748e+04, 2.66026296e+04, 

1537 2.71388848e+04, 2.76745959e+04, 2.82098429e+04, 2.92893984e+04, 

1538 3.03685478e+04, 3.08997866e+04, 3.10729575e+04, 3.16013527e+04, 

1539 3.21337166e+04, 3.26668783e+04, 3.31930745e+04, 3.37295906e+04, 

1540 3.42575950e+04, 3.47930111e+04, 3.53194913e+04, 3.58360666e+04, 

1541 3.63796428e+04, 3.69119003e+04, 3.79618999e+04, 3.85046991e+04, 

1542 3.90341729e+04, 3.95622456e+04, 4.00906725e+04, 4.06248524e+04, 

1543 4.11506714e+04, 4.16820728e+04, 4.27281690e+04, 4.32583738e+04, 

1544 4.37923105e+04, 4.48436280e+04, 4.53713042e+04, 4.58983070e+04, 

1545 4.69589412e+04, 4.74759399e+04, 4.80036320e+04, 4.85414573e+04, 

1546 4.90619668e+04, 4.95708602e+04, 5.01124419e+04, 5.06550432e+04, 

1547 5.11459970e+04, 5.16864720e+04, 5.22155963e+04, 5.32732837e+04, 

1548 5.37950395e+04, 5.43202717e+04, 5.48449050e+04, 5.58936896e+04, 

1549 5.64268047e+04, 5.69454503e+04, 5.74788533e+04, 5.79886165e+04, 

1550 5.85227316e+04, 5.90467563e+04, 5.95529633e+04, 6.01107425e+04, 

1551 6.06190504e+04, 6.11482815e+04, 6.22041090e+04, 6.27192672e+04, 

1552 6.32698650e+04, 6.37882800e+04, 6.43035282e+04, 6.48401842e+04, 

1553 6.53646656e+04, 6.59030142e+04, 6.64333556e+04, 6.69479267e+04, 

1554 6.74848468e+04, 6.80079972e+04, 6.85445388e+04, 6.90509171e+04, 

1555 6.96092229e+04, 7.01385610e+04, 7.06212128e+04, 7.11939523e+04, 

1556 7.17266360e+04, 7.22471223e+04, 7.27780652e+04, 7.32761803e+04, 

1557 7.38361226e+04, 7.43656998e+04, 7.48934046e+04, 7.54352821e+04, 

1558 7.59644966e+04, 7.64724502e+04, 7.70119423e+04, 7.75439221e+04, 

1559 7.80842181e+04, 7.85926430e+04, 7.91251970e+04, 7.96491204e+04, 

1560 8.01869810e+04, 8.07146073e+04, 8.12202954e+04, 8.17785695e+04, 

1561 8.22963087e+04, 8.33550384e+04, 8.38994212e+04, 8.44155447e+04, 

1562 8.49563789e+04, 8.60281829e+04, 8.65433251e+04, 8.70627645e+04, 

1563 8.76007341e+04, 8.81511125e+04, 8.92018550e+04, 8.97044207e+04, 

1564 9.07592037e+04, 9.13032564e+04, 9.18479184e+04, 9.23763279e+04, 

1565 9.28541040e+04, 9.34276276e+04, 9.39508203e+04, 9.44807722e+04, 

1566 9.50201270e+04, 9.55260238e+04, 9.60584060e+04, 9.65900977e+04, 

1567 9.71082260e+04, 9.76499634e+04, 9.86927409e+04, 9.92001749e+04, 

1568 9.97605950e+04, 1.00281826e+05, 1.00799323e+05, 1.01317520e+05, 

1569 1.01880214e+05, 1.02375482e+05, 1.02921781e+05, 1.03914664e+05, 

1570 1.04996919e+05, 1.05531177e+05, 1.06045662e+05, 1.06553960e+05, 

1571 1.07074502e+05, 1.07620081e+05, 1.08135030e+05, 1.08625699e+05, 

1572 1.09176443e+05, 1.09713812e+05, 1.10216327e+05, 1.10733831e+05, 

1573 1.11710810e+05, 1.12193799e+05, 1.12690561e+05, 1.13133767e+05, 

1574 1.13607554e+05, 1.14479014e+05, 1.14907269e+05, 1.15294108e+05, 

1575 1.15680838e+05, 1.16050756e+05, 1.16395663e+05, 1.16738698e+05, 

1576 1.17036744e+05, 1.17606634e+05, 1.17864854e+05, 1.18107937e+05, 

1577 1.18338933e+05, 1.18484492e+05, 1.18751107e+05, 1.18925783e+05, 

1578 1.19127596e+05, 1.19257553e+05, 1.19452513e+05, 1.19608706e+05, 

1579 1.19753398e+05, 1.19883813e+05, 1.20021670e+05, 1.20155507e+05, 

1580 1.20406612e+05, 1.20605600e+05, 1.20753078e+05, 1.20866466e+05, 

1581 np.nan, np.nan, np.nan, np.nan, 

1582 np.nan, np.nan, np.nan, np.nan, 

1583 np.nan, np.nan, np.nan, np.nan, 

1584 np.nan, np.nan, np.nan, np.nan, 

1585 np.nan, np.nan, np.nan, np.nan, 

1586 np.nan, np.nan, np.nan, np.nan, 

1587 np.nan, np.nan, np.nan, np.nan, 

1588 np.nan, np.nan, np.nan, np.nan, 

1589 np.nan, np.nan, np.nan, np.nan, 

1590 np.nan, np.nan, np.nan, np.nan, 

1591 np.nan, np.nan, np.nan, np.nan, 

1592 np.nan, np.nan, np.nan, np.nan, 

1593 np.nan, np.nan, np.nan, np.nan, 

1594 np.nan, np.nan, np.nan, np.nan, 

1595 np.nan, np.nan, np.nan, np.nan, 

1596 np.nan, np.nan, np.nan, np.nan]) 

1597 rawVars = np.array( 

1598 [3.70611558e+01, 3.83737395e+01, 3.99468861e+01, 4.10014338e+01, 

1599 4.23251266e+01, 4.33678155e+01, 4.59071461e+01, 4.73626968e+01, 

1600 4.87148063e+01, 5.03835098e+01, 5.25225011e+01, 5.49763960e+01, 

1601 5.89144406e+01, 6.46901096e+01, 6.46921274e+01, 6.77000641e+01, 

1602 7.03062675e+01, 7.37864491e+01, 7.78022510e+01, 8.44978037e+01, 

1603 8.74723267e+01, 9.13765683e+01, 9.51046462e+01, 9.90038919e+01, 

1604 1.01309767e+02, 1.06498820e+02, 1.10600587e+02, 1.18170347e+02, 

1605 1.21408878e+02, 1.28214192e+02, 1.36647653e+02, 1.42148979e+02, 

1606 1.48491678e+02, 1.59805162e+02, 1.65823057e+02, 1.73305507e+02, 

1607 1.80522937e+02, 1.87449934e+02, 1.96245721e+02, 2.08352732e+02, 

1608 2.21201432e+02, 2.32523118e+02, 2.44009905e+02, 2.56991468e+02, 

1609 2.68047397e+02, 2.79329180e+02, 2.97712914e+02, 3.15304298e+02, 

1610 3.27789122e+02, 3.44980267e+02, 3.61446379e+02, 3.84494985e+02, 

1611 4.05677044e+02, 4.22749240e+02, 4.44709272e+02, 4.77813761e+02, 

1612 5.01815280e+02, 5.21252820e+02, 5.49793847e+02, 5.80608964e+02, 

1613 6.10172377e+02, 6.44282320e+02, 6.76618722e+02, 7.14200019e+02, 

1614 7.52150585e+02, 7.90093939e+02, 8.43584018e+02, 8.74257958e+02, 

1615 9.25137165e+02, 9.77217130e+02, 1.02268591e+03, 1.07911844e+03, 

1616 1.20579007e+03, 1.21094193e+03, 1.26536689e+03, 1.26783114e+03, 

1617 1.33667935e+03, 1.34071853e+03, 1.40959965e+03, 1.49236868e+03, 

1618 1.56214455e+03, 1.73911080e+03, 1.84452009e+03, 2.01282493e+03, 

1619 2.11914383e+03, 2.23859893e+03, 2.35101284e+03, 2.48665441e+03, 

1620 2.61201878e+03, 2.74350197e+03, 2.89732268e+03, 3.05252644e+03, 

1621 3.22199981e+03, 3.22767156e+03, 3.38954315e+03, 3.58149621e+03, 

1622 3.76614023e+03, 4.19955412e+03, 4.39939398e+03, 4.74116692e+03, 

1623 5.08774295e+03, 5.43362489e+03, 5.76587686e+03, 6.09147076e+03, 

1624 6.46434875e+03, 6.77118428e+03, 7.10758829e+03, 7.41292668e+03, 

1625 7.75391200e+03, 8.07133480e+03, 8.40331959e+03, 8.71723040e+03, 

1626 9.03873483e+03, 9.36871022e+03, 9.69206829e+03, 9.99510413e+03, 

1627 1.03183250e+04, 1.06519986e+04, 1.09717629e+04, 1.12984284e+04, 

1628 1.19017371e+04, 1.22009054e+04, 1.25073348e+04, 1.24828917e+04, 

1629 1.28123892e+04, 1.27965364e+04, 1.34024560e+04, 1.36798307e+04, 

1630 1.40186807e+04, 1.43485421e+04, 1.45916270e+04, 1.48802247e+04, 

1631 1.51990105e+04, 1.54775801e+04, 1.57746393e+04, 1.60211115e+04, 

1632 1.63459546e+04, 1.66499888e+04, 1.68983125e+04, 1.74427484e+04, 

1633 1.80456894e+04, 1.82652348e+04, 1.83690177e+04, 1.86208031e+04, 

1634 1.89412363e+04, 1.91602864e+04, 1.94785697e+04, 1.97091334e+04, 

1635 1.99827654e+04, 2.02492520e+04, 2.04397095e+04, 2.07912874e+04, 

1636 2.09363768e+04, 2.12446667e+04, 2.17637411e+04, 2.19817593e+04, 

1637 2.22395694e+04, 2.24653630e+04, 2.27254307e+04, 2.29678916e+04, 

1638 2.32155716e+04, 2.34915971e+04, 2.39308788e+04, 2.41386350e+04, 

1639 2.43300723e+04, 2.47776731e+04, 2.49855450e+04, 2.52822560e+04, 

1640 2.57310565e+04, 2.58705668e+04, 2.61365827e+04, 2.63745002e+04, 

1641 2.64761919e+04, 2.67763879e+04, 2.69546269e+04, 2.72247330e+04, 

1642 2.73854794e+04, 2.75964799e+04, 2.78536768e+04, 2.83219440e+04, 

1643 2.84473603e+04, 2.86066766e+04, 2.88858064e+04, 2.93640042e+04, 

1644 2.95802005e+04, 2.97953000e+04, 2.99784114e+04, 3.01818213e+04, 

1645 3.04537120e+04, 3.07186903e+04, 3.09159639e+04, 3.11340544e+04, 

1646 3.13467981e+04, 3.16593731e+04, 3.19829978e+04, 3.22855092e+04, 

1647 3.25921574e+04, 3.27154499e+04, 3.28698071e+04, 3.31481419e+04, 

1648 3.34606399e+04, 3.37260080e+04, 3.38331508e+04, 3.40882291e+04, 

1649 3.43298166e+04, 3.44626343e+04, 3.47352389e+04, 3.48844453e+04, 

1650 3.50976243e+04, 3.53422532e+04, 3.54703155e+04, 3.57850397e+04, 

1651 3.60218788e+04, 3.61282209e+04, 3.63718905e+04, 3.64159312e+04, 

1652 3.67264583e+04, 3.68810487e+04, 3.70236104e+04, 3.73025531e+04, 

1653 3.74696213e+04, 3.74774745e+04, 3.76885954e+04, 3.77461428e+04, 

1654 3.77311980e+04, 3.76449769e+04, 3.71874494e+04, 3.67403027e+04, 

1655 3.58397731e+04, 3.44249565e+04, 3.25971681e+04, 3.12036933e+04, 

1656 2.94985871e+04, 2.71719366e+04, 2.69809068e+04, 2.72483125e+04, 

1657 2.83267080e+04, 3.15350383e+04, 3.33307911e+04, 3.48927220e+04, 

1658 3.65827728e+04, 3.79316518e+04, 3.97114600e+04, 4.02038182e+04, 

1659 4.10252529e+04, 4.14747301e+04, 4.16607368e+04, 4.18321712e+04, 

1660 4.18311337e+04, 4.21298732e+04, 4.21384783e+04, 4.21559876e+04, 

1661 4.23156351e+04, 4.22011377e+04, 4.22592203e+04, 4.20913479e+04, 

1662 4.15029042e+04, 4.09470822e+04, 3.85767751e+04, 3.64665853e+04, 

1663 3.45138148e+04, 3.21709915e+04, 2.96629755e+04, 2.69203438e+04, 

1664 2.43537600e+04, 2.23428644e+04, 2.01581545e+04, 1.62544599e+04, 

1665 1.34824506e+04, 1.18721963e+04, 1.05452615e+04, 9.46843007e+03, 

1666 8.23841467e+03, 7.23997272e+03, 6.36586857e+03, 5.65708162e+03, 

1667 4.99963764e+03, 4.48251363e+03, 4.09078951e+03, 3.72817220e+03, 

1668 3.21067198e+03, 3.03262162e+03, 2.89743032e+03, 2.77343484e+03, 

1669 2.69667301e+03, 2.60188277e+03, 2.55172731e+03, 2.52540578e+03, 

1670 2.56130915e+03, 2.52293303e+03, 2.50717444e+03, 2.51044664e+03, 

1671 2.51531215e+03, 2.53768779e+03, 2.56201926e+03, 2.56217908e+03, 

1672 2.60528686e+03, 2.61531849e+03, 2.62971142e+03, 2.66896083e+03, 

1673 2.69706371e+03, 2.73927492e+03, 2.74999442e+03, 2.75180096e+03, 

1674 2.78694836e+03, 2.80704605e+03, 2.83222240e+03, 2.86654398e+03, 

1675 2.90678852e+03, 2.95139745e+03, 2.95942911e+03, 3.00791154e+03, 

1676 np.nan, np.nan, np.nan, np.nan, 

1677 np.nan, np.nan, np.nan, np.nan, 

1678 np.nan, np.nan, np.nan, np.nan, 

1679 np.nan, np.nan, np.nan, np.nan, 

1680 np.nan, np.nan, np.nan, np.nan, 

1681 np.nan, np.nan, np.nan, np.nan, 

1682 np.nan, np.nan, np.nan, np.nan, 

1683 np.nan, np.nan, np.nan, np.nan, 

1684 np.nan, np.nan, np.nan, np.nan, 

1685 np.nan, np.nan, np.nan, np.nan, 

1686 np.nan, np.nan, np.nan, np.nan, 

1687 np.nan, np.nan, np.nan, np.nan, 

1688 np.nan, np.nan, np.nan, np.nan, 

1689 np.nan, np.nan, np.nan, np.nan, 

1690 np.nan, np.nan, np.nan, np.nan, 

1691 np.nan, np.nan, np.nan, np.nan]) 

1692 elif not dense and mode == "normal": 

1693 # Taken from B protocol run 13557, detector 94, amplifier C02 

1694 ptcTurnoff = 92173.9596 

1695 rawMeans = np.array([ 

1696 7.35242203e+01, 9.29532799e+01, 1.12149391e+02, 1.39776279e+02, 

1697 1.74220020e+02, 2.15692281e+02, 2.68814926e+02, 3.34446868e+02, 

1698 4.14359931e+02, 5.14691775e+02, 6.40642848e+02, 7.95596873e+02, 

1699 9.90753280e+02, 1.22885224e+03, 1.52684706e+03, 1.89907469e+03, 

1700 2.35701770e+03, 2.93106806e+03, 3.59466174e+03, 4.46720318e+03, 

1701 5.55232373e+03, 6.90091293e+03, 8.57660238e+03, 1.06583769e+04, 

1702 1.32457052e+04, 1.64618675e+04, 2.04605037e+04, 2.54301936e+04, 

1703 3.15926481e+04, 3.87784321e+04, 4.81318315e+04, 5.97145570e+04, 

1704 7.41859291e+04, 9.21739596e+04, 1.08484387e+05, 1.10456942e+05, 

1705 1.10677645e+05, 1.10691134e+05, 1.10693202e+05, 1.10692292e+05, 

1706 1.10699619e+05, 1.10703407e+05, 1.10704764e+05]) 

1707 rawVars = np.array([ 

1708 71.66098099, 85.85187266, 100.07444552, 121.59045422, 

1709 143.54998243, 171.39262057, 210.51220342, 257.40796789, 

1710 313.11677494, 381.91333248, 476.46542075, 583.72632638, 

1711 729.26397749, 888.46194891, 1101.58606157, 1363.39263745, 

1712 1686.28916615, 2096.14920835, 2552.12897667, 3159.70329711, 

1713 3894.29254595, 4800.37079501, 5940.17760433, 7310.2253724, 

1714 9015.14374818, 11022.81586492, 13509.18049715, 16391.89059679, 

1715 19905.15871788, 23628.84875886, 28128.21785629, 33476.91933085, 

1716 40023.07406229, 45198.48421179, 3390.76561947, 1601.38678043, 

1717 1890.12715102, 1805.34862035, 1904.84156084, 1903.84859699, 

1718 1857.15885789, 1889.45649514, 1892.01672711]) 

1719 elif not dense and mode == "upturn": 

1720 # Taken from B protocol run 13557, detector 73, amplifier C07 

1721 ptcTurnoff = 71832.2986 

1722 rawMeans = np.array([ 

1723 5.65607783e+01, 7.04062631e+01, 8.74047057e+01, 1.08812996e+02, 

1724 1.35333046e+02, 1.67636667e+02, 2.08445200e+02, 2.59202618e+02, 

1725 3.21602277e+02, 3.99545078e+02, 4.96963648e+02, 6.17791959e+02, 

1726 7.67578708e+02, 9.54040040e+02, 1.18587264e+03, 1.47297327e+03, 

1727 1.83109922e+03, 2.27527491e+03, 2.79309339e+03, 3.47193365e+03, 

1728 4.31520802e+03, 5.36244611e+03, 6.66482002e+03, 8.28357528e+03, 

1729 1.02962387e+04, 1.27972565e+04, 1.59069356e+04, 1.97746199e+04, 

1730 2.45737678e+04, 3.01873089e+04, 3.75075197e+04, 4.65677579e+04, 

1731 5.77977537e+04, 7.18322986e+04, 8.92553708e+04, 9.74408608e+04, 

1732 np.nan, np.nan, np.nan, np.nan, 

1733 np.nan, np.nan, np.nan]) 

1734 rawVars = np.array([ 

1735 68.2700079, 76.51661413, 84.52771312, 98.70960506, 

1736 113.95644441, 137.2544902, 158.39159813, 190.7985178, 

1737 229.92447148, 279.52534113, 338.90663196, 414.97072284, 

1738 510.16012626, 622.00951125, 763.81268011, 938.07098006, 

1739 1149.75983481, 1424.88125193, 1745.36382679, 2165.89927287, 

1740 2666.43505016, 3303.63407541, 4094.4066631, 5072.7831761, 

1741 6238.35971003, 7697.01580574, 9479.41363292, 11654.65158713, 

1742 14268.54471588, 17316.88016853, 21012.8242229, 25275.74644538, 

1743 30725.05799423, 37363.24467221, 39830.3337401, 48083.26241611, 

1744 np.nan, np.nan, np.nan, np.nan, 

1745 np.nan, np.nan, np.nan]) 

1746 elif not dense and mode == "dip": 

1747 # Taken from B protocol run 13557, detector 46, amplifier C16 

1748 ptcTurnoff = 87557.8289 

1749 rawMeans = np.array( 

1750 [6.94187281e+01, 8.92438988e+01, 1.05958756e+02, 1.32423251e+02, 

1751 1.64877564e+02, 2.04367731e+02, 2.55076247e+02, 3.16940500e+02, 

1752 3.92525299e+02, 4.87631833e+02, 6.06783494e+02, 7.53540982e+02, 

1753 9.39742534e+02, 1.16367754e+03, 1.44670172e+03, 1.80047945e+03, 

1754 2.23357272e+03, 2.77872101e+03, 3.40646845e+03, 4.23306945e+03, 

1755 5.26085005e+03, 6.53969254e+03, 8.12914423e+03, 1.01016373e+04, 

1756 1.25546410e+04, 1.56072062e+04, 1.93987924e+04, 2.41153677e+04, 

1757 2.99669024e+04, 3.67956267e+04, 4.56879445e+04, 5.66901053e+04, 

1758 7.04360489e+04, 8.75578289e+04, 1.08738204e+05, np.nan, 

1759 np.nan, np.nan, np.nan, np.nan, 

1760 np.nan, np.nan, np.nan]) 

1761 rawVars = np.array( 

1762 [61.7553328, 75.60175792, 88.98931208, 106.95977, 

1763 129.78637495, 153.5130247, 192.25182776, 233.4904232, 

1764 287.02595043, 349.57554198, 428.71515892, 528.0987701, 

1765 656.97011401, 820.88213784, 1003.62289116, 1243.67283887, 

1766 1543.24210179, 1905.00050382, 2321.63329694, 2889.08652787, 

1767 3574.52610263, 4393.02299998, 5427.50087472, 6691.62708604, 

1768 8226.42941205, 10104.75767742, 12365.56291744, 15029.66357377, 

1769 18233.5785582, 21684.66746226, 25811.97832361, 30686.30643311, 

1770 36834.73747467, 41993.20346722, 30079.64884394, np.nan, 

1771 np.nan, np.nan, np.nan, np.nan, 

1772 np.nan, np.nan, np.nan]) 

1773 else: 

1774 raise RuntimeError("Illegal mode") 

1775 

1776 return rawMeans, rawVars, ptcTurnoff 

1777 

1778 

1779class MeasurePhotonTransferCurveDatasetTestCase(lsst.utils.tests.TestCase): 

1780 def setUp(self): 

1781 self.ptcData = PhotonTransferCurveDataset(["C00", "C01"], " ") 

1782 self.ptcData.inputExpIdPairs = { 

1783 "C00": [(123, 234), (345, 456), (567, 678)], 

1784 "C01": [(123, 234), (345, 456), (567, 678)], 

1785 } 

1786 

1787 def test_generalBehaviour(self): 

1788 test = PhotonTransferCurveDataset(["C00", "C01"], " ") 

1789 test.inputExpIdPairs = { 

1790 "C00": [(123, 234), (345, 456), (567, 678)], 

1791 "C01": [(123, 234), (345, 456), (567, 678)], 

1792 } 

1793 

1794 

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

1796 pass 

1797 

1798 

1799def setup_module(module): 

1800 lsst.utils.tests.init() 

1801 

1802 

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

1804 lsst.utils.tests.init() 

1805 unittest.main()