Coverage for tests / test_ptc.py: 6%
568 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-17 09:35 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-17 09:35 +0000
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
32import warnings
34import lsst.log
35import lsst.utils
36import lsst.utils.tests
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
43from lsst.pipe.base import InMemoryDatasetHandle
46class FakeCamera(list):
47 def getName(self):
48 return "FakeCam"
51class PretendRef:
52 "A class to act as a mock exposure reference"
54 def __init__(self, exposure):
55 self.exp = exposure
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
68class MeasurePhotonTransferCurveTaskTestCase(lsst.utils.tests.TestCase):
69 """A test case for the PTC tasks."""
71 def setUp(self):
72 self.defaultConfigExtract = (
73 cpPipe.ptc.PhotonTransferCurveExtractPairTask.ConfigClass()
74 )
75 self.defaultTaskExtract = cpPipe.ptc.PhotonTransferCurveExtractTask(
76 config=self.defaultConfigExtract
77 )
79 self.defaultConfigSolve = cpPipe.ptc.PhotonTransferCurveSolveTask.ConfigClass()
80 self.defaultTaskSolve = cpPipe.ptc.PhotonTransferCurveSolveTask(
81 config=self.defaultConfigSolve
82 )
84 self.flatMean = 2000
85 self.readNoiseAdu = 10
86 mockImageConfig = isrMock.IsrMock.ConfigClass()
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
93 self.flatExp1 = isrMock.FlatMock(config=mockImageConfig).run()
94 self.flatExp2 = self.flatExp1.clone()
95 (shapeY, shapeX) = self.flatExp1.getDimensions()
97 self.flatWidth = np.sqrt(self.flatMean) + self.readNoiseAdu
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))
104 self.flatExp1.image.array[:] = flatData1
105 self.flatExp2.image.array[:] = flatData2
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))
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 )
135 def test_covAstier(self):
136 """Test to check getCovariancesAstier
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),
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)
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
168 inputGain = self.gain
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'
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)
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)
226 pdCalib1 = PhotodiodeCalib(timeSamples=timeSamples, currentSamples=currentSamples1)
227 pdCalib1.currentScale = -1.0
228 pdCalib1.integrationMethod = "CHARGE_SUM"
230 pdCalib2 = PhotodiodeCalib(timeSamples=timeSamples, currentSamples=currentSamples2)
231 pdCalib2.currentScale = -1.0
232 pdCalib2.integrationMethod = "CHARGE_SUM"
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
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)
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])
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
272 # Reorganize the outputCovariances so we can confirm they come
273 # out sorted afterwards.
274 outputCovariancesRev = outputCovariances[::-1]
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 }
291 for fitType in ["FULLCOVARIANCE", "FULLCOVARIANCE_NO_B"]:
292 solveConfig.ptcFitType = fitType
293 solveTask = cpPipe.ptc.PhotonTransferCurveSolveTask(config=solveConfig)
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 )
301 ptc = resultsSolve.outputPtcDataset
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())
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])
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])
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 )
408 mask = ptc.getGoodPoints(amp)
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)
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)
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)
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)
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 )
441 goodAmps = ptc.getGoodAmps()
442 self.assertEqual(goodAmps, self.ampNames)
444 # Check that every possibly modified field has the same length.
445 covShape = None
446 covSqrtShape = None
447 covModelShape = None
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)
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)
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)
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
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 )
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 ]
533 solveTask = cpPipe.ptc.PhotonTransferCurveSolveTask(config=configSolve)
535 if fitType == "EXPAPPROXIMATION":
536 localDataset = solveTask.fitPtc(localDataset)
537 else:
538 localDataset = solveTask.fitDataFullCovariance(localDataset)
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 )
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)
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)
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
588 configSolve = copy.copy(self.defaultConfigSolve)
589 configSolve.doModelPtcRolloff = doModelPtcRolloff
590 configSolve.doFitBootstrap = False
592 solveTask = cpPipe.ptc.PhotonTransferCurveSolveTask(config=configSolve)
594 initialFitDataset = solveTask.fitPtc(dataset, computePtcTurnoff=True)
596 # Model the PTC rolloff
597 if doModelPtcRolloff:
598 initialFitDataset = solveTask.fitPtcRolloff(initialFitDataset)
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 )
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 )
653 # If that passes set the maxMean to the PTC Rolloff
654 maxMean = solvedDataset.ptcRolloff[ampName]
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 )
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 )
677 def test_ptcFit(self):
678 for fitType in ["EXPAPPROXIMATION"]:
679 self.ptcFitAndCheckPtc(
680 fitType=fitType
681 )
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)
690 self.assertLess(self.flatWidth - np.sqrt(varDiff), 1)
691 self.assertLess(self.flatMean - mu, 1)
693 def test_meanVarMeasurementWithNans(self):
694 task = self.defaultTaskExtract
696 flatExp1 = self.flatExp1.clone()
697 flatExp2 = self.flatExp2.clone()
699 flatExp1.image.array[20:30, :] = np.nan
700 flatExp2.image.array[20:30, :] = np.nan
702 im1Area, im2Area, imStatsCtrl, mu1, mu2 = task.getImageAreasMasksStats(
703 flatExp1, flatExp2
704 )
705 mu, varDiff, _, _ = task.measureMeanVarCov(im1Area, im2Area, imStatsCtrl, mu1, mu2)
707 expectedMu1 = np.nanmean(flatExp1.image.array)
708 expectedMu2 = np.nanmean(flatExp2.image.array)
709 expectedMu = 0.5 * (expectedMu1 + expectedMu2)
711 # Now the variance of the difference. First, create the diff image.
712 im1 = flatExp1.maskedImage
713 im2 = flatExp2.maskedImage
715 temp = im2.clone()
716 temp *= expectedMu1
717 diffIm = im1.clone()
718 diffIm *= expectedMu2
719 diffIm -= temp
720 diffIm /= expectedMu
722 # Divide by two as it is what measureMeanVarCov returns
723 # (variance of difference)
724 expectedVar = 0.5 * np.nanvar(diffIm.image.array)
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)
731 def test_meanVarMeasurementAllNan(self):
732 task = self.defaultTaskExtract
733 flatExp1 = self.flatExp1.clone()
734 flatExp2 = self.flatExp2.clone()
736 flatExp1.image.array[:, :] = np.nan
737 flatExp2.image.array[:, :] = np.nan
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 )
746 self.assertTrue(np.isnan(mu))
747 self.assertTrue(np.isnan(varDiff))
748 self.assertTrue(covDiff is None)
749 self.assertTrue(np.isnan(rowMeanVariance))
751 def test_meanVarMeasurementTooFewPixels(self):
752 task = self.defaultTaskExtract
753 flatExp1 = self.flatExp1.clone()
754 flatExp2 = self.flatExp2.clone()
756 flatExp1.image.array[0:190, :] = np.nan
757 flatExp2.image.array[0:190, :] = np.nan
759 bit = flatExp1.mask.getMaskPlaneDict()["NO_DATA"]
760 flatExp1.mask.array[0:190, :] &= 2**bit
761 flatExp2.mask.array[0:190, :] &= 2**bit
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])
772 self.assertTrue(np.isnan(mu))
773 self.assertTrue(np.isnan(varDiff))
774 self.assertTrue(covDiff is None)
775 self.assertTrue(np.isnan(rowMeanVariance))
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()
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
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
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])
806 self.assertTrue(np.isnan(mu))
807 self.assertTrue(np.isnan(varDiff))
808 self.assertTrue(covDiff is None)
809 self.assertTrue(np.isnan(rowMeanVariance))
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]
816 substituteValue = 1e-10
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))
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 )
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)
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)
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
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 )
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)
893 resultsSolve = solveTask.run(
894 resultsExtract.outputCovariances,
895 camera=FakeCamera([self.flatExp1.getDetector()]),
896 )
897 ptc = resultsSolve.outputPtcDataset
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 )
910 def test_getGainFromFlatPair(self):
911 for gainCorrectionType in [
912 "NONE",
913 "SIMPLE",
914 "FULL",
915 ]:
916 self.runGetGainFromFlatPair(gainCorrectionType)
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)
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)
929 gainsTruth = rng.normal(loc=1.7, scale=0.05, size=len(self.ampNames))
930 gainsMedian = np.median(gainsTruth)
932 gainsMeasured = rng.normal(loc=gainsTruth, scale=0.02, size=len(self.ampNames))
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
939 # We have a perfectly flat illuminated detector (in electrons)
940 nFlat = 20
941 meansElectron = gainsMedian * np.linspace(500.0, 30000.0, nFlat)
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)
951 for testMode in ["full", "badamp"]:
952 badAmp = None
954 ptc = PhotonTransferCurveDataset(self.ampNames, ptcFitType="FULLCOVARIANCE")
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]
961 if testMode == "badamp" and i == 3:
962 ptc.gain[ampName] = np.nan
963 ptc.gainUnadjusted[ampName] = np.nan
964 badAmp = ampName
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_)
970 # Fill the amp offsets temporarily.
971 ptc.ampOffsets[ampName] = np.zeros(len(meansElectron))
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
982 ampOffset = AmpOffsetTask(config=config)
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
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
997 ampOffset.run(exp)
998 metadatas.append(exp.metadata)
1000 result = fixupTask.run(inputPtc=ptc, exposureMetadata=metadatas)
1001 ptc = result.outputPtc
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
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
1014 self.assertFloatsAlmostEqual(testImage.ravel(), 1.0, rtol=1e-6)
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)
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)
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]
1031 if ampName1 != badAmp and ampName2 != badAmp:
1032 self.assertFloatsAlmostEqual(ratio, ratioTruth, rtol=1e-7)
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
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])
1042 for ampName in self.ampNames[1:]:
1043 ptc.gain[ampName] = np.nan
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])
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
1058 task = cpPipe.ptc.PhotonTransferCurveExtractPairTask(config=extractConfig)
1059 exposures = [self.flatExp1, self.flatExp2]
1060 with self.assertNoLogs(level=logging.WARNING):
1061 task._maskVignetteFunctionRegion(exposures)
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()}")
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
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)
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()}")
1090 def _getSampleMeanAndVar(self, dense=False, mode="normal"):
1091 """Get sample mean/var vectors and ptcTurnoff from LSSTCam data.
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.
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".
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")
1776 return rawMeans, rawVars, ptcTurnoff
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 }
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 }
1795class TestMemory(lsst.utils.tests.MemoryTestCase):
1796 pass
1799def setup_module(module):
1800 lsst.utils.tests.init()
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()