Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DM-42163: eo_pipe/cp_verify parity: ptc #36

Merged
merged 4 commits into from
Jan 25, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
41 changes: 31 additions & 10 deletions python/lsst/cp/verify/verifyPtc.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,16 +123,34 @@ def amplifierStatistics(self, inputCalib, camera=None):
outputStatistics = {amp.getName(): {} for amp in detector}
for amp in detector:
ampName = amp.getName()
outputStatistics[ampName]['PTC_GAIN'] = inputCalib.gain[ampName]
calibGain = inputCalib.gain[ampName]
outputStatistics[ampName]['PTC_GAIN'] = calibGain
outputStatistics[ampName]['AMP_GAIN'] = amp.getGain()
outputStatistics[ampName]['PTC_NOISE'] = inputCalib.noise[ampName]
outputStatistics[ampName]['AMP_NOISE'] = amp.getReadNoise()
outputStatistics[ampName]['PTC_TURNOFF'] = inputCalib.ptcTurnoff[ampName]
outputStatistics[ampName]['PTC_FIT_TYPE'] = ptcFitType
outputStatistics[ampName]['PTC_ROW_MEAN_VARIANCE'] = inputCalib.rowMeanVariance[ampName].tolist()
outputStatistics[ampName]['PTC_MAX_RAW_MEANS'] = float(np.max(inputCalib.rawMeans[ampName]))
if ptcFitType == 'EXPAPPROXIMATION':
outputStatistics[ampName]['PTC_BFE_A00'] = float(inputCalib.ptcFitPars[ampName][0])
if ptcFitType == 'FULLCOVARIANCE':
outputStatistics[ampName]['PTC_BFE_A00'] = float(inputCalib.aMatrix[ampName][0][0])

# Test from eo_pipe: github.com/lsst-camera-dh/eo-pipe;
# ptcPlotTask.py
# Slope of [variance of means of rows](electrons^2)
# vs [2*signal(electrons)/numCols]
numCols = amp.getBBox().width
mask = inputCalib.expIdMask[ampName]
rowMeanVar = inputCalib.rowMeanVariance[ampName][mask]*calibGain**2
signal = inputCalib.rawMeans[ampName][mask]*calibGain
try:
slope = sum(rowMeanVar) / sum(2.*signal/numCols)
except ZeroDivisionError:
slope = np.nan
outputStatistics[ampName]['ROW_MEAN_VARIANCE_SLOPE'] = float(slope)

return outputStatistics

def verify(self, calib, statisticsDict, camera=None):
Expand Down Expand Up @@ -170,21 +188,23 @@ def verify(self, calib, statisticsDict, camera=None):
for amp in detector:
verify = {}
ampName = amp.getName()
diffGain = (np.abs(calib.gain[ampName] - amp.getGain()) / amp.getGain())*100
calibGain = calib.gain[ampName]

diffGain = (np.abs(calibGain - amp.getGain()) / amp.getGain())*100
diffNoise = (np.abs(calib.noise[ampName] - amp.getReadNoise()) / amp.getReadNoise())*100

# DMTN-101: 16.1 and 16.2
# The fractional relative difference between the fitted PTC and the
# nominal amplifier gain and readout noise values should be less
# than a certain threshold (default: 5%).
verify['GAIN'] = bool(diffGain < self.config.gainThreshold)
verify['NOISE'] = bool(diffNoise < self.config.noiseThreshold)
verify['PTC_GAIN'] = bool(diffGain < self.config.gainThreshold)
verify['PTC_NOISE'] = bool(diffNoise < self.config.noiseThreshold)

# DMTN-101: 16.3
# Check that the measured PTC turnoff is at least greater than the
# full-well requirement of 90k e-.
turnoffCut = self.config.turnoffThreshold
verify['PTC_TURNOFF'] = bool(calib.ptcTurnoff[ampName]*calib.gain[ampName] > turnoffCut)
verify['PTC_TURNOFF'] = bool(calib.ptcTurnoff[ampName]*calibGain > turnoffCut)
# DMTN-101: 16.4
# Check the a00 value (brighter-fatter effect).
# This is a purely electrostatic parameter that should not change
Expand All @@ -200,13 +220,14 @@ def verify(self, calib, statisticsDict, camera=None):
if detVendor == 'ITL':
a00Max = self.config.a00MaxITL
a00Min = self.config.a00MinITL
verify['BFE_A00'] = bool(a00 > a00Min and a00 < a00Max)
verify['PTC_BFE_A00'] = bool(a00 > a00Min and a00 < a00Max)
elif detVendor == 'E2V':
a00Max = self.config.a00MaxE2V
a00Min = self.config.a00MinE2V
verify['BFE_A00'] = bool(a00 > a00Min and a00 < a00Max)
verify['PTC_BFE_A00'] = bool(a00 > a00Min and a00 < a00Max)
else:
raise RuntimeError(f"Detector type {detVendor} not one of 'ITL' or 'E2V'")

# Overall success among all tests for this amp.
verify['SUCCESS'] = bool(np.all(list(verify.values())))
if verify['SUCCESS'] is False:
Expand All @@ -215,16 +236,16 @@ def verify(self, calib, statisticsDict, camera=None):
verifyStats[ampName] = verify

# Loop over amps to make a detector summary.
verifyDetStats = {'GAIN': [], 'NOISE': [], 'PTC_TURNOFF': [], 'BFE_A00': []}
verifyDetStats = {'PTC_GAIN': [], 'PTC_NOISE': [], 'PTC_TURNOFF': [], 'PTC_BFE_A00': []}
for amp in verifyStats:
for testName in verifyStats[amp]:
if testName == 'SUCCESS':
continue
verifyDetStats[testName].append(verifyStats[amp][testName])

# If ptc model did not fit for a00 (e.g., POLYNOMIAL)
if not len(verifyDetStats['BFE_A00']):
verifyDetStats.pop('BFE_A00')
if not len(verifyDetStats['PTC_BFE_A00']):
verifyDetStats.pop('PTC_BFE_A00')

# VerifyDetStatsFinal has final boolean test over all amps
verifyDetStatsFinal = {}
Expand Down