Coverage for tests/test_ptc.py: 6%
565 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-13 02:26 -0800
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-13 02:26 -0800
1#!/usr/bin/env python
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."""
27import unittest
28import numpy as np
29import copy
30import tempfile
31import logging
33import lsst.log
34import lsst.utils
35import lsst.utils.tests
37import lsst.cp.pipe as cpPipe
38import lsst.ip.isr.isrMock as isrMock
39from lsst.ip.isr import PhotonTransferCurveDataset, PhotodiodeCalib, AmpOffsetTask
40from lsst.cp.pipe.utils import makeMockFlats, ampOffsetGainRatioFixup
42from lsst.pipe.base import InMemoryDatasetHandle
45class FakeCamera(list):
46 def getName(self):
47 return "FakeCam"
50class PretendRef:
51 "A class to act as a mock exposure reference"
53 def __init__(self, exposure):
54 self.exp = exposure
56 def get(self, component=None):
57 if component == "visitInfo":
58 return self.exp.info.getVisitInfo()
59 elif component == "detector":
60 return self.exp.getDetector()
61 elif component == "metadata":
62 return self.exp.getMetadata()
63 else:
64 return self.exp
67class MeasurePhotonTransferCurveTaskTestCase(lsst.utils.tests.TestCase):
68 """A test case for the PTC tasks."""
70 def setUp(self):
71 self.defaultConfigExtract = (
72 cpPipe.ptc.PhotonTransferCurveExtractPairTask.ConfigClass()
73 )
74 self.defaultTaskExtract = cpPipe.ptc.PhotonTransferCurveExtractTask(
75 config=self.defaultConfigExtract
76 )
78 self.defaultConfigSolve = cpPipe.ptc.PhotonTransferCurveSolveTask.ConfigClass()
79 self.defaultTaskSolve = cpPipe.ptc.PhotonTransferCurveSolveTask(
80 config=self.defaultConfigSolve
81 )
83 self.flatMean = 2000
84 self.readNoiseAdu = 10
85 mockImageConfig = isrMock.IsrMock.ConfigClass()
87 # flatDrop is not really relevant as we replace the data
88 # but good to note it in case we change how this image is made
89 mockImageConfig.flatDrop = 0.99999
90 mockImageConfig.isTrimmed = True
92 self.flatExp1 = isrMock.FlatMock(config=mockImageConfig).run()
93 self.flatExp2 = self.flatExp1.clone()
94 (shapeY, shapeX) = self.flatExp1.getDimensions()
96 self.flatWidth = np.sqrt(self.flatMean) + self.readNoiseAdu
98 self.rng1 = np.random.RandomState(1984)
99 flatData1 = self.rng1.normal(self.flatMean, self.flatWidth, (shapeX, shapeY))
100 self.rng2 = np.random.RandomState(666)
101 flatData2 = self.rng2.normal(self.flatMean, self.flatWidth, (shapeX, shapeY))
103 self.flatExp1.image.array[:] = flatData1
104 self.flatExp2.image.array[:] = flatData2
106 # create fake PTC data to see if fit works, for one amp ('amp')
107 self.flux = 1000.0 # ADU/sec
108 self.timeVec = np.arange(1.0, 101.0, 5)
109 self.k2NonLinearity = -5e-6
110 # quadratic signal-chain non-linearity
111 muVec = self.flux * self.timeVec + self.k2NonLinearity * self.timeVec**2
112 self.gain = 0.75 # e-/ADU
113 self.c1 = 1.0 / self.gain
114 self.noiseSq = 2 * self.gain # 7.5 (e-)^2
115 self.a00 = -1.2e-6
116 self.c2 = -1.5e-6
117 self.c3 = -4.7e-12 # tuned so that it turns over for 200k mean
118 self.photoCharges = np.linspace(1e-8, 1e-5, len(self.timeVec))
120 self.ampNames = [
121 amp.getName() for amp in self.flatExp1.getDetector().getAmplifiers()
122 ]
123 self.dataset = PhotonTransferCurveDataset(self.ampNames, ptcFitType="PARTIAL")
124 self.covariancesSqrtWeights = {}
125 for (
126 ampName
127 ) in self.ampNames: # just the expTimes and means here - vars vary per function
128 self.dataset.rawExpTimes[ampName] = self.timeVec
129 self.dataset.rawMeans[ampName] = muVec
130 self.dataset.covariancesSqrtWeights[ampName] = np.zeros(
131 (1, self.dataset.covMatrixSide, self.dataset.covMatrixSide)
132 )
134 def test_covAstier(self):
135 """Test to check getCovariancesAstier
137 We check that the gain is the same as the input gain from the
138 mock data, that the covariances via FFT (as it is in
139 MeasurePhotonTransferCurveTask when doCovariancesAstier=True)
140 are the same as calculated in real space, and that Cov[0, 0]
141 (i.e., the variances) are similar to the variances calculated
142 with the standard method (when doCovariancesAstier=false),
144 """
145 extractConfig = self.defaultConfigExtract
146 extractConfig.minNumberGoodPixelsForCovariance = 5000
147 extractConfig.detectorMeasurementRegion = "FULL"
148 extractConfig.doExtractPhotodiodeData = True
149 extractConfig.doKsHistMeasurement = True
150 extractConfig.auxiliaryHeaderKeys = ["CCOBCURR", "CCDTEMP"]
151 extractPairTask = cpPipe.ptc.PhotonTransferCurveExtractPairTask(config=extractConfig)
153 # Create solve task config
154 solveConfig = self.defaultConfigSolve
155 # Cut off the low-flux point which is a bad fit, and this
156 # also exercises this functionality and makes the tests
157 # run a lot faster.
158 solveConfig.minMeanSignal["ALL_AMPS"] = 2000.0
159 # Set the outlier fit threshold higher than the default appropriate
160 # for this test dataset.
161 solveConfig.maxSignalInitialPtcOutlierFit = 90000.0
162 # Given the limited nature of the test data, we can only
163 # reliably fit out to a 3x3 covariance matrix.
164 # Improvements will be investigated on DM-46131.
165 solveConfig.maximumRangeCovariancesAstierFullCovFit = 3
167 inputGain = self.gain
169 muStandard, varStandard = {}, {}
170 nPixelCovarianceStandard = {}
171 expHandles = []
172 expIds = []
173 pdHandles = []
174 idCounter = 0
175 for i, expTime in enumerate(self.timeVec):
176 mockExp1, mockExp2 = makeMockFlats(
177 expTime,
178 gain=inputGain,
179 readNoiseElectrons=3,
180 expId1=idCounter,
181 expId2=idCounter + 1,
182 ampNames=self.ampNames,
183 )
184 for mockExp in [mockExp1, mockExp2]:
185 md = mockExp.getMetadata()
186 # These values are chosen to be easily compared after
187 # processing for correct ordering.
188 md['CCOBCURR'] = float(idCounter)
189 md['CCDTEMP'] = float(idCounter + 1)
190 mockExp.setMetadata(md)
191 md['SEQFILE'] = 'a_seqfile'
192 md['SEQNAME'] = 'a_seqfile'
193 md['SEQCKSUM'] = 'deadbeef'
195 mockExpRef1 = PretendRef(mockExp1)
196 mockExpRef2 = PretendRef(mockExp2)
197 expHandles.extend((mockExpRef1, mockExpRef2))
198 expIds.append(idCounter)
199 expIds.append(idCounter + 1)
200 maskValue = mockExp1.mask.getPlaneBitMask(extractPairTask.config.maskNameList)
201 for ampNumber, ampName in enumerate(self.ampNames):
202 # cov has (i, j, var, cov, npix)
203 (
204 im1Area,
205 im2Area,
206 imStatsCtrl,
207 mu1,
208 mu2,
209 ) = extractPairTask.getImageAreasMasksStats(mockExp1, mockExp2)
210 nPixelCovariance = ((im1Area.mask.array & maskValue) == 0).sum()
211 nPixelCovarianceStandard.setdefault(ampName, []).append(nPixelCovariance)
212 muDiff, varDiff, covAstier, rowMeanVariance = extractPairTask.measureMeanVarCov(
213 im1Area, im2Area, imStatsCtrl, mu1, mu2
214 )
215 muStandard.setdefault(ampName, []).append(muDiff)
216 varStandard.setdefault(ampName, []).append(varDiff)
218 # Make a photodiode dataset to integrate.
219 timeSamples = np.linspace(0, 20.0, 100)
220 currentSamples1 = np.zeros(100)
221 currentSamples1[50] = -1.0*self.photoCharges[i]
222 currentSamples2 = np.zeros(100)
223 currentSamples2[50] = -1.0*(self.photoCharges[i] + 1e-12)
225 pdCalib1 = PhotodiodeCalib(timeSamples=timeSamples, currentSamples=currentSamples1)
226 pdCalib1.currentScale = -1.0
227 pdCalib1.integrationMethod = "CHARGE_SUM"
229 pdCalib2 = PhotodiodeCalib(timeSamples=timeSamples, currentSamples=currentSamples2)
230 pdCalib2.currentScale = -1.0
231 pdCalib2.integrationMethod = "CHARGE_SUM"
233 pdHandles.append(
234 InMemoryDatasetHandle(
235 pdCalib1,
236 dataId={"exposure": idCounter},
237 )
238 )
239 pdHandles.append(
240 InMemoryDatasetHandle(
241 pdCalib2,
242 dataId={"exposure": idCounter + 1},
243 )
244 )
245 idCounter += 2
247 # Divide out the pairs.
248 outputCovariances = []
249 for i in range(len(expHandles) // 2):
250 inputExp = [expHandles[2*i], expHandles[2*i + 1]]
251 inputDims = [expIds[2*i], expIds[2*i + 1]]
252 inputPhotodiodeData = [pdHandles[2*i], pdHandles[2*i + 1]]
253 results = extractPairTask.run(
254 inputExp=inputExp,
255 inputDims=inputDims,
256 inputPhotodiodeData=inputPhotodiodeData,
257 )
258 outputCovariances.append(results.outputCovariance)
260 # Force the last PTC dataset to have a NaN, and ensure that the
261 # task runs (DM-38029). This is a minor perturbation and does not
262 # affect the output comparison.
263 outputCovariances[-1].rawMeans["C:0,0"] = np.array([np.nan])
264 outputCovariances[-1].rawVars["C:0,0"] = np.array([np.nan])
266 # Force the next-to-last PTC dataset to have a decreased variance to
267 # ensure that the outlier fit rejection works.
268 rawVar = outputCovariances[-2].rawVars["C:0,0"]
269 outputCovariances[-2].rawVars["C:0,0"] = rawVar * 0.9
271 # Reorganize the outputCovariances so we can confirm they come
272 # out sorted afterwards.
273 outputCovariancesRev = outputCovariances[::-1]
275 # Some expected values for noise matrix, just to check that
276 # it was calculated.
277 expectedNoiseMatrix = {
278 "FULLCOVARIANCE": np.array(
279 [[8.99474598, 9.94916264, -27.90587299],
280 [-2.95079527, -17.11827641, -47.88156244],
281 [5.24915021, -3.25786165, 26.09634067]],
282 ),
283 "FULLCOVARIANCE_NO_B": np.array(
284 [[8.71049338, 12.48584043, -37.06585088],
285 [-4.80523971, -23.29102809, -66.37815343],
286 [7.48654766, -4.10168337, 35.64469824]],
287 ),
288 }
290 for fitType in ["FULLCOVARIANCE", "FULLCOVARIANCE_NO_B"]:
291 solveConfig.ptcFitType = fitType
292 solveTask = cpPipe.ptc.PhotonTransferCurveSolveTask(config=solveConfig)
294 # Ensure no warnings re: read noise mismatches are logged.
295 with self.assertNoLogs(level=logging.WARNING):
296 resultsSolve = solveTask.run(
297 outputCovariancesRev, camera=FakeCamera([self.flatExp1.getDetector()])
298 )
300 ptc = resultsSolve.outputPtcDataset
302 # Confirm that metadata keywords are set.
303 for key in ["SEQFILE", "SEQNAME", "SEQCKSUM"]:
304 self.assertEqual(ptc.metadata[key], expHandles[0].get().metadata[key])
305 self.assertEqual(ptc.metadata["INSTRUME"], FakeCamera().getName())
306 det = expHandles[0].get().getDetector()
307 self.assertEqual(ptc.metadata["DETECTOR"], det.getId())
308 self.assertEqual(ptc.metadata["DET_NAME"], det.getName())
309 self.assertEqual(ptc.metadata["DET_SER"], det.getSerial())
311 for amp in self.ampNames:
312 self.assertAlmostEqual(ptc.gain[amp], inputGain, places=2)
313 self.assertFloatsAlmostEqual(
314 np.asarray(varStandard[amp])[ptc.expIdMask[amp]] / ptc.finalVars[amp][ptc.expIdMask[amp]],
315 1.0,
316 rtol=1e-4,
317 )
318 np.testing.assert_array_equal(ptc.nPixelCovariances[amp], nPixelCovarianceStandard[amp][0])
320 # Check that the PTC turnoff is correctly computed.
321 # This will be different for the C:0,0 amp.
322 if amp == "C:0,0":
323 self.assertAlmostEqual(ptc.ptcTurnoff[amp], ptc.rawMeans[amp][-3])
324 else:
325 self.assertAlmostEqual(ptc.ptcTurnoff[amp], ptc.rawMeans[amp][-1])
327 # Test that all the quantities are correctly ordered and
328 # have not accidentally been masked.
329 for i, extractPtc in enumerate(outputCovariances):
330 self.assertFloatsAlmostEqual(
331 extractPtc.rawExpTimes[ampName][0],
332 ptc.rawExpTimes[ampName][i],
333 )
334 self.assertFloatsAlmostEqual(
335 extractPtc.rawMeans[ampName][0],
336 ptc.rawMeans[ampName][i],
337 )
338 self.assertFloatsAlmostEqual(
339 extractPtc.rawVars[ampName][0],
340 ptc.rawVars[ampName][i],
341 )
342 self.assertFloatsAlmostEqual(
343 extractPtc.rawDeltas[ampName][0],
344 ptc.rawDeltas[ampName][i],
345 )
346 # Ensure these are set to a non-zero value.
347 self.assertFloatsNotEqual(
348 extractPtc.rawDeltas[ampName][0],
349 0.0,
350 )
351 self.assertFloatsAlmostEqual(
352 extractPtc.photoCharges[ampName][0],
353 ptc.photoCharges[ampName][i],
354 )
355 self.assertFloatsAlmostEqual(
356 extractPtc.photoChargeDeltas[ampName][0],
357 ptc.photoChargeDeltas[ampName][i],
358 )
359 # Ensure these are set to a non-zero value.
360 self.assertFloatsNotEqual(
361 extractPtc.photoChargeDeltas[ampName][0],
362 0.0,
363 )
364 self.assertFloatsAlmostEqual(
365 extractPtc.histVars[ampName][0],
366 ptc.histVars[ampName][i],
367 )
368 self.assertFloatsAlmostEqual(
369 extractPtc.histChi2Dofs[ampName][0],
370 ptc.histChi2Dofs[ampName][i],
371 )
372 self.assertFloatsAlmostEqual(
373 extractPtc.kspValues[ampName][0],
374 ptc.kspValues[ampName][i],
375 )
376 self.assertFloatsAlmostEqual(
377 extractPtc.covariances[ampName][0],
378 ptc.covariances[ampName][i],
379 )
380 self.assertFloatsAlmostEqual(
381 extractPtc.covariancesSqrtWeights[ampName][0],
382 ptc.covariancesSqrtWeights[ampName][i],
383 )
384 self.assertFloatsAlmostEqual(
385 ptc.noiseMatrix[ampName],
386 expectedNoiseMatrix[fitType],
387 atol=1e-8,
388 rtol=None,
389 )
390 self.assertFloatsAlmostEqual(
391 ptc.ampOffsets[ampName],
392 0.0,
393 )
394 self.assertFloatsAlmostEqual(
395 ptc.noise[ampName],
396 np.nanmedian(ptc.noiseList[ampName]) * ptc.gain[ampName],
397 rtol=0.05,
398 )
399 # If the noise error is greater than the noise,
400 # something is seriously wrong. Possibly some
401 # kind of gain application mismatch.
402 self.assertLess(
403 ptc.noiseErr[ampName],
404 ptc.noise[ampName],
405 )
407 mask = ptc.getGoodPoints(amp)
409 values = (
410 ptc.covariancesModel[amp][mask, 0, 0] - ptc.covariances[amp][mask, 0, 0]
411 ) / ptc.covariancesModel[amp][mask, 0, 0]
412 np.testing.assert_array_less(np.abs(values), 2e-3)
414 if ptc.ptcFitType == "FULLCOVARIANCE":
415 values = (
416 ptc.covariancesModel[amp][mask, 0, 1] - ptc.covariances[amp][mask, 0, 1]
417 ) / ptc.covariancesModel[amp][mask, 0, 1]
418 np.testing.assert_array_less(np.abs(values), 0.3)
420 values = (
421 ptc.covariancesModel[amp][mask, 1, 0] - ptc.covariances[amp][mask, 1, 0]
422 ) / ptc.covariancesModel[amp][mask, 1, 0]
423 np.testing.assert_array_less(np.abs(values), 0.3)
425 # And test that the auxiliary values are there and
426 # correctly ordered.
427 self.assertIn('CCOBCURR', ptc.auxValues)
428 self.assertIn('CCDTEMP', ptc.auxValues)
429 firstExpIds = np.array([i for i, _ in ptc.inputExpIdPairs['C:0,0']], dtype=np.float64)
430 self.assertFloatsAlmostEqual(ptc.auxValues['CCOBCURR'], firstExpIds)
431 self.assertFloatsAlmostEqual(ptc.auxValues['CCDTEMP'], firstExpIds + 1)
433 expIdsUsed = ptc.getExpIdsUsed("C:0,0")
434 # Check that these are the same as the inputs, paired up, with the
435 # first two (low flux) and final four (outliers, nans) removed.
436 self.assertTrue(
437 np.all(expIdsUsed == np.array(expIds).reshape(len(expIds) // 2, 2)[1:-2])
438 )
440 goodAmps = ptc.getGoodAmps()
441 self.assertEqual(goodAmps, self.ampNames)
443 # Check that every possibly modified field has the same length.
444 covShape = None
445 covSqrtShape = None
446 covModelShape = None
448 for ampName in self.ampNames:
449 if covShape is None:
450 covShape = ptc.covariances[ampName].shape
451 covSqrtShape = ptc.covariancesSqrtWeights[ampName].shape
452 covModelShape = ptc.covariancesModel[ampName].shape
453 else:
454 self.assertEqual(ptc.covariances[ampName].shape, covShape)
455 self.assertEqual(
456 ptc.covariancesSqrtWeights[ampName].shape, covSqrtShape
457 )
458 self.assertEqual(ptc.covariancesModel[ampName].shape, covModelShape)
460 # Check if evalPtcModel produces expected values
461 nanMask = ~np.isnan(ptc.finalMeans[ampName])
462 means = ptc.finalMeans[ampName][nanMask]
463 covModel = ptc.covariancesModel[ampName][nanMask]
464 covariancesModel = ptc.evalPtcModel(means)[ampName]
465 self.assertFloatsAlmostEqual(covariancesModel, covModel, atol=1e-12)
467 # And check that this is serializable
468 with tempfile.NamedTemporaryFile(suffix=".fits") as f:
469 usedFilename = ptc.writeFits(f.name)
470 fromFits = PhotonTransferCurveDataset.readFits(usedFilename)
471 self.assertEqual(fromFits, ptc)
473 def ptcFitAndCheckPtc(
474 self,
475 fitType=None,
476 doFitBootstrap=False,
477 ):
478 localDataset = copy.deepcopy(self.dataset)
479 localDataset.ptcFitType = fitType
480 configSolve = copy.copy(self.defaultConfigSolve)
481 if doFitBootstrap:
482 configSolve.doFitBootstrap = True
484 if fitType == "EXPAPPROXIMATION":
485 g = self.gain
486 for ampName in self.ampNames:
487 localDataset.rawVars[ampName] = [
488 (
489 0.5 / (self.a00 * g**2) * (np.exp(2 * self.a00 * mu * g) - 1)
490 + self.noiseSq / (g * g)
491 )
492 for mu in localDataset.rawMeans[ampName]
493 ]
494 else:
495 raise RuntimeError(
496 "Fit type must be 'EXPAPPROXIMATION'"
497 )
499 # Initialize mask and covariance weights that will be used in fits.
500 # Covariance weights values empirically determined from one of
501 # the cases in test_covAstier.
502 matrixSize = localDataset.covMatrixSide
503 maskLength = len(localDataset.rawMeans[ampName])
504 for ampName in self.ampNames:
505 localDataset.expIdMask[ampName] = np.repeat(True, maskLength)
506 localDataset.covariancesSqrtWeights[ampName] = np.repeat(
507 np.ones((matrixSize, matrixSize)), maskLength
508 ).reshape((maskLength, matrixSize, matrixSize))
509 localDataset.covariancesSqrtWeights[ampName][:, 0, 0] = [
510 0.07980188,
511 0.01339653,
512 0.0073118,
513 0.00502802,
514 0.00383132,
515 0.00309475,
516 0.00259572,
517 0.00223528,
518 0.00196273,
519 0.00174943,
520 0.00157794,
521 0.00143707,
522 0.00131929,
523 0.00121935,
524 0.0011334,
525 0.00105893,
526 0.00099357,
527 0.0009358,
528 0.00088439,
529 0.00083833,
530 ]
532 solveTask = cpPipe.ptc.PhotonTransferCurveSolveTask(config=configSolve)
534 if fitType == "EXPAPPROXIMATION":
535 localDataset = solveTask.fitPtc(localDataset)
536 else:
537 localDataset = solveTask.fitDataFullCovariance(localDataset)
539 # Check entries in localDataset, which was modified by the function
540 for ampName in self.ampNames:
541 self.assertEqual(fitType, localDataset.ptcFitType)
542 self.assertAlmostEqual(self.gain, localDataset.gain[ampName])
543 if fitType == "EXPAPPROXIMATION":
544 self.assertAlmostEqual(
545 self.a00, localDataset.ptcFitPars[ampName][0]
546 )
547 # Noise already in electrons
548 self.assertAlmostEqual(
549 np.sqrt(self.noiseSq), localDataset.noise[ampName]
550 )
551 # If the noise error is greater than the noise, something
552 # is seriously wrong. Possibly some kind of gain application
553 # mismatch.
554 self.assertLess(
555 localDataset.noiseErr[ampName],
556 np.sqrt(self.noiseSq)
557 )
559 # Check if evalColModel produces expected values
560 if not doFitBootstrap:
561 nanMask = ~np.isnan(localDataset.finalMeans[ampName])
562 means = localDataset.finalMeans[ampName][nanMask]
563 model = localDataset.finalModelVars[ampName][nanMask]
564 evalVarModel = localDataset.evalPtcModel(means)[ampName]
565 self.assertFloatsEqual(evalVarModel, model)
567 def test_lsstcam_samples(self):
568 for dense in [False, True]:
569 for mode in ["normal", "upturn", "dip"]:
570 for doModelPtcRolloff in [False, True]:
571 rawMeans, rawVars, ptcTurnoff = self._getSampleMeanAndVar(dense=dense, mode=mode)
573 # We only need a single amp.
574 ampName = self.ampNames[0]
575 dataset = PhotonTransferCurveDataset([ampName], ptcFitType="EXPAPPROXIMATION")
576 dataset.rawExpTimes[ampName] = np.arange(len(rawMeans), dtype=np.float64) + 1.0
577 dataset.rawMeans[ampName] = rawMeans
578 dataset.rawVars[ampName] = rawVars
579 dataset.covariancesSqrtWeights[ampName] = np.repeat(
580 np.ones((dataset.covMatrixSide, dataset.covMatrixSide)), len(rawMeans)
581 ).reshape((len(rawMeans), dataset.covMatrixSide, dataset.covMatrixSide))
582 dataset.covariancesSqrtWeights[ampName][:, 0, 0] = np.sqrt(rawVars)
583 mask = np.ones(len(rawMeans), dtype=np.bool_)
584 mask[~np.isfinite(rawMeans) | ~np.isfinite(rawVars)] = False
585 dataset.expIdMask[ampName] = mask
587 configSolve = copy.copy(self.defaultConfigSolve)
588 configSolve.doModelPtcRolloff = doModelPtcRolloff
589 configSolve.doFitBootstrap = False
591 solveTask = cpPipe.ptc.PhotonTransferCurveSolveTask(config=configSolve)
593 initialFitDataset = solveTask.fitPtc(dataset, computePtcTurnoff=True)
595 # Model the PTC rolloff
596 if doModelPtcRolloff:
597 initialFitDataset = solveTask.fitPtcRolloff(initialFitDataset)
599 solvedDataset = solveTask.fitPtc(initialFitDataset, computePtcTurnoff=False)
600 # Check that the ptcTurnoff is what is expected.
601 self.assertFloatsAlmostEqual(
602 solvedDataset.ptcTurnoff[ampName],
603 ptcTurnoff,
604 msg=(
605 f"Dense: {dense}; Mode: {mode}, "
606 f"doModelPtcRolloff: {doModelPtcRolloff}; Amp: {ampName}"
607 ),
608 )
610 # Check that no values above the
611 # turnoff/rolloff are "good".
612 maxMean = solvedDataset.ptcTurnoff[ampName]
613 if doModelPtcRolloff:
614 # Check that the PTC rolloff is less
615 # than the PTC turnoff and within 10%
616 # of the turnoff.
617 if dense:
618 # Check that
619 self.assertLess(
620 solvedDataset.ptcRolloff[ampName],
621 solvedDataset.ptcTurnoff[ampName],
622 msg=(
623 f"Dense: {dense}; Mode: {mode}, "
624 f"doModelPtcRolloff: {doModelPtcRolloff}; "
625 f"Amp: {ampName}"
626 ),
627 )
628 self.assertFloatsAlmostEqual(
629 solvedDataset.ptcRolloff[ampName],
630 solvedDataset.ptcTurnoff[ampName],
631 atol=0.1 * solvedDataset.ptcTurnoff[ampName],
632 msg=(
633 f"Dense: {dense}; Mode: {mode}, "
634 f"doModelPtcRolloff: {doModelPtcRolloff}; "
635 f"Amp: {ampName}"
636 ),
637 )
638 else:
639 # In all other cases, it should not be able to
640 # find points beyond the turnoff, and the
641 # rolloff should be set to the PTC turnoff.
642 self.assertEqual(
643 solvedDataset.ptcRolloff[ampName],
644 solvedDataset.ptcTurnoff[ampName],
645 msg=(
646 f"Dense: {dense}; Mode: {mode}, "
647 f"doModelPtcRolloff: {doModelPtcRolloff}; "
648 f"Amp: {ampName}"
649 ),
650 )
652 # If that passes set the maxMean to the PTC Rolloff
653 maxMean = solvedDataset.ptcRolloff[ampName]
655 above = (solvedDataset.finalMeans[ampName] > maxMean)
656 self.assertEqual(
657 np.sum(above),
658 0,
659 msg=(
660 f"Dense: {dense}; Mode: {mode}, "
661 f"doModelPtcRolloff: {doModelPtcRolloff}; Amp: {ampName}"
662 ),
663 )
665 # Check the sampling error on the turnoff.
666 turnoffIdx = np.argwhere(
667 solvedDataset.rawMeans[ampName] == solvedDataset.ptcTurnoff[ampName]
668 )
669 samplingError = (rawMeans[turnoffIdx + 1] - rawMeans[turnoffIdx - 1])/2.
670 self.assertFloatsAlmostEqual(
671 solvedDataset.ptcTurnoffSamplingError[ampName],
672 samplingError,
673 msg=f"Dense: {dense}; Mode: {mode}",
674 )
676 def test_ptcFit(self):
677 for fitType in ["EXPAPPROXIMATION"]:
678 self.ptcFitAndCheckPtc(
679 fitType=fitType
680 )
682 def test_meanVarMeasurement(self):
683 task = self.defaultTaskExtract
684 im1Area, im2Area, imStatsCtrl, mu1, mu2 = task.getImageAreasMasksStats(
685 self.flatExp1, self.flatExp2
686 )
687 mu, varDiff, _, _ = task.measureMeanVarCov(im1Area, im2Area, imStatsCtrl, mu1, mu2)
689 self.assertLess(self.flatWidth - np.sqrt(varDiff), 1)
690 self.assertLess(self.flatMean - mu, 1)
692 def test_meanVarMeasurementWithNans(self):
693 task = self.defaultTaskExtract
695 flatExp1 = self.flatExp1.clone()
696 flatExp2 = self.flatExp2.clone()
698 flatExp1.image.array[20:30, :] = np.nan
699 flatExp2.image.array[20:30, :] = np.nan
701 im1Area, im2Area, imStatsCtrl, mu1, mu2 = task.getImageAreasMasksStats(
702 flatExp1, flatExp2
703 )
704 mu, varDiff, _, _ = task.measureMeanVarCov(im1Area, im2Area, imStatsCtrl, mu1, mu2)
706 expectedMu1 = np.nanmean(flatExp1.image.array)
707 expectedMu2 = np.nanmean(flatExp2.image.array)
708 expectedMu = 0.5 * (expectedMu1 + expectedMu2)
710 # Now the variance of the difference. First, create the diff image.
711 im1 = flatExp1.maskedImage
712 im2 = flatExp2.maskedImage
714 temp = im2.clone()
715 temp *= expectedMu1
716 diffIm = im1.clone()
717 diffIm *= expectedMu2
718 diffIm -= temp
719 diffIm /= expectedMu
721 # Divide by two as it is what measureMeanVarCov returns
722 # (variance of difference)
723 expectedVar = 0.5 * np.nanvar(diffIm.image.array)
725 # Check that the standard deviations and the emans agree to
726 # less than 1 ADU
727 self.assertLess(np.sqrt(expectedVar) - np.sqrt(varDiff), 1)
728 self.assertLess(expectedMu - mu, 1)
730 def test_meanVarMeasurementAllNan(self):
731 task = self.defaultTaskExtract
732 flatExp1 = self.flatExp1.clone()
733 flatExp2 = self.flatExp2.clone()
735 flatExp1.image.array[:, :] = np.nan
736 flatExp2.image.array[:, :] = np.nan
738 im1Area, im2Area, imStatsCtrl, mu1, mu2 = task.getImageAreasMasksStats(
739 flatExp1, flatExp2
740 )
741 mu, varDiff, covDiff, rowMeanVariance = task.measureMeanVarCov(
742 im1Area, im2Area, imStatsCtrl, mu1, mu2
743 )
745 self.assertTrue(np.isnan(mu))
746 self.assertTrue(np.isnan(varDiff))
747 self.assertTrue(covDiff is None)
748 self.assertTrue(np.isnan(rowMeanVariance))
750 def test_meanVarMeasurementTooFewPixels(self):
751 task = self.defaultTaskExtract
752 flatExp1 = self.flatExp1.clone()
753 flatExp2 = self.flatExp2.clone()
755 flatExp1.image.array[0:190, :] = np.nan
756 flatExp2.image.array[0:190, :] = np.nan
758 bit = flatExp1.mask.getMaskPlaneDict()["NO_DATA"]
759 flatExp1.mask.array[0:190, :] &= 2**bit
760 flatExp2.mask.array[0:190, :] &= 2**bit
762 im1Area, im2Area, imStatsCtrl, mu1, mu2 = task.getImageAreasMasksStats(
763 flatExp1, flatExp2
764 )
765 with self.assertLogs(level=logging.WARNING) as cm:
766 mu, varDiff, covDiff, rowMeanVariance = task.measureMeanVarCov(
767 im1Area, im2Area, imStatsCtrl, mu1, mu2
768 )
769 self.assertIn("Number of good points", cm.output[0])
771 self.assertTrue(np.isnan(mu))
772 self.assertTrue(np.isnan(varDiff))
773 self.assertTrue(covDiff is None)
774 self.assertTrue(np.isnan(rowMeanVariance))
776 def test_meanVarMeasurementTooNarrowStrip(self):
777 # We need a new config to make sure the second covariance cut is
778 # triggered.
779 config = cpPipe.ptc.PhotonTransferCurveExtractTask.ConfigClass()
780 config.minNumberGoodPixelsForCovariance = 10
781 task = cpPipe.ptc.PhotonTransferCurveExtractTask(config=config)
782 flatExp1 = self.flatExp1.clone()
783 flatExp2 = self.flatExp2.clone()
785 flatExp1.image.array[0:195, :] = np.nan
786 flatExp2.image.array[0:195, :] = np.nan
787 flatExp1.image.array[:, 0:195] = np.nan
788 flatExp2.image.array[:, 0:195] = np.nan
790 bit = flatExp1.mask.getMaskPlaneDict()["NO_DATA"]
791 flatExp1.mask.array[0:195, :] &= 2**bit
792 flatExp2.mask.array[0:195, :] &= 2**bit
793 flatExp1.mask.array[:, 0:195] &= 2**bit
794 flatExp2.mask.array[:, 0:195] &= 2**bit
796 im1Area, im2Area, imStatsCtrl, mu1, mu2 = task.getImageAreasMasksStats(
797 flatExp1, flatExp2
798 )
799 with self.assertLogs(level=logging.WARNING) as cm:
800 mu, varDiff, covDiff, rowMeanVariance = task.measureMeanVarCov(
801 im1Area, im2Area, imStatsCtrl, mu1, mu2
802 )
803 self.assertIn("Not enough pixels", cm.output[0])
805 self.assertTrue(np.isnan(mu))
806 self.assertTrue(np.isnan(varDiff))
807 self.assertTrue(covDiff is None)
808 self.assertTrue(np.isnan(rowMeanVariance))
810 def test_makeZeroSafe(self):
811 noZerosArray = [1.0, 20, -35, 45578.98, 90.0, 897, 659.8]
812 someZerosArray = [1.0, 20, 0, 0, 90, 879, 0]
813 allZerosArray = [0.0, 0.0, 0, 0, 0.0, 0, 0]
815 substituteValue = 1e-10
817 expectedSomeZerosArray = [
818 1.0,
819 20,
820 substituteValue,
821 substituteValue,
822 90,
823 879,
824 substituteValue,
825 ]
826 expectedAllZerosArray = np.repeat(substituteValue, len(allZerosArray))
828 measuredSomeZerosArray = self.defaultTaskSolve._makeZeroSafe(
829 someZerosArray, substituteValue=substituteValue
830 )
831 measuredAllZerosArray = self.defaultTaskSolve._makeZeroSafe(
832 allZerosArray, substituteValue=substituteValue
833 )
834 measuredNoZerosArray = self.defaultTaskSolve._makeZeroSafe(
835 noZerosArray, substituteValue=substituteValue
836 )
838 for exp, meas in zip(expectedSomeZerosArray, measuredSomeZerosArray):
839 self.assertEqual(exp, meas)
840 for exp, meas in zip(expectedAllZerosArray, measuredAllZerosArray):
841 self.assertEqual(exp, meas)
842 for exp, meas in zip(noZerosArray, measuredNoZerosArray):
843 self.assertEqual(exp, meas)
845 def runGetGainFromFlatPair(self, correctionType="NONE"):
846 extractConfig = self.defaultConfigExtract
847 extractConfig.gainCorrectionType = correctionType
848 extractConfig.minNumberGoodPixelsForCovariance = 5000
849 extractTask = cpPipe.ptc.PhotonTransferCurveExtractTask(config=extractConfig)
851 expDict = {}
852 expIds = []
853 idCounter = 0
854 inputGain = self.gain # 1.5 e/ADU
855 for expTime in self.timeVec:
856 # Approximation works better at low flux, e.g., < 10000 ADU
857 mockExp1, mockExp2 = makeMockFlats(
858 expTime,
859 gain=inputGain,
860 readNoiseElectrons=np.sqrt(self.noiseSq),
861 fluxElectrons=100,
862 expId1=idCounter,
863 expId2=idCounter + 1,
864 ampNames=self.ampNames,
865 )
866 mockExpRef1 = PretendRef(mockExp1)
867 mockExpRef2 = PretendRef(mockExp2)
868 expDict[expTime] = ((mockExpRef1, idCounter), (mockExpRef2, idCounter + 1))
869 expIds.append(idCounter)
870 expIds.append(idCounter + 1)
871 idCounter += 2
873 # This will test the full extract task.
874 resultsExtract = extractTask.run(
875 inputExp=expDict,
876 inputDims=expIds,
877 )
878 for exposurePair in resultsExtract.outputCovariances:
879 for ampName in self.ampNames:
880 if exposurePair.gain[ampName] is np.nan:
881 continue
882 self.assertAlmostEqual(
883 exposurePair.gain[ampName], inputGain, delta=0.04
884 )
886 # Run through the solver and check that the gains from flat pairs
887 # are recorded in the gainList.
888 solveConfig = self.defaultConfigSolve
889 solveConfig.ptcFitType = "EXPAPPROXIMATION"
890 solveTask = cpPipe.ptc.PhotonTransferCurveSolveTask(config=solveConfig)
892 resultsSolve = solveTask.run(
893 resultsExtract.outputCovariances,
894 camera=FakeCamera([self.flatExp1.getDetector()]),
895 )
896 ptc = resultsSolve.outputPtcDataset
898 for i in range(len(ptc.inputExpIdPairs)):
899 for ampName in self.ampNames:
900 if np.isnan(ptc.gainList[ampName][i]):
901 continue
902 self.assertAlmostEqual(
903 ptc.gainList[ampName][i], inputGain, delta=0.04,
904 )
905 self.assertAlmostEqual(
906 ptc.noiseList[ampName][i], np.sqrt(self.noiseSq) / self.gain,
907 )
909 def test_getGainFromFlatPair(self):
910 for gainCorrectionType in [
911 "NONE",
912 "SIMPLE",
913 "FULL",
914 ]:
915 self.runGetGainFromFlatPair(gainCorrectionType)
917 def test_ptcFitBootstrap(self):
918 """Test the bootstrap fit option for the PTC"""
919 for fitType in ['EXPAPPROXIMATION']:
920 self.ptcFitAndCheckPtc(fitType=fitType, doFitBootstrap=True)
922 def test_ampOffsetGainRatioFixup(self):
923 """Test the ampOffsetGainRatioFixup code via
924 PhotonTransferCurveFixupGainRatiosTask."""
925 rng = np.random.RandomState(12345)
927 gainsTruth = rng.normal(loc=1.7, scale=0.05, size=len(self.ampNames))
928 gainsMedian = np.median(gainsTruth)
930 gainsMeasured = rng.normal(loc=gainsTruth, scale=0.02, size=len(self.ampNames))
932 # Make one of the measured gains a much larger outlier to ensure
933 # the code can handle a wacky measurement.
934 weird_amp_index = 1
935 gainsMeasured[weird_amp_index] = 1.2
937 # We have a perfectly flat illuminated detector (in electrons)
938 nFlat = 20
939 meansElectron = gainsMedian * np.linspace(500.0, 30000.0, nFlat)
941 # Set up the fixup task.
942 fixupConfig = cpPipe.ptc.PhotonTransferCurveFixupGainRatiosConfig()
943 fixupConfig.ampOffsetGainRatioMinAdu = 1000.0
944 fixupConfig.ampOffsetGainRatioMaxAdu = 20000.0
945 fixupTask = cpPipe.ptc.PhotonTransferCurveFixupGainRatiosTask(config=fixupConfig)
947 for testMode in ["full", "badamp"]:
948 badAmp = None
950 ptc = PhotonTransferCurveDataset(self.ampNames, ptcFitType="FULLCOVARIANCE")
952 # Build the PTC to test amp offsets.
953 for i, ampName in enumerate(self.ampNames):
954 ptc.gain[ampName] = gainsMeasured[i]
955 ptc.gainUnadjusted[ampName] = gainsMeasured[i]
957 if testMode == "badamp" and i == 3:
958 ptc.gain[ampName] = np.nan
959 ptc.gainUnadjusted[ampName] = np.nan
960 badAmp = ampName
962 # The measured amp means are given by the true gains.
963 ptc.finalMeans[ampName] = meansElectron / gainsTruth[i]
964 ptc.expIdMask[ampName] = np.ones(nFlat, dtype=np.bool_)
966 # Fill the amp offsets temporarily.
967 ptc.ampOffsets[ampName] = np.zeros(len(meansElectron))
969 # Build each toy flat and measure the amp offsets.
970 config = AmpOffsetTask.ConfigClass()
971 config.ampEdgeMaxOffset = 100000.0
972 config.ampEdgeWidth = 16
973 config.ampEdgeInset = 10
974 config.doBackground = False
975 config.doDetection = False
976 config.doApplyAmpOffset = False
978 ampOffset = AmpOffsetTask(config=config)
980 detector = self.flatExp1.getDetector()
981 metadatas = []
982 for i in range(nFlat):
983 exp = self.flatExp1.clone()
984 for amp in detector:
985 amp_name = amp.getName()
986 exp[amp.getBBox()].image.array[:, :] = ptc.finalMeans[amp_name][i]
987 md = exp.metadata
989 md[f"LSST ISR FINAL MEDIAN {amp_name}"] = ptc.finalMeans[amp_name][i]
990 md[f"LSST ISR FINAL STDEV {amp_name}"] = np.sqrt(ptc.finalMeans[amp_name][i])
991 md[f"LSST ISR READNOISE {amp_name}"] = 0.0
993 ampOffset.run(exp)
994 metadatas.append(exp.metadata)
996 result = fixupTask.run(inputPtc=ptc, exposureMetadata=metadatas)
997 ptc = result.outputPtc
999 # Check that the flats are flat after adjustment.
1000 for i in range(nFlat):
1001 for j, amp in enumerate(detector):
1002 gain = ptc.gain[amp.getName()]
1003 exp[amp.getBBox()].image.array[:, :] = ptc.finalMeans[amp.getName()][i] * gain
1005 testImage = exp.image.array / np.nanmedian(exp.image.array)
1006 if testMode == "badamp":
1007 # Force the bad values to 1.0
1008 testImage[~np.isfinite(testImage)] = 1.0
1010 self.assertFloatsAlmostEqual(testImage.ravel(), 1.0, rtol=1e-6)
1012 # Confirm that the median gain is reasonably unchanged.
1013 gainsAdjusted = np.array([ptc.gain[ampName] for ampName in self.ampNames])
1014 self.assertFloatsAlmostEqual(np.nanmedian(gainsAdjusted), np.nanmedian(gainsMeasured), rtol=0.007)
1016 # Confirm that the median of the corrections is 1.0
1017 gainCorrections = np.array([ptc.gain[ampName]/ptc.gainUnadjusted[ampName]
1018 for ampName in self.ampNames])
1019 self.assertFloatsAlmostEqual(np.nanmedian(gainCorrections), 1.0, rtol=1e-7)
1021 # Check that the gain ratios are matched as expected.
1022 for i, ampName1 in enumerate(self.ampNames):
1023 for j, ampName2 in enumerate(self.ampNames):
1024 ratioTruth = gainsTruth[i] / gainsTruth[j]
1025 ratio = ptc.gain[ampName1] / ptc.gain[ampName2]
1027 if ampName1 != badAmp and ampName2 != badAmp:
1028 self.assertFloatsAlmostEqual(ratio, ratioTruth, rtol=1e-7)
1030 # Check that everything is logged correctly when things are very bad.
1031 for ampName in self.ampNames[2:]:
1032 ptc.ampOffsets[ampName][:] = np.nan
1034 with self.assertLogs(level=logging.WARNING) as cm:
1035 ampOffsetGainRatioFixup(ptc, 1000.0, 20000.0)
1036 self.assertIn("Not enough good amp offset measurements", cm.output[0])
1038 for ampName in self.ampNames[1:]:
1039 ptc.gain[ampName] = np.nan
1041 with self.assertLogs(level=logging.WARNING) as cm:
1042 ampOffsetGainRatioFixup(ptc, 1000.0, 20000.0)
1043 self.assertIn("Cannot apply ampOffsetGainRatioFixup", cm.output[0])
1045 def test_maskVignetteFunctionRegion(self):
1046 # The function coefficients are chosen to trigger on some amps.
1047 # The amps with no masked pixels are C:1,0 and C:1,3 due to the
1048 # curvature.
1049 extractConfig = self.defaultConfigExtract
1050 extractConfig.doVignetteFunctionRegionSelection = True
1051 extractConfig.vignetteFunctionPolynomialCoeffs = [-100.0, -18.0, 1.0]
1052 extractConfig.vignetteFunctionRegionSelectionMinimumPixels = 2_000
1054 task = cpPipe.ptc.PhotonTransferCurveExtractPairTask(config=extractConfig)
1055 exposures = [self.flatExp1, self.flatExp2]
1056 with self.assertNoLogs(level=logging.WARNING):
1057 task._maskVignetteFunctionRegion(exposures)
1059 bitmask = self.flatExp1.mask.getPlaneBitMask("SUSPECT")
1060 for amp in self.flatExp1.getDetector():
1061 bbox = amp.getBBox()
1062 nMasked = ((self.flatExp1.mask[bbox].array & bitmask) > 0).sum()
1063 if amp.getName() not in ["C:1,0", "C:1,3"]:
1064 self.assertGreater(nMasked, 0, msg=f"Missing masked pixels in {amp.getName()}")
1065 else:
1066 self.assertEqual(nMasked, 0, msg=f"Unexpected masked pixels in {amp.getName()}")
1068 # Check what happens if we ask for too many pixels.
1069 extractConfig = self.defaultConfigExtract
1070 extractConfig.doVignetteFunctionRegionSelection = True
1071 extractConfig.vignetteFunctionPolynomialCoeffs = [-100.0, -18.0, 1.0]
1072 extractConfig.vignetteFunctionRegionSelectionMinimumPixels = 10_000
1074 self.flatExp1.mask.array[:, :] = 0
1075 self.flatExp2.mask.array[:, :] = 0
1076 task = cpPipe.ptc.PhotonTransferCurveExtractPairTask(config=extractConfig)
1077 exposures = [self.flatExp1, self.flatExp2]
1078 with self.assertLogs(level=logging.WARNING):
1079 task._maskVignetteFunctionRegion(exposures)
1081 # This should not have any masked pixels because we essentially
1082 # insisted that the full amp be selected.
1083 for amp in self.flatExp1.getDetector():
1084 self.assertEqual(nMasked, 0, msg=f"Unexpected masked pixels in {amp.getName()}")
1086 def _getSampleMeanAndVar(self, dense=False, mode="normal"):
1087 """Get sample mean/var vectors and ptcTurnoff from LSSTCam data.
1089 The ptcTurnoff values here were obtained by looking at the data
1090 and what the code does. These may be changed in the future if
1091 we decide on a different way of computing the turnoff.
1093 Parameters
1094 ----------
1095 dense : `bool`, optional
1096 Return a dense PTC?
1097 mode : `str`, optional
1098 The ptc type, should be "normal", "upturn", or "dip".
1100 Returns
1101 -------
1102 rawMeans : `np.ndarray`
1103 Array of raw mean values.
1104 rawVars : `np.ndarray`
1105 Array of raw variance values.
1106 ptcTurnoff : `float`
1107 PTC turnoff determined from fitting by eye.
1108 """
1109 if dense and mode == "normal":
1110 # Taken from dense run 13591, detector 94, amplifier C02
1111 ptcTurnoff = 92239.4794
1112 rawMeans = np.array([
1113 3.72806883e+01, 3.86850679e+01, 4.09319941e+01, 4.30288886e+01,
1114 4.59546561e+01, 4.77510985e+01, 5.06130505e+01, 5.35060747e+01,
1115 5.61016577e+01, 5.95244630e+01, 6.21722799e+01, 6.59958508e+01,
1116 7.32513785e+01, 7.91695151e+01, 8.19214651e+01, 8.66175502e+01,
1117 9.06656207e+01, 9.57917501e+01, 1.00925700e+02, 1.07661026e+02,
1118 1.12211207e+02, 1.18038278e+02, 1.24776787e+02, 1.33127394e+02,
1119 1.39086972e+02, 1.47962442e+02, 1.55007859e+02, 1.64972119e+02,
1120 1.72224552e+02, 1.81663660e+02, 1.92083706e+02, 2.01818483e+02,
1121 2.12893098e+02, 2.25865898e+02, 2.36777769e+02, 2.50805751e+02,
1122 2.63582968e+02, 2.78848126e+02, 2.93430577e+02, 3.10974538e+02,
1123 3.28617662e+02, 3.44447122e+02, 3.63779087e+02, 3.85447934e+02,
1124 4.04865571e+02, 4.26619625e+02, 4.50642349e+02, 4.75572605e+02,
1125 5.00924590e+02, 5.29463072e+02, 5.56894775e+02, 5.89400667e+02,
1126 6.22194672e+02, 6.55411968e+02, 6.90233178e+02, 7.28617776e+02,
1127 7.70386654e+02, 8.11275732e+02, 8.56899058e+02, 9.04075885e+02,
1128 9.53041280e+02, 1.00428165e+03, 1.05984066e+03, 1.11936964e+03,
1129 1.17993499e+03, 1.24493657e+03, 1.31333429e+03, 1.38477571e+03,
1130 1.46288220e+03, 1.54131684e+03, 1.62718454e+03, 1.71685496e+03,
1131 1.91104434e+03, 1.91128408e+03, 2.01496942e+03, 2.01510504e+03,
1132 2.12643136e+03, 2.12665024e+03, 2.24351981e+03, 2.36534141e+03,
1133 2.49658670e+03, 2.77859948e+03, 2.92932915e+03, 3.21897902e+03,
1134 3.39732732e+03, 3.58413491e+03, 3.78057120e+03, 3.98731229e+03,
1135 4.20691253e+03, 4.43947873e+03, 4.68353906e+03, 4.94068272e+03,
1136 5.20957520e+03, 5.21201592e+03, 5.49832249e+03, 5.80143284e+03,
1137 6.12091976e+03, 6.81333865e+03, 7.18560833e+03, 7.76381518e+03,
1138 8.33998116e+03, 8.91777512e+03, 9.49514657e+03, 1.00697547e+04,
1139 1.06495655e+04, 1.12197718e+04, 1.18024551e+04, 1.23803888e+04,
1140 1.29546730e+04, 1.35302383e+04, 1.41095292e+04, 1.46864242e+04,
1141 1.52554127e+04, 1.58424382e+04, 1.64174609e+04, 1.69934436e+04,
1142 1.75654540e+04, 1.81523967e+04, 1.87298339e+04, 1.93014337e+04,
1143 2.04450305e+04, 2.10377447e+04, 2.16102067e+04, 2.16123196e+04,
1144 2.21851791e+04, 2.21921696e+04, 2.33433082e+04, 2.39171545e+04,
1145 2.44958327e+04, 2.50717007e+04, 2.56486425e+04, 2.62185599e+04,
1146 2.68048566e+04, 2.73814219e+04, 2.79519282e+04, 2.85325879e+04,
1147 2.91077169e+04, 2.96844973e+04, 3.02554411e+04, 3.14125545e+04,
1148 3.25683638e+04, 3.31324135e+04, 3.33243063e+04, 3.38868072e+04,
1149 3.44574798e+04, 3.50295131e+04, 3.55959947e+04, 3.61681182e+04,
1150 3.67288051e+04, 3.73019527e+04, 3.78659087e+04, 3.84175071e+04,
1151 3.90035052e+04, 3.95715617e+04, 4.06979100e+04, 4.12778387e+04,
1152 4.18444142e+04, 4.24067921e+04, 4.29743477e+04, 4.35479754e+04,
1153 4.41086362e+04, 4.46748906e+04, 4.57912581e+04, 4.63620286e+04,
1154 4.69293084e+04, 4.80512660e+04, 4.86149041e+04, 4.91798146e+04,
1155 5.03083769e+04, 5.08678825e+04, 5.14329108e+04, 5.20101245e+04,
1156 5.25674618e+04, 5.31040686e+04, 5.36908774e+04, 5.42697605e+04,
1157 5.47843148e+04, 5.53743324e+04, 5.59452125e+04, 5.70753786e+04,
1158 5.76356662e+04, 5.81990397e+04, 5.87644952e+04, 5.98894309e+04,
1159 6.04630169e+04, 6.10270338e+04, 6.15960865e+04, 6.21427559e+04,
1160 6.27197146e+04, 6.32781202e+04, 6.38170695e+04, 6.44264810e+04,
1161 6.49720024e+04, 6.55524996e+04, 6.66814853e+04, 6.72313467e+04,
1162 6.78274362e+04, 6.83859289e+04, 6.89427312e+04, 6.95198678e+04,
1163 7.00847030e+04, 7.06620283e+04, 7.12327432e+04, 7.17769841e+04,
1164 7.23610736e+04, 7.29237272e+04, 7.34938353e+04, 7.40400864e+04,
1165 7.46399787e+04, 7.52085787e+04, 7.57175033e+04, 7.63346271e+04,
1166 7.69141477e+04, 7.74690838e+04, 7.80403707e+04, 7.85672045e+04,
1167 7.91728742e+04, 7.97519543e+04, 8.03063026e+04, 8.08869068e+04,
1168 8.14577271e+04, 8.20105730e+04, 8.25824739e+04, 8.31490218e+04,
1169 8.37308110e+04, 8.42758180e+04, 8.48493221e+04, 8.54126656e+04,
1170 8.59826959e+04, 8.65501659e+04, 8.70696403e+04, 8.76932979e+04,
1171 8.82464074e+04, 8.93795020e+04, 8.99537321e+04, 9.05097100e+04,
1172 9.10881246e+04, 9.22394794e+04, 9.27870984e+04, 9.33315296e+04,
1173 9.39230922e+04, 9.44926266e+04, 9.56192429e+04, 9.61483057e+04,
1174 9.72621754e+04, 9.78325850e+04, 9.83972793e+04, 9.89552969e+04,
1175 9.94332509e+04, 1.00047506e+05, 1.00569417e+05, 1.01105830e+05,
1176 1.01634936e+05, 1.02121705e+05, 1.02641415e+05, 1.03123767e+05,
1177 1.03599733e+05, 1.04062370e+05, 1.04907216e+05, 1.05256436e+05,
1178 1.05665701e+05, 1.06007083e+05, 1.06318115e+05, 1.06593953e+05,
1179 1.06893542e+05, 1.07121150e+05, 1.07346243e+05, 1.07625934e+05,
1180 1.08044429e+05, 1.08167080e+05, 1.08308995e+05, 1.08399830e+05,
1181 1.08526582e+05, 1.08620505e+05, 1.08713803e+05, 1.08784455e+05,
1182 1.08862350e+05, 1.08937801e+05, 1.08989964e+05, 1.09060085e+05,
1183 1.09162026e+05, 1.09220593e+05, 1.09273416e+05, 1.09333464e+05,
1184 1.09372863e+05, 1.09468530e+05, 1.09513735e+05, 1.09553322e+05,
1185 1.09594566e+05, 1.09641845e+05, 1.09679236e+05, 1.09723860e+05,
1186 1.09753056e+05, 1.09826579e+05, 1.09872135e+05, 1.09895670e+05,
1187 1.09902080e+05, 1.09943174e+05, 1.10002465e+05, 1.10019329e+05,
1188 1.10068730e+05, 1.10095848e+05, 1.10145789e+05, 1.10193658e+05,
1189 1.10213581e+05, 1.10248075e+05, 1.10291320e+05, 1.10316883e+05,
1190 1.10358975e+05, 1.10350689e+05, 1.10391552e+05, 1.10400507e+05,
1191 1.10409523e+05, 1.10409459e+05, 1.10412119e+05, 1.10409689e+05,
1192 1.10414648e+05, 1.10391061e+05, 1.10420513e+05, 1.10424437e+05,
1193 1.10435588e+05, 1.10438362e+05, 1.10443905e+05, 1.10450180e+05,
1194 1.10452714e+05, 1.10449100e+05, 1.10466222e+05, 1.10458324e+05,
1195 1.10478871e+05, 1.10486620e+05, 1.10485105e+05, 1.10489515e+05,
1196 1.10491243e+05, 1.10499598e+05, 1.10501449e+05, 1.10501009e+05,
1197 1.10515083e+05, 1.10533044e+05, 1.10531740e+05, 1.10548636e+05,
1198 1.10558815e+05, 1.10560570e+05, 1.10569349e+05, 1.10572778e+05,
1199 1.10588800e+05, 1.10593287e+05, 1.10596037e+05, 1.10584233e+05,
1200 1.10611084e+05, 1.10616525e+05, 1.10621289e+05, 1.10631455e+05,
1201 1.10639320e+05, 1.10647906e+05, 1.10646043e+05, 1.10635789e+05,
1202 1.10635305e+05, 1.10652093e+05, 1.10638755e+05, 1.10655426e+05,
1203 1.10651182e+05, 1.10653604e+05, 1.10665648e+05, 1.10655049e+05,
1204 1.10650105e+05, 1.10655658e+05, 1.10660937e+05, 1.10673337e+05,
1205 1.10673003e+05, 1.10655815e+05, 1.10661151e+05, 1.10662036e+05,
1206 1.10676951e+05, 1.10667334e+05, 1.10679642e+05, 1.10678497e+05])
1207 rawVars = np.array([
1208 4.47787277e+01, 4.64353847e+01, 4.85247580e+01, 4.93948408e+01,
1209 5.15948411e+01, 5.30389406e+01, 5.58813000e+01, 5.88525810e+01,
1210 6.11585484e+01, 6.41104167e+01, 6.56152371e+01, 6.82093774e+01,
1211 7.14063291e+01, 7.45066055e+01, 7.64755940e+01, 7.93540481e+01,
1212 8.18907727e+01, 8.66402959e+01, 8.97887750e+01, 9.68782459e+01,
1213 9.95221383e+01, 1.02767714e+02, 1.08068716e+02, 1.16108758e+02,
1214 1.20246097e+02, 1.26018524e+02, 1.30397686e+02, 1.36138570e+02,
1215 1.41942986e+02, 1.46772865e+02, 1.53919845e+02, 1.60521709e+02,
1216 1.68353264e+02, 1.78909843e+02, 1.88788533e+02, 2.00792706e+02,
1217 2.07611019e+02, 2.16057203e+02, 2.26987335e+02, 2.39701806e+02,
1218 2.51287870e+02, 2.64963149e+02, 2.81918185e+02, 2.93010615e+02,
1219 3.04772726e+02, 3.21723049e+02, 3.43194608e+02, 3.60791523e+02,
1220 3.72312673e+02, 3.92534946e+02, 4.18291901e+02, 4.40825475e+02,
1221 4.58818537e+02, 4.88340078e+02, 5.12852998e+02, 5.35522179e+02,
1222 5.69935148e+02, 5.92975103e+02, 6.31052929e+02, 6.61056947e+02,
1223 6.95541286e+02, 7.33787875e+02, 7.74291674e+02, 8.19211863e+02,
1224 8.62765375e+02, 8.98546352e+02, 9.55344080e+02, 1.00237170e+03,
1225 1.05926161e+03, 1.10844186e+03, 1.17604012e+03, 1.24027865e+03,
1226 1.37334609e+03, 1.37631570e+03, 1.44433952e+03, 1.44613237e+03,
1227 1.53642103e+03, 1.53144123e+03, 1.60103165e+03, 1.69486912e+03,
1228 1.79228744e+03, 1.97807118e+03, 2.08913779e+03, 2.29127569e+03,
1229 2.41035376e+03, 2.54559185e+03, 2.68285671e+03, 2.82061302e+03,
1230 2.98565936e+03, 3.13680879e+03, 3.29910967e+03, 3.48157975e+03,
1231 3.66147828e+03, 3.67694292e+03, 3.84787540e+03, 4.07925681e+03,
1232 4.28699288e+03, 4.75578456e+03, 5.00956756e+03, 5.39321737e+03,
1233 5.79686635e+03, 6.17477624e+03, 6.55132737e+03, 6.93000705e+03,
1234 7.31757235e+03, 7.68650298e+03, 8.05377657e+03, 8.42789583e+03,
1235 8.77475510e+03, 9.17341164e+03, 9.54927300e+03, 9.89596158e+03,
1236 1.02637150e+04, 1.06167914e+04, 1.09873368e+04, 1.13685550e+04,
1237 1.17026479e+04, 1.20765605e+04, 1.23946750e+04, 1.27577017e+04,
1238 1.34485509e+04, 1.37927193e+04, 1.42006355e+04, 1.41857628e+04,
1239 1.44769908e+04, 1.45162172e+04, 1.51614067e+04, 1.55571196e+04,
1240 1.58809609e+04, 1.61752079e+04, 1.65104318e+04, 1.68369000e+04,
1241 1.71408213e+04, 1.75355600e+04, 1.78226398e+04, 1.81932474e+04,
1242 1.84482292e+04, 1.88389901e+04, 1.91150651e+04, 1.97375210e+04,
1243 2.03591057e+04, 2.07155451e+04, 2.07138350e+04, 2.11073361e+04,
1244 2.13837002e+04, 2.16588926e+04, 2.19612146e+04, 2.22753789e+04,
1245 2.25303517e+04, 2.27928117e+04, 2.31125410e+04, 2.33679689e+04,
1246 2.37393625e+04, 2.40488975e+04, 2.45764011e+04, 2.48064050e+04,
1247 2.50721617e+04, 2.53965873e+04, 2.56131331e+04, 2.59277943e+04,
1248 2.61709392e+04, 2.64119896e+04, 2.68955682e+04, 2.72267063e+04,
1249 2.74887295e+04, 2.79083033e+04, 2.82310485e+04, 2.84366770e+04,
1250 2.90226269e+04, 2.92324828e+04, 2.94521967e+04, 2.97949458e+04,
1251 2.99735234e+04, 3.02749574e+04, 3.05427850e+04, 3.07518546e+04,
1252 3.09317879e+04, 3.12692332e+04, 3.15643550e+04, 3.21293639e+04,
1253 3.24007437e+04, 3.26147619e+04, 3.28979579e+04, 3.34807881e+04,
1254 3.37109710e+04, 3.40246283e+04, 3.43898469e+04, 3.45302267e+04,
1255 3.47818944e+04, 3.51593681e+04, 3.52477656e+04, 3.56490287e+04,
1256 3.59240161e+04, 3.61669226e+04, 3.66423677e+04, 3.68827117e+04,
1257 3.71622239e+04, 3.74768274e+04, 3.76872328e+04, 3.79405515e+04,
1258 3.81364527e+04, 3.84119822e+04, 3.86423009e+04, 3.88877574e+04,
1259 3.91248488e+04, 3.92990610e+04, 3.96215459e+04, 3.98297091e+04,
1260 4.00712366e+04, 4.04322148e+04, 4.05178037e+04, 4.07431736e+04,
1261 4.10193223e+04, 4.11740695e+04, 4.13790755e+04, 4.14632263e+04,
1262 4.18525778e+04, 4.20979322e+04, 4.23130642e+04, 4.24582022e+04,
1263 4.24946930e+04, 4.27860167e+04, 4.30933820e+04, 4.32894483e+04,
1264 4.33858206e+04, 4.34411628e+04, 4.36629531e+04, 4.39919091e+04,
1265 4.40293360e+04, 4.42002784e+04, 4.42310862e+04, 4.45443328e+04,
1266 4.45481958e+04, 4.48604145e+04, 4.48891948e+04, 4.48416001e+04,
1267 4.50553039e+04, 4.50927543e+04, 4.51136486e+04, 4.51126520e+04,
1268 4.49857031e+04, 4.48705631e+04, 4.46276191e+04, 4.43327388e+04,
1269 4.37938194e+04, 4.32211550e+04, 4.27332194e+04, 4.23177306e+04,
1270 4.14539982e+04, 4.06974694e+04, 3.96551098e+04, 3.82440396e+04,
1271 3.67165456e+04, 3.47661502e+04, 3.28393493e+04, 3.02395522e+04,
1272 2.76939927e+04, 2.48272541e+04, 1.92526286e+04, 1.63986811e+04,
1273 1.42095886e+04, 1.22350406e+04, 1.06293553e+04, 9.24838723e+03,
1274 8.09429377e+03, 7.27582028e+03, 6.47441127e+03, 5.21985266e+03,
1275 4.36279092e+03, 4.00953782e+03, 3.69585190e+03, 3.43405611e+03,
1276 3.18567804e+03, 3.01195379e+03, 2.89123841e+03, 2.68282359e+03,
1277 2.60091022e+03, 2.51301062e+03, 2.43890788e+03, 2.35838231e+03,
1278 2.26256855e+03, 2.21204078e+03, 2.20282902e+03, 2.18205860e+03,
1279 2.15007675e+03, 2.08949483e+03, 2.10732780e+03, 2.09600072e+03,
1280 2.07407783e+03, 2.11741997e+03, 2.08083045e+03, 2.06397688e+03,
1281 2.04765529e+03, 2.05836012e+03, 2.04093663e+03, 1.98334647e+03,
1282 2.01999612e+03, 1.99394914e+03, 1.96972450e+03, 1.88216817e+03,
1283 1.86902307e+03, 1.98290800e+03, 1.94714119e+03, 1.92046621e+03,
1284 1.83796316e+03, 1.87468459e+03, 1.89491779e+03, 1.83110571e+03,
1285 1.75025929e+03, 1.66067524e+03, 1.68052010e+03, 1.67404206e+03,
1286 1.65221787e+03, 1.63380745e+03, 1.61258211e+03, 1.57173282e+03,
1287 1.55635385e+03, 1.59914440e+03, 1.63280915e+03, 1.62416209e+03,
1288 1.55550327e+03, 1.59790786e+03, 1.63913552e+03, 1.62123248e+03,
1289 1.59571147e+03, 1.48508783e+03, 1.60763833e+03, 1.60573267e+03,
1290 1.66286509e+03, 1.56023986e+03, 1.60226461e+03, 1.62178972e+03,
1291 1.63248481e+03, 1.63982132e+03, 1.67350316e+03, 1.62120745e+03,
1292 1.69261497e+03, 1.67835970e+03, 1.71259617e+03, 1.66567572e+03,
1293 1.73107044e+03, 1.60808418e+03, 1.62957233e+03, 1.65949976e+03,
1294 1.62773379e+03, 1.74438786e+03, 1.61948665e+03, 1.83335873e+03,
1295 1.65774501e+03, 1.65605436e+03, 1.72054542e+03, 1.68968657e+03,
1296 1.73787963e+03, 1.74437326e+03, 1.71408015e+03, 1.93871967e+03,
1297 1.87508731e+03, 1.70631906e+03, 1.92219749e+03, 1.72410949e+03,
1298 1.86172638e+03, 1.88692937e+03, 1.77337717e+03, 1.95303579e+03,
1299 1.86292107e+03, 1.87948406e+03, 1.91966097e+03, 1.76238101e+03,
1300 1.59694869e+03, 1.89306746e+03, 1.84068186e+03, 1.86018512e+03,
1301 1.81578862e+03, 1.83413719e+03, 1.80771751e+03, 1.79214601e+03])
1302 elif dense and mode == "upturn":
1303 # Taken from dense run 13591, detector 73, amplifier C07
1304 ptcTurnoff = 86917.0045
1305 rawMeans = np.array([
1306 2.87448603e+01, 3.03861239e+01, 3.20301466e+01, 3.35831624e+01,
1307 3.51161960e+01, 3.69857753e+01, 3.91580507e+01, 4.12179225e+01,
1308 4.36662086e+01, 4.58399375e+01, 4.80202775e+01, 5.10071275e+01,
1309 5.68263968e+01, 5.99352524e+01, 6.34210182e+01, 6.68834309e+01,
1310 7.01195882e+01, 7.43313750e+01, 7.80758357e+01, 8.27309929e+01,
1311 8.73124933e+01, 9.17856382e+01, 9.70086101e+01, 1.02546128e+02,
1312 1.08169091e+02, 1.13738150e+02, 1.20058621e+02, 1.26792703e+02,
1313 1.33422104e+02, 1.40893068e+02, 1.48727555e+02, 1.56662520e+02,
1314 1.65129261e+02, 1.74130948e+02, 1.83878223e+02, 1.93976598e+02,
1315 2.04599993e+02, 2.16044601e+02, 2.27838642e+02, 2.40360862e+02,
1316 2.53772624e+02, 2.67443055e+02, 2.82013487e+02, 2.97705423e+02,
1317 3.14297001e+02, 3.31260825e+02, 3.49758342e+02, 3.68963998e+02,
1318 3.88634613e+02, 4.10112249e+02, 4.32301833e+02, 4.56407219e+02,
1319 4.81690100e+02, 5.08370293e+02, 5.35921852e+02, 5.65828928e+02,
1320 5.96685398e+02, 6.29615188e+02, 6.64802708e+02, 7.00563142e+02,
1321 7.39711995e+02, 7.79679559e+02, 8.22530629e+02, 8.67814522e+02,
1322 9.15951880e+02, 9.65946953e+02, 1.01948611e+03, 1.07504268e+03,
1323 1.13509200e+03, 1.19727942e+03, 1.26351949e+03, 1.33211624e+03,
1324 1.48320209e+03, 1.48384430e+03, 1.56467822e+03, 1.56485206e+03,
1325 1.65060918e+03, 1.65147654e+03, 1.74229201e+03, 1.83706229e+03,
1326 1.93811946e+03, 2.15719262e+03, 2.27546155e+03, 2.50056748e+03,
1327 2.63872700e+03, 2.78379012e+03, 2.93745238e+03, 3.09833186e+03,
1328 3.27013288e+03, 3.44990418e+03, 3.63968250e+03, 3.83921968e+03,
1329 4.04711266e+03, 4.05013387e+03, 4.27266981e+03, 4.50809670e+03,
1330 4.75635569e+03, 5.29310771e+03, 5.58427306e+03, 6.03306708e+03,
1331 6.48160541e+03, 6.92983470e+03, 7.37874615e+03, 7.82619855e+03,
1332 8.27493037e+03, 8.72049208e+03, 9.17227788e+03, 9.62234260e+03,
1333 1.00674503e+04, 1.05166951e+04, 1.09652006e+04, 1.14145457e+04,
1334 1.18581337e+04, 1.23138210e+04, 1.27597933e+04, 1.32094995e+04,
1335 1.36537794e+04, 1.41079990e+04, 1.45579666e+04, 1.50042564e+04,
1336 1.58932106e+04, 1.63527856e+04, 1.67995854e+04, 1.68014549e+04,
1337 1.72456751e+04, 1.72511595e+04, 1.81472850e+04, 1.85967925e+04,
1338 1.90437339e+04, 1.94933795e+04, 1.99423590e+04, 2.03854630e+04,
1339 2.08408610e+04, 2.12909264e+04, 2.17356857e+04, 2.21873924e+04,
1340 2.26346682e+04, 2.30822802e+04, 2.35248689e+04, 2.44292445e+04,
1341 2.53306721e+04, 2.57709779e+04, 2.59292740e+04, 2.63672474e+04,
1342 2.68118979e+04, 2.72586202e+04, 2.76977437e+04, 2.81455545e+04,
1343 2.85840092e+04, 2.90309073e+04, 2.94738200e+04, 2.99007273e+04,
1344 3.03581316e+04, 3.08035397e+04, 3.16820715e+04, 3.21348581e+04,
1345 3.25795035e+04, 3.30160938e+04, 3.34614077e+04, 3.39098464e+04,
1346 3.43488841e+04, 3.47938018e+04, 3.56683528e+04, 3.61120617e+04,
1347 3.65571740e+04, 3.74373798e+04, 3.78795706e+04, 3.83213509e+04,
1348 3.92106205e+04, 3.96436191e+04, 4.00888939e+04, 4.05395713e+04,
1349 4.09729696e+04, 4.13953138e+04, 4.18558141e+04, 4.23098575e+04,
1350 4.27184098e+04, 4.31754813e+04, 4.36191519e+04, 4.45068672e+04,
1351 4.49463419e+04, 4.53858299e+04, 4.58261673e+04, 4.67014085e+04,
1352 4.71515103e+04, 4.75882657e+04, 4.80322253e+04, 4.84586953e+04,
1353 4.89039488e+04, 4.93442503e+04, 4.97561230e+04, 5.02341725e+04,
1354 5.06588581e+04, 5.11035621e+04, 5.19836216e+04, 5.24056394e+04,
1355 5.28686518e+04, 5.33018757e+04, 5.37265598e+04, 5.41807663e+04,
1356 5.46136176e+04, 5.50609130e+04, 5.55007300e+04, 5.59337737e+04,
1357 5.63788843e+04, 5.68094757e+04, 5.72570533e+04, 5.76741866e+04,
1358 5.81383020e+04, 5.85826153e+04, 5.89753856e+04, 5.94617576e+04,
1359 5.99083532e+04, 6.03419978e+04, 6.07815876e+04, 6.11916990e+04,
1360 6.16679074e+04, 6.21070006e+04, 6.25498996e+04, 6.30000329e+04,
1361 6.34432415e+04, 6.38632967e+04, 6.43145751e+04, 6.47608638e+04,
1362 6.52134266e+04, 6.56348895e+04, 6.60841662e+04, 6.65220989e+04,
1363 6.69687269e+04, 6.74171257e+04, 6.78295038e+04, 6.83037417e+04,
1364 6.87381890e+04, 6.96234966e+04, 7.00749883e+04, 7.05130803e+04,
1365 7.09702156e+04, 7.18669367e+04, 7.23008238e+04, 7.27326728e+04,
1366 7.31879639e+04, 7.36444652e+04, 7.45313822e+04, 7.49512933e+04,
1367 7.58422569e+04, 7.63002282e+04, 7.67542279e+04, 7.71971910e+04,
1368 7.75899806e+04, 7.80880043e+04, 7.85207688e+04, 7.89717058e+04,
1369 7.94257076e+04, 7.98485141e+04, 8.03023282e+04, 8.07414358e+04,
1370 8.11910981e+04, 8.16398955e+04, 8.25250712e+04, 8.29401845e+04,
1371 8.34236581e+04, 8.38641888e+04, 8.42971844e+04, 8.47295006e+04,
1372 8.52114910e+04, 8.56328503e+04, 8.60862279e+04, 8.69170045e+04,
1373 8.78165034e+04, 8.82689547e+04, 8.87058177e+04, 8.90804208e+04,
1374 8.95362169e+04, 8.99496410e+04, 9.03236457e+04, 9.06958198e+04,
1375 9.11193888e+04, 9.14557890e+04, 9.17189073e+04, 9.21437093e+04,
1376 9.28449356e+04, 9.31434208e+04, 9.33064667e+04, 9.34994900e+04,
1377 9.37926812e+04, 9.41725477e+04, 9.45383949e+04, 9.46575696e+04,
1378 9.49209096e+04, 9.49952393e+04, 9.50539106e+04, 9.52347786e+04,
1379 9.52460768e+04, 9.54989344e+04, 9.56298553e+04, 9.58490767e+04,
1380 9.62648021e+04, 9.61075892e+04, 9.63538129e+04, 9.63559508e+04,
1381 9.64708846e+04, 9.64756350e+04, 9.66256538e+04, 9.64809810e+04,
1382 9.65366387e+04, 9.68214859e+04, 9.69137722e+04, 9.68210311e+04,
1383 9.71873201e+04, 9.71342102e+04, 9.71078451e+04, 9.71069892e+04,
1384 9.75296912e+04, 9.74999383e+04, 9.73480623e+04, 9.76524037e+04,
1385 9.74981803e+04, 9.76922174e+04, 9.76337785e+04, 9.75835125e+04,
1386 9.75674694e+04, 9.75367570e+04, 9.77438281e+04, 9.76871410e+04,
1387 9.78773702e+04, 9.78321613e+04, 9.77808877e+04, 9.77359422e+04,
1388 9.79278808e+04, 9.79329075e+04, 9.77675254e+04, 9.78952318e+04,
1389 9.77270368e+04, 9.79509533e+04, 9.77760093e+04, 9.80460286e+04,
1390 9.81360499e+04, 9.79637125e+04, 9.79664967e+04, 9.78575509e+04,
1391 9.80556911e+04, 9.81417648e+04, 9.80352945e+04, 9.81329700e+04,
1392 9.81188437e+04, 9.79678779e+04, 9.79598626e+04, 9.80560275e+04,
1393 9.79542087e+04, 9.79987939e+04, 9.81534114e+04, 9.83899105e+04,
1394 9.84065000e+04, 9.82811922e+04, 9.82840840e+04, 9.82784134e+04,
1395 9.82871998e+04, 9.84461381e+04, 9.84682635e+04, 9.85020571e+04,
1396 np.nan, np.nan, np.nan, np.nan,
1397 np.nan, np.nan, np.nan, np.nan,
1398 np.nan, np.nan, np.nan, np.nan,
1399 np.nan, np.nan, np.nan, np.nan])
1400 rawVars = np.array([
1401 4.87069525e+01, 4.96960311e+01, 5.04910053e+01, 5.17128726e+01,
1402 5.25955479e+01, 5.38353690e+01, 5.53191132e+01, 5.66941478e+01,
1403 5.82926522e+01, 5.98938552e+01, 6.12951161e+01, 6.37287578e+01,
1404 6.80636332e+01, 7.04028909e+01, 7.29998462e+01, 7.48586667e+01,
1405 7.66622012e+01, 7.82391455e+01, 7.99899592e+01, 8.21891213e+01,
1406 8.44852817e+01, 8.74729321e+01, 9.05085253e+01, 9.45153523e+01,
1407 9.84325033e+01, 1.02490363e+02, 1.05547104e+02, 1.08782968e+02,
1408 1.12593458e+02, 1.17458820e+02, 1.22086446e+02, 1.27863525e+02,
1409 1.34404768e+02, 1.42189276e+02, 1.48361964e+02, 1.52241417e+02,
1410 1.56903695e+02, 1.63487388e+02, 1.71250175e+02, 1.79776726e+02,
1411 1.87500190e+02, 1.95127335e+02, 2.05237738e+02, 2.17941739e+02,
1412 2.27601893e+02, 2.34445474e+02, 2.46136553e+02, 2.58638437e+02,
1413 2.70612240e+02, 2.88057360e+02, 3.01436607e+02, 3.11174829e+02,
1414 3.27060261e+02, 3.47777215e+02, 3.68419809e+02, 3.80518820e+02,
1415 3.97377177e+02, 4.25381795e+02, 4.42049448e+02, 4.59452324e+02,
1416 4.92530031e+02, 5.14495733e+02, 5.34196108e+02, 5.72228281e+02,
1417 5.92914611e+02, 6.29229419e+02, 6.63254402e+02, 7.10047069e+02,
1418 7.31110299e+02, 7.74635732e+02, 8.06624321e+02, 8.55180585e+02,
1419 9.44435441e+02, 9.43183163e+02, 1.00413513e+03, 9.99872981e+02,
1420 1.05311443e+03, 1.05562621e+03, 1.10199374e+03, 1.15531802e+03,
1421 1.22522414e+03, 1.36520090e+03, 1.42667128e+03, 1.56495960e+03,
1422 1.65397576e+03, 1.74424087e+03, 1.84231293e+03, 1.94740328e+03,
1423 2.03765806e+03, 2.14414450e+03, 2.27212692e+03, 2.38935653e+03,
1424 2.50602833e+03, 2.51661588e+03, 2.64775661e+03, 2.78538088e+03,
1425 2.93987651e+03, 3.26826498e+03, 3.44330599e+03, 3.69978469e+03,
1426 3.97061173e+03, 4.24728849e+03, 4.50971380e+03, 4.77595875e+03,
1427 5.05755732e+03, 5.30327839e+03, 5.58773282e+03, 5.81966058e+03,
1428 6.10932503e+03, 6.36332817e+03, 6.61863136e+03, 6.90433479e+03,
1429 7.13413117e+03, 7.43562156e+03, 7.66582807e+03, 7.94754672e+03,
1430 8.18686206e+03, 8.45779399e+03, 8.71402609e+03, 8.95964156e+03,
1431 9.47591061e+03, 9.76959463e+03, 9.95917651e+03, 9.97584309e+03,
1432 1.02555717e+04, 1.02417814e+04, 1.07674493e+04, 1.09981921e+04,
1433 1.12352859e+04, 1.15551940e+04, 1.17333125e+04, 1.19690736e+04,
1434 1.22534101e+04, 1.24640828e+04, 1.27500496e+04, 1.29625045e+04,
1435 1.32703257e+04, 1.34926746e+04, 1.37251524e+04, 1.42302648e+04,
1436 1.46793658e+04, 1.49722647e+04, 1.49709034e+04, 1.52549107e+04,
1437 1.55088982e+04, 1.57314736e+04, 1.59816003e+04, 1.61640169e+04,
1438 1.64548981e+04, 1.66413940e+04, 1.68686050e+04, 1.71125336e+04,
1439 1.73511674e+04, 1.75817535e+04, 1.80470011e+04, 1.82624491e+04,
1440 1.84524739e+04, 1.87019552e+04, 1.89575762e+04, 1.91930866e+04,
1441 1.94004074e+04, 1.96460005e+04, 2.00479314e+04, 2.02955099e+04,
1442 2.04822881e+04, 2.09531956e+04, 2.11697303e+04, 2.13633602e+04,
1443 2.18346507e+04, 2.19539919e+04, 2.22252821e+04, 2.25155821e+04,
1444 2.26702123e+04, 2.28414558e+04, 2.30830649e+04, 2.32726468e+04,
1445 2.34988786e+04, 2.37395021e+04, 2.39101878e+04, 2.43317884e+04,
1446 2.45771060e+04, 2.47054420e+04, 2.49622825e+04, 2.52797662e+04,
1447 2.55292494e+04, 2.57138336e+04, 2.59366428e+04, 2.61122036e+04,
1448 2.63896695e+04, 2.64562386e+04, 2.66907602e+04, 2.69102279e+04,
1449 2.71833821e+04, 2.73303887e+04, 2.77661838e+04, 2.79006930e+04,
1450 2.81874904e+04, 2.83607526e+04, 2.86045106e+04, 2.87425416e+04,
1451 2.89632711e+04, 2.91293885e+04, 2.93514145e+04, 2.96850582e+04,
1452 2.98715928e+04, 3.01274873e+04, 3.03033141e+04, 3.04572121e+04,
1453 3.07470469e+04, 3.10501508e+04, 3.11450218e+04, 3.14122871e+04,
1454 3.16022955e+04, 3.18325755e+04, 3.21339141e+04, 3.23047828e+04,
1455 3.24219992e+04, 3.28022196e+04, 3.30193533e+04, 3.32907509e+04,
1456 3.34017470e+04, 3.36009585e+04, 3.39733107e+04, 3.40535547e+04,
1457 3.42458795e+04, 3.44664410e+04, 3.47643491e+04, 3.50165080e+04,
1458 3.51727941e+04, 3.53854796e+04, 3.55711407e+04, 3.58190707e+04,
1459 3.60454029e+04, 3.63969548e+04, 3.66329292e+04, 3.68771986e+04,
1460 3.71032547e+04, 3.73983989e+04, 3.76425541e+04, 3.79247481e+04,
1461 3.80882104e+04, 3.82317170e+04, 3.86471187e+04, 3.89086176e+04,
1462 3.92339037e+04, 3.95436246e+04, 3.96460919e+04, 3.98028414e+04,
1463 3.99125771e+04, 4.01715067e+04, 4.03722901e+04, 4.05626968e+04,
1464 4.06933838e+04, 4.10184964e+04, 4.11922744e+04, 4.13557454e+04,
1465 4.16157584e+04, 4.16356931e+04, 4.21157583e+04, 4.21816345e+04,
1466 4.24543184e+04, 4.26313857e+04, 4.27797954e+04, 4.29586701e+04,
1467 4.31317246e+04, 4.31196229e+04, 4.30508028e+04, 4.29439940e+04,
1468 4.14814510e+04, 4.17104998e+04, 4.12950588e+04, 4.00762620e+04,
1469 3.95745952e+04, 3.79603760e+04, 3.68764412e+04, 3.59324071e+04,
1470 3.41774826e+04, 3.35146378e+04, 3.01416949e+04, 3.10962443e+04,
1471 2.93723225e+04, 2.88267934e+04, 2.93057515e+04, 2.78885387e+04,
1472 2.97481790e+04, 2.89003096e+04, 2.98475325e+04, 3.15227067e+04,
1473 3.15157345e+04, 3.32593077e+04, 3.30733852e+04, 3.37623662e+04,
1474 3.58784503e+04, 3.75160267e+04, 3.82803313e+04, 3.89001912e+04,
1475 4.17283047e+04, 4.20086699e+04, 4.22993774e+04, 4.34867653e+04,
1476 4.17054368e+04, 4.52190044e+04, 4.55586401e+04, 4.39034690e+04,
1477 4.49939183e+04, 4.75700720e+04, 4.78978238e+04, 4.62120749e+04,
1478 4.85317658e+04, 4.97305999e+04, 4.70691830e+04, 4.77667215e+04,
1479 5.19257836e+04, 5.01885056e+04, 4.83671721e+04, 5.21924342e+04,
1480 5.10329762e+04, 5.25552111e+04, 5.17040972e+04, 5.11958488e+04,
1481 5.19165668e+04, 4.88842210e+04, 5.17286013e+04, 5.13182361e+04,
1482 5.16342048e+04, 5.17850241e+04, 5.16475818e+04, 5.00165868e+04,
1483 5.19391672e+04, 5.21771011e+04, 5.01633917e+04, 5.19270231e+04,
1484 4.93839429e+04, 4.96516804e+04, 4.93706114e+04, 5.25025570e+04,
1485 5.43045043e+04, 5.27477605e+04, 5.23609667e+04, 4.89296194e+04,
1486 5.26232764e+04, 5.24395882e+04, 4.90790820e+04, 5.19268918e+04,
1487 5.21608822e+04, 4.89292620e+04, 4.86074588e+04, 4.93274381e+04,
1488 4.84901815e+04, 4.91868029e+04, 5.25082453e+04, 5.44279458e+04,
1489 5.55797293e+04, 5.20003094e+04, 5.19304424e+04, 5.17391458e+04,
1490 5.24042964e+04, 5.53566164e+04, 5.53202737e+04, 5.58931187e+04,
1491 np.nan, np.nan, np.nan, np.nan,
1492 np.nan, np.nan, np.nan, np.nan,
1493 np.nan, np.nan, np.nan, np.nan,
1494 np.nan, np.nan, np.nan, np.nan])
1495 elif dense and mode == "dip":
1496 # Taken from dense run 13591, detector 46, amplifier C16
1497 ptcTurnoff = 78592.643
1498 rawMeans = np.array(
1499 [3.46319253e+01, 3.66430301e+01, 3.86622690e+01, 4.05725802e+01,
1500 4.25802432e+01, 4.40269809e+01, 4.80275071e+01, 5.05005628e+01,
1501 5.24638704e+01, 5.51726716e+01, 5.80431294e+01, 6.18363693e+01,
1502 6.76872491e+01, 7.54744430e+01, 7.59445874e+01, 8.07200670e+01,
1503 8.39801977e+01, 8.89822266e+01, 9.34165914e+01, 1.00259640e+02,
1504 1.04115753e+02, 1.09746401e+02, 1.16495426e+02, 1.24702365e+02,
1505 1.29617918e+02, 1.38517235e+02, 1.44598282e+02, 1.55474182e+02,
1506 1.60372893e+02, 1.68952583e+02, 1.79169853e+02, 1.87803850e+02,
1507 1.97901901e+02, 2.12236200e+02, 2.20703858e+02, 2.33721460e+02,
1508 2.45632287e+02, 2.60078861e+02, 2.73309812e+02, 2.91303550e+02,
1509 3.08138900e+02, 3.20634527e+02, 3.39157572e+02, 3.61285287e+02,
1510 3.77306857e+02, 3.97532592e+02, 4.19725123e+02, 4.42637799e+02,
1511 4.66432222e+02, 4.92760774e+02, 5.18439719e+02, 5.49043359e+02,
1512 5.80725784e+02, 6.10607872e+02, 6.42130865e+02, 6.78015970e+02,
1513 7.19634201e+02, 7.56125967e+02, 7.97647549e+02, 8.44250515e+02,
1514 8.88164221e+02, 9.35554605e+02, 9.87551014e+02, 1.04304478e+03,
1515 1.09859274e+03, 1.15934514e+03, 1.22290957e+03, 1.28928061e+03,
1516 1.36205339e+03, 1.43517932e+03, 1.51527821e+03, 1.59829513e+03,
1517 1.77964089e+03, 1.78170273e+03, 1.87682761e+03, 1.87684189e+03,
1518 1.98075997e+03, 1.98113130e+03, 2.08945214e+03, 2.20305152e+03,
1519 2.32556464e+03, 2.58962409e+03, 2.72814882e+03, 2.99794092e+03,
1520 3.16447505e+03, 3.33946592e+03, 3.52147949e+03, 3.71394579e+03,
1521 3.91907040e+03, 4.13438382e+03, 4.36189594e+03, 4.60043753e+03,
1522 4.85130253e+03, 4.85473652e+03, 5.12061926e+03, 5.40324180e+03,
1523 5.70061253e+03, 6.34723550e+03, 6.69436828e+03, 7.23257375e+03,
1524 7.76958269e+03, 8.30697359e+03, 8.84549436e+03, 9.38149894e+03,
1525 9.92214412e+03, 1.04540863e+04, 1.09984280e+04, 1.15336125e+04,
1526 1.20730516e+04, 1.26066598e+04, 1.31475457e+04, 1.36835704e+04,
1527 1.42142220e+04, 1.47607783e+04, 1.52995772e+04, 1.58349683e+04,
1528 1.63699779e+04, 1.69169118e+04, 1.74527183e+04, 1.79882677e+04,
1529 1.90590055e+04, 1.96042099e+04, 2.01412931e+04, 2.01415525e+04,
1530 2.06773002e+04, 2.06836599e+04, 2.17563308e+04, 2.22945949e+04,
1531 2.28326494e+04, 2.33730224e+04, 2.39083711e+04, 2.44415981e+04,
1532 2.49887745e+04, 2.55254849e+04, 2.60582748e+04, 2.66026296e+04,
1533 2.71388848e+04, 2.76745959e+04, 2.82098429e+04, 2.92893984e+04,
1534 3.03685478e+04, 3.08997866e+04, 3.10729575e+04, 3.16013527e+04,
1535 3.21337166e+04, 3.26668783e+04, 3.31930745e+04, 3.37295906e+04,
1536 3.42575950e+04, 3.47930111e+04, 3.53194913e+04, 3.58360666e+04,
1537 3.63796428e+04, 3.69119003e+04, 3.79618999e+04, 3.85046991e+04,
1538 3.90341729e+04, 3.95622456e+04, 4.00906725e+04, 4.06248524e+04,
1539 4.11506714e+04, 4.16820728e+04, 4.27281690e+04, 4.32583738e+04,
1540 4.37923105e+04, 4.48436280e+04, 4.53713042e+04, 4.58983070e+04,
1541 4.69589412e+04, 4.74759399e+04, 4.80036320e+04, 4.85414573e+04,
1542 4.90619668e+04, 4.95708602e+04, 5.01124419e+04, 5.06550432e+04,
1543 5.11459970e+04, 5.16864720e+04, 5.22155963e+04, 5.32732837e+04,
1544 5.37950395e+04, 5.43202717e+04, 5.48449050e+04, 5.58936896e+04,
1545 5.64268047e+04, 5.69454503e+04, 5.74788533e+04, 5.79886165e+04,
1546 5.85227316e+04, 5.90467563e+04, 5.95529633e+04, 6.01107425e+04,
1547 6.06190504e+04, 6.11482815e+04, 6.22041090e+04, 6.27192672e+04,
1548 6.32698650e+04, 6.37882800e+04, 6.43035282e+04, 6.48401842e+04,
1549 6.53646656e+04, 6.59030142e+04, 6.64333556e+04, 6.69479267e+04,
1550 6.74848468e+04, 6.80079972e+04, 6.85445388e+04, 6.90509171e+04,
1551 6.96092229e+04, 7.01385610e+04, 7.06212128e+04, 7.11939523e+04,
1552 7.17266360e+04, 7.22471223e+04, 7.27780652e+04, 7.32761803e+04,
1553 7.38361226e+04, 7.43656998e+04, 7.48934046e+04, 7.54352821e+04,
1554 7.59644966e+04, 7.64724502e+04, 7.70119423e+04, 7.75439221e+04,
1555 7.80842181e+04, 7.85926430e+04, 7.91251970e+04, 7.96491204e+04,
1556 8.01869810e+04, 8.07146073e+04, 8.12202954e+04, 8.17785695e+04,
1557 8.22963087e+04, 8.33550384e+04, 8.38994212e+04, 8.44155447e+04,
1558 8.49563789e+04, 8.60281829e+04, 8.65433251e+04, 8.70627645e+04,
1559 8.76007341e+04, 8.81511125e+04, 8.92018550e+04, 8.97044207e+04,
1560 9.07592037e+04, 9.13032564e+04, 9.18479184e+04, 9.23763279e+04,
1561 9.28541040e+04, 9.34276276e+04, 9.39508203e+04, 9.44807722e+04,
1562 9.50201270e+04, 9.55260238e+04, 9.60584060e+04, 9.65900977e+04,
1563 9.71082260e+04, 9.76499634e+04, 9.86927409e+04, 9.92001749e+04,
1564 9.97605950e+04, 1.00281826e+05, 1.00799323e+05, 1.01317520e+05,
1565 1.01880214e+05, 1.02375482e+05, 1.02921781e+05, 1.03914664e+05,
1566 1.04996919e+05, 1.05531177e+05, 1.06045662e+05, 1.06553960e+05,
1567 1.07074502e+05, 1.07620081e+05, 1.08135030e+05, 1.08625699e+05,
1568 1.09176443e+05, 1.09713812e+05, 1.10216327e+05, 1.10733831e+05,
1569 1.11710810e+05, 1.12193799e+05, 1.12690561e+05, 1.13133767e+05,
1570 1.13607554e+05, 1.14479014e+05, 1.14907269e+05, 1.15294108e+05,
1571 1.15680838e+05, 1.16050756e+05, 1.16395663e+05, 1.16738698e+05,
1572 1.17036744e+05, 1.17606634e+05, 1.17864854e+05, 1.18107937e+05,
1573 1.18338933e+05, 1.18484492e+05, 1.18751107e+05, 1.18925783e+05,
1574 1.19127596e+05, 1.19257553e+05, 1.19452513e+05, 1.19608706e+05,
1575 1.19753398e+05, 1.19883813e+05, 1.20021670e+05, 1.20155507e+05,
1576 1.20406612e+05, 1.20605600e+05, 1.20753078e+05, 1.20866466e+05,
1577 np.nan, np.nan, np.nan, np.nan,
1578 np.nan, np.nan, np.nan, np.nan,
1579 np.nan, np.nan, np.nan, np.nan,
1580 np.nan, np.nan, np.nan, np.nan,
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 rawVars = np.array(
1594 [3.70611558e+01, 3.83737395e+01, 3.99468861e+01, 4.10014338e+01,
1595 4.23251266e+01, 4.33678155e+01, 4.59071461e+01, 4.73626968e+01,
1596 4.87148063e+01, 5.03835098e+01, 5.25225011e+01, 5.49763960e+01,
1597 5.89144406e+01, 6.46901096e+01, 6.46921274e+01, 6.77000641e+01,
1598 7.03062675e+01, 7.37864491e+01, 7.78022510e+01, 8.44978037e+01,
1599 8.74723267e+01, 9.13765683e+01, 9.51046462e+01, 9.90038919e+01,
1600 1.01309767e+02, 1.06498820e+02, 1.10600587e+02, 1.18170347e+02,
1601 1.21408878e+02, 1.28214192e+02, 1.36647653e+02, 1.42148979e+02,
1602 1.48491678e+02, 1.59805162e+02, 1.65823057e+02, 1.73305507e+02,
1603 1.80522937e+02, 1.87449934e+02, 1.96245721e+02, 2.08352732e+02,
1604 2.21201432e+02, 2.32523118e+02, 2.44009905e+02, 2.56991468e+02,
1605 2.68047397e+02, 2.79329180e+02, 2.97712914e+02, 3.15304298e+02,
1606 3.27789122e+02, 3.44980267e+02, 3.61446379e+02, 3.84494985e+02,
1607 4.05677044e+02, 4.22749240e+02, 4.44709272e+02, 4.77813761e+02,
1608 5.01815280e+02, 5.21252820e+02, 5.49793847e+02, 5.80608964e+02,
1609 6.10172377e+02, 6.44282320e+02, 6.76618722e+02, 7.14200019e+02,
1610 7.52150585e+02, 7.90093939e+02, 8.43584018e+02, 8.74257958e+02,
1611 9.25137165e+02, 9.77217130e+02, 1.02268591e+03, 1.07911844e+03,
1612 1.20579007e+03, 1.21094193e+03, 1.26536689e+03, 1.26783114e+03,
1613 1.33667935e+03, 1.34071853e+03, 1.40959965e+03, 1.49236868e+03,
1614 1.56214455e+03, 1.73911080e+03, 1.84452009e+03, 2.01282493e+03,
1615 2.11914383e+03, 2.23859893e+03, 2.35101284e+03, 2.48665441e+03,
1616 2.61201878e+03, 2.74350197e+03, 2.89732268e+03, 3.05252644e+03,
1617 3.22199981e+03, 3.22767156e+03, 3.38954315e+03, 3.58149621e+03,
1618 3.76614023e+03, 4.19955412e+03, 4.39939398e+03, 4.74116692e+03,
1619 5.08774295e+03, 5.43362489e+03, 5.76587686e+03, 6.09147076e+03,
1620 6.46434875e+03, 6.77118428e+03, 7.10758829e+03, 7.41292668e+03,
1621 7.75391200e+03, 8.07133480e+03, 8.40331959e+03, 8.71723040e+03,
1622 9.03873483e+03, 9.36871022e+03, 9.69206829e+03, 9.99510413e+03,
1623 1.03183250e+04, 1.06519986e+04, 1.09717629e+04, 1.12984284e+04,
1624 1.19017371e+04, 1.22009054e+04, 1.25073348e+04, 1.24828917e+04,
1625 1.28123892e+04, 1.27965364e+04, 1.34024560e+04, 1.36798307e+04,
1626 1.40186807e+04, 1.43485421e+04, 1.45916270e+04, 1.48802247e+04,
1627 1.51990105e+04, 1.54775801e+04, 1.57746393e+04, 1.60211115e+04,
1628 1.63459546e+04, 1.66499888e+04, 1.68983125e+04, 1.74427484e+04,
1629 1.80456894e+04, 1.82652348e+04, 1.83690177e+04, 1.86208031e+04,
1630 1.89412363e+04, 1.91602864e+04, 1.94785697e+04, 1.97091334e+04,
1631 1.99827654e+04, 2.02492520e+04, 2.04397095e+04, 2.07912874e+04,
1632 2.09363768e+04, 2.12446667e+04, 2.17637411e+04, 2.19817593e+04,
1633 2.22395694e+04, 2.24653630e+04, 2.27254307e+04, 2.29678916e+04,
1634 2.32155716e+04, 2.34915971e+04, 2.39308788e+04, 2.41386350e+04,
1635 2.43300723e+04, 2.47776731e+04, 2.49855450e+04, 2.52822560e+04,
1636 2.57310565e+04, 2.58705668e+04, 2.61365827e+04, 2.63745002e+04,
1637 2.64761919e+04, 2.67763879e+04, 2.69546269e+04, 2.72247330e+04,
1638 2.73854794e+04, 2.75964799e+04, 2.78536768e+04, 2.83219440e+04,
1639 2.84473603e+04, 2.86066766e+04, 2.88858064e+04, 2.93640042e+04,
1640 2.95802005e+04, 2.97953000e+04, 2.99784114e+04, 3.01818213e+04,
1641 3.04537120e+04, 3.07186903e+04, 3.09159639e+04, 3.11340544e+04,
1642 3.13467981e+04, 3.16593731e+04, 3.19829978e+04, 3.22855092e+04,
1643 3.25921574e+04, 3.27154499e+04, 3.28698071e+04, 3.31481419e+04,
1644 3.34606399e+04, 3.37260080e+04, 3.38331508e+04, 3.40882291e+04,
1645 3.43298166e+04, 3.44626343e+04, 3.47352389e+04, 3.48844453e+04,
1646 3.50976243e+04, 3.53422532e+04, 3.54703155e+04, 3.57850397e+04,
1647 3.60218788e+04, 3.61282209e+04, 3.63718905e+04, 3.64159312e+04,
1648 3.67264583e+04, 3.68810487e+04, 3.70236104e+04, 3.73025531e+04,
1649 3.74696213e+04, 3.74774745e+04, 3.76885954e+04, 3.77461428e+04,
1650 3.77311980e+04, 3.76449769e+04, 3.71874494e+04, 3.67403027e+04,
1651 3.58397731e+04, 3.44249565e+04, 3.25971681e+04, 3.12036933e+04,
1652 2.94985871e+04, 2.71719366e+04, 2.69809068e+04, 2.72483125e+04,
1653 2.83267080e+04, 3.15350383e+04, 3.33307911e+04, 3.48927220e+04,
1654 3.65827728e+04, 3.79316518e+04, 3.97114600e+04, 4.02038182e+04,
1655 4.10252529e+04, 4.14747301e+04, 4.16607368e+04, 4.18321712e+04,
1656 4.18311337e+04, 4.21298732e+04, 4.21384783e+04, 4.21559876e+04,
1657 4.23156351e+04, 4.22011377e+04, 4.22592203e+04, 4.20913479e+04,
1658 4.15029042e+04, 4.09470822e+04, 3.85767751e+04, 3.64665853e+04,
1659 3.45138148e+04, 3.21709915e+04, 2.96629755e+04, 2.69203438e+04,
1660 2.43537600e+04, 2.23428644e+04, 2.01581545e+04, 1.62544599e+04,
1661 1.34824506e+04, 1.18721963e+04, 1.05452615e+04, 9.46843007e+03,
1662 8.23841467e+03, 7.23997272e+03, 6.36586857e+03, 5.65708162e+03,
1663 4.99963764e+03, 4.48251363e+03, 4.09078951e+03, 3.72817220e+03,
1664 3.21067198e+03, 3.03262162e+03, 2.89743032e+03, 2.77343484e+03,
1665 2.69667301e+03, 2.60188277e+03, 2.55172731e+03, 2.52540578e+03,
1666 2.56130915e+03, 2.52293303e+03, 2.50717444e+03, 2.51044664e+03,
1667 2.51531215e+03, 2.53768779e+03, 2.56201926e+03, 2.56217908e+03,
1668 2.60528686e+03, 2.61531849e+03, 2.62971142e+03, 2.66896083e+03,
1669 2.69706371e+03, 2.73927492e+03, 2.74999442e+03, 2.75180096e+03,
1670 2.78694836e+03, 2.80704605e+03, 2.83222240e+03, 2.86654398e+03,
1671 2.90678852e+03, 2.95139745e+03, 2.95942911e+03, 3.00791154e+03,
1672 np.nan, np.nan, np.nan, np.nan,
1673 np.nan, np.nan, np.nan, np.nan,
1674 np.nan, np.nan, np.nan, np.nan,
1675 np.nan, np.nan, np.nan, np.nan,
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 elif not dense and mode == "normal":
1689 # Taken from B protocol run 13557, detector 94, amplifier C02
1690 ptcTurnoff = 92173.9596
1691 rawMeans = np.array([
1692 7.35242203e+01, 9.29532799e+01, 1.12149391e+02, 1.39776279e+02,
1693 1.74220020e+02, 2.15692281e+02, 2.68814926e+02, 3.34446868e+02,
1694 4.14359931e+02, 5.14691775e+02, 6.40642848e+02, 7.95596873e+02,
1695 9.90753280e+02, 1.22885224e+03, 1.52684706e+03, 1.89907469e+03,
1696 2.35701770e+03, 2.93106806e+03, 3.59466174e+03, 4.46720318e+03,
1697 5.55232373e+03, 6.90091293e+03, 8.57660238e+03, 1.06583769e+04,
1698 1.32457052e+04, 1.64618675e+04, 2.04605037e+04, 2.54301936e+04,
1699 3.15926481e+04, 3.87784321e+04, 4.81318315e+04, 5.97145570e+04,
1700 7.41859291e+04, 9.21739596e+04, 1.08484387e+05, 1.10456942e+05,
1701 1.10677645e+05, 1.10691134e+05, 1.10693202e+05, 1.10692292e+05,
1702 1.10699619e+05, 1.10703407e+05, 1.10704764e+05])
1703 rawVars = np.array([
1704 71.66098099, 85.85187266, 100.07444552, 121.59045422,
1705 143.54998243, 171.39262057, 210.51220342, 257.40796789,
1706 313.11677494, 381.91333248, 476.46542075, 583.72632638,
1707 729.26397749, 888.46194891, 1101.58606157, 1363.39263745,
1708 1686.28916615, 2096.14920835, 2552.12897667, 3159.70329711,
1709 3894.29254595, 4800.37079501, 5940.17760433, 7310.2253724,
1710 9015.14374818, 11022.81586492, 13509.18049715, 16391.89059679,
1711 19905.15871788, 23628.84875886, 28128.21785629, 33476.91933085,
1712 40023.07406229, 45198.48421179, 3390.76561947, 1601.38678043,
1713 1890.12715102, 1805.34862035, 1904.84156084, 1903.84859699,
1714 1857.15885789, 1889.45649514, 1892.01672711])
1715 elif not dense and mode == "upturn":
1716 # Taken from B protocol run 13557, detector 73, amplifier C07
1717 ptcTurnoff = 71832.2986
1718 rawMeans = np.array([
1719 5.65607783e+01, 7.04062631e+01, 8.74047057e+01, 1.08812996e+02,
1720 1.35333046e+02, 1.67636667e+02, 2.08445200e+02, 2.59202618e+02,
1721 3.21602277e+02, 3.99545078e+02, 4.96963648e+02, 6.17791959e+02,
1722 7.67578708e+02, 9.54040040e+02, 1.18587264e+03, 1.47297327e+03,
1723 1.83109922e+03, 2.27527491e+03, 2.79309339e+03, 3.47193365e+03,
1724 4.31520802e+03, 5.36244611e+03, 6.66482002e+03, 8.28357528e+03,
1725 1.02962387e+04, 1.27972565e+04, 1.59069356e+04, 1.97746199e+04,
1726 2.45737678e+04, 3.01873089e+04, 3.75075197e+04, 4.65677579e+04,
1727 5.77977537e+04, 7.18322986e+04, 8.92553708e+04, 9.74408608e+04,
1728 np.nan, np.nan, np.nan, np.nan,
1729 np.nan, np.nan, np.nan])
1730 rawVars = np.array([
1731 68.2700079, 76.51661413, 84.52771312, 98.70960506,
1732 113.95644441, 137.2544902, 158.39159813, 190.7985178,
1733 229.92447148, 279.52534113, 338.90663196, 414.97072284,
1734 510.16012626, 622.00951125, 763.81268011, 938.07098006,
1735 1149.75983481, 1424.88125193, 1745.36382679, 2165.89927287,
1736 2666.43505016, 3303.63407541, 4094.4066631, 5072.7831761,
1737 6238.35971003, 7697.01580574, 9479.41363292, 11654.65158713,
1738 14268.54471588, 17316.88016853, 21012.8242229, 25275.74644538,
1739 30725.05799423, 37363.24467221, 39830.3337401, 48083.26241611,
1740 np.nan, np.nan, np.nan, np.nan,
1741 np.nan, np.nan, np.nan])
1742 elif not dense and mode == "dip":
1743 # Taken from B protocol run 13557, detector 46, amplifier C16
1744 ptcTurnoff = 87557.8289
1745 rawMeans = np.array(
1746 [6.94187281e+01, 8.92438988e+01, 1.05958756e+02, 1.32423251e+02,
1747 1.64877564e+02, 2.04367731e+02, 2.55076247e+02, 3.16940500e+02,
1748 3.92525299e+02, 4.87631833e+02, 6.06783494e+02, 7.53540982e+02,
1749 9.39742534e+02, 1.16367754e+03, 1.44670172e+03, 1.80047945e+03,
1750 2.23357272e+03, 2.77872101e+03, 3.40646845e+03, 4.23306945e+03,
1751 5.26085005e+03, 6.53969254e+03, 8.12914423e+03, 1.01016373e+04,
1752 1.25546410e+04, 1.56072062e+04, 1.93987924e+04, 2.41153677e+04,
1753 2.99669024e+04, 3.67956267e+04, 4.56879445e+04, 5.66901053e+04,
1754 7.04360489e+04, 8.75578289e+04, 1.08738204e+05, np.nan,
1755 np.nan, np.nan, np.nan, np.nan,
1756 np.nan, np.nan, np.nan])
1757 rawVars = np.array(
1758 [61.7553328, 75.60175792, 88.98931208, 106.95977,
1759 129.78637495, 153.5130247, 192.25182776, 233.4904232,
1760 287.02595043, 349.57554198, 428.71515892, 528.0987701,
1761 656.97011401, 820.88213784, 1003.62289116, 1243.67283887,
1762 1543.24210179, 1905.00050382, 2321.63329694, 2889.08652787,
1763 3574.52610263, 4393.02299998, 5427.50087472, 6691.62708604,
1764 8226.42941205, 10104.75767742, 12365.56291744, 15029.66357377,
1765 18233.5785582, 21684.66746226, 25811.97832361, 30686.30643311,
1766 36834.73747467, 41993.20346722, 30079.64884394, np.nan,
1767 np.nan, np.nan, np.nan, np.nan,
1768 np.nan, np.nan, np.nan])
1769 else:
1770 raise RuntimeError("Illegal mode")
1772 return rawMeans, rawVars, ptcTurnoff
1775class MeasurePhotonTransferCurveDatasetTestCase(lsst.utils.tests.TestCase):
1776 def setUp(self):
1777 self.ptcData = PhotonTransferCurveDataset(["C00", "C01"], " ")
1778 self.ptcData.inputExpIdPairs = {
1779 "C00": [(123, 234), (345, 456), (567, 678)],
1780 "C01": [(123, 234), (345, 456), (567, 678)],
1781 }
1783 def test_generalBehaviour(self):
1784 test = PhotonTransferCurveDataset(["C00", "C01"], " ")
1785 test.inputExpIdPairs = {
1786 "C00": [(123, 234), (345, 456), (567, 678)],
1787 "C01": [(123, 234), (345, 456), (567, 678)],
1788 }
1791class TestMemory(lsst.utils.tests.MemoryTestCase):
1792 pass
1795def setup_module(module):
1796 lsst.utils.tests.init()
1799if __name__ == "__main__": 1799 ↛ 1800line 1799 didn't jump to line 1800 because the condition on line 1799 was never true
1800 lsst.utils.tests.init()
1801 unittest.main()