Coverage for python/lsst/cp/verify/repackStats.py: 22%

227 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-03-16 02:44 -0700

1# This file is part of cp_verify. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (http://www.lsst.org). 

6# See the COPYRIGHT file at the top-level directory of this distribution 

7# for details of code ownership. 

8# 

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

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

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

12# (at your option) any later version. 

13# 

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

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

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

17# GNU General Public License for more details. 

18# 

19# You should have received a copy of the GNU General Public License 

20# along with this program. If not, see <http://www.gnu.org/licenses/>. 

21import numpy as np 

22 

23from astropy.table import Table 

24 

25import lsst.pipe.base as pipeBase 

26import lsst.pipe.base.connectionTypes as cT 

27import lsst.pex.config as pexConfig 

28 

29__all__ = [ 

30 "CpVerifyRepackInstrumentConnections", 

31 "CpVerifyRepackPhysicalFilterConnections", 

32 "CpVerifyRepackInstrumentConfig", 

33 "CpVerifyRepackPhysicalFilterConfig", 

34 "CpVerifyRepackBiasTask", 

35 "CpVerifyRepackDarkTask", 

36 "CpVerifyRepackFlatTask", 

37 "CpVerifyRepackDefectTask", 

38 "CpVerifyRepackPtcTask", 

39 "CpVerifyRepackBfkTask", 

40 "CpVerifyRepackCtiTask", 

41] 

42 

43 

44class CpVerifyRepackInstrumentConnections(pipeBase.PipelineTaskConnections, 

45 dimensions={"instrument"}, 

46 defaultTemplate={}): 

47 """Connections class for calibration statistics with only instrument 

48 dimension. 

49 """ 

50 detectorStats = cT.Input( 

51 name="detectorStats", 

52 doc="Input detector statistics.", 

53 storageClass="StructuredDataDict", 

54 dimensions={"instrument", "exposure", "detector"}, 

55 multiple=True, 

56 ) 

57 exposureStats = cT.Input( 

58 name="exposureStats", 

59 doc="Input exposure statistics.", 

60 storageClass="StructuredDataDict", 

61 dimensions={"instrument", "exposure"}, 

62 multiple=True, 

63 ) 

64 runStats = cT.Input( 

65 name="runStats", 

66 doc="Input Run statistics.", 

67 storageClass="StructuredDataDict", 

68 dimensions={"instrument", }, 

69 multiple=True, 

70 ) 

71 

72 outputCatalog = cT.Output( 

73 name="cpvCatalog", 

74 doc="Output merged catalog.", 

75 storageClass="ArrowAstropy", 

76 dimensions={"instrument", }, 

77 ) 

78 matrixCatalog = cT.Output( 

79 name="cpvMatrix", 

80 doc="Output matrix catalog.", 

81 storageClass="ArrowAstropy", 

82 dimensions={"instrument", }, 

83 ) 

84 

85 def __init__(self, *, config=None): 

86 super().__init__(config=config) 

87 

88 if not config.hasMatrixCatalog: 

89 self.outputs.remove("matrixCatalog") 

90 

91 

92class CpVerifyRepackInstrumentConfig(pipeBase.PipelineTaskConfig, 

93 pipelineConnections=CpVerifyRepackInstrumentConnections): 

94 

95 expectedDistributionLevels = pexConfig.ListField( 

96 dtype=float, 

97 doc="Percentile levels expected in the calibration header.", 

98 default=[0, 5, 16, 50, 84, 95, 100], 

99 ) 

100 hasMatrixCatalog = pexConfig.Field( 

101 dtype=bool, 

102 doc="Will a matrix catalog be created?", 

103 default=False, 

104 ) 

105 

106 

107class CpVerifyRepackTask(pipeBase.PipelineTask): 

108 """Repack cpVerify statistics for analysis_tools. 

109 

110 This version is the base for calibrations with summary 

111 dimensions of instrument only. 

112 """ 

113 ConfigClass = CpVerifyRepackInstrumentConfig 

114 _DefaultName = "cpVerifyRepack" 

115 

116 def runQuantum(self, butlerQC, inputRefs, outputRefs): 

117 inputs = butlerQC.get(inputRefs) 

118 

119 inputs["detectorDims"] = [dict(exp.dataId.required) for exp in inputRefs.detectorStats] 

120 inputs["exposureDims"] = [dict(exp.dataId.required) for exp in inputRefs.exposureStats] 

121 

122 outputs = self.run(**inputs) 

123 butlerQC.put(outputs, outputRefs) 

124 

125 def run(self, detectorStats, detectorDims, exposureStats, exposureDims, runStats): 

126 """ 

127 """ 

128 results = self.repack(detectorStats, detectorDims, exposureStats, exposureDims, runStats) 

129 catalog = Table(results.rowList) 

130 

131 matrixCatalog = None 

132 if self.config.hasMatrixCatalog: 

133 matrixCatalog = Table(results.matrixList) 

134 return pipeBase.Struct( 

135 outputCatalog=catalog, 

136 matrixCatalog=matrixCatalog, 

137 ) 

138 

139 def repackDetStats(self, detectorStats, detectorDims): 

140 raise NotImplementedError("Repack needs to be defined by subclasses.") 

141 

142 def repackExpStats(self, exposureStats, exposureDims): 

143 # for expStats, expDims in zip(exposureStats, exposureDims): 

144 raise NotImplementedError("Repack needs to be defined by subclasses.") 

145 

146 def repackRunStats(self, runStats): 

147 # for runStats in runStats: 

148 raise NotImplementedError("Repack needs to be defined by subclasses.") 

149 

150 def repack(self, detectorStats, detectorDims, exposureStats, exposureDims, runStats): 

151 return self.repackDetStats(detectorStats, detectorDims) 

152 

153 

154class CpVerifyRepackBiasTask(CpVerifyRepackTask): 

155 stageName = "bias" 

156 

157 def repackDetStats(self, detectorStats, detectorDims): 

158 rowList = [] 

159 

160 for detStats, detDims in zip(detectorStats, detectorDims): 

161 row = {} 

162 instrument = detDims["instrument"] 

163 exposure = detDims["exposure"] 

164 detector = detDims["detector"] 

165 mjd = detStats["ISR"]["MJD"] 

166 

167 # Get amp stats 

168 # AMP {ampName} [CR_NOISE MEAN NOISE] value 

169 for ampName, stats in detStats["AMP"].items(): 

170 row[ampName] = { 

171 "instrument": instrument, 

172 "exposure": exposure, 

173 "mjd": mjd, 

174 "detector": detector, 

175 "amplifier": ampName, 

176 "biasMean": stats["MEAN"], 

177 "biasNoise": stats["NOISE"], 

178 "biasCrNoise": stats["CR_NOISE"] 

179 } 

180 # Get catalog stats CATALOG 

181 # Get detector stats DET 

182 # Get metadata stats 

183 # METADATA (RESIDUAL STDEV) {ampName} value 

184 for ampName, value in detStats["METADATA"]["RESIDUAL STDEV"].items(): 

185 row[ampName]["biasReadNoise"] = value 

186 

187 # Get verify stats 

188 for ampName, stats in detStats["VERIFY"]["AMP"].items(): 

189 row[ampName]["biasVerifyMean"] = stats["MEAN"] 

190 row[ampName]["biasVerifyNoise"] = stats["NOISE"] 

191 row[ampName]["biasVerifyCrNoise"] = stats["CR_NOISE"] 

192 row[ampName]["biasVerifyReadNoiseConsistent"] = stats["READ_NOISE_CONSISTENT"] 

193 

194 # Get isr stats 

195 for ampName, stats in detStats["ISR"]["CALIBDIST"].items(): 

196 for level in self.config.expectedDistributionLevels: 

197 key = f"LSST CALIB {self.stageName.upper()} {ampName} DISTRIBUTION {level}-PCT" 

198 row[ampName][f"biasDistribution_{level}"] = stats[key] 

199 

200 projStats = detStats["ISR"]["PROJECTION"] 

201 for ampName in projStats["AMP_HPROJECTION"].keys(): 

202 row[ampName]["biasSerialProfile"] = np.array(projStats["AMP_HPROJECTION"][ampName]) 

203 for ampName in projStats["AMP_VPROJECTION"].keys(): 

204 row[ampName]["biasParallelProfile"] = np.array(projStats["AMP_VPROJECTION"][ampName]) 

205 

206 shiftStats = detStats["ISR"]["BIASSHIFT"] 

207 for ampName, stats in shiftStats.items(): 

208 row[ampName]["biasShiftCount"] = len(stats["BIAS_SHIFTS"]) 

209 row[ampName]["biasShiftNoise"] = stats["LOCAL_NOISE"] 

210 corrStats = detStats["ISR"]["AMPCORR"] 

211 

212 # Create output table: 

213 for ampName, stats in row.items(): 

214 rowList.append(stats) 

215 

216 # We need all rows of biasParallelProfile and biasParallelProfile 

217 # to be the same length for serialization. Therefore, we pad 

218 # to the longest length. 

219 

220 maxSerialLen = 0 

221 maxParallelLen = 0 

222 

223 for row in rowList: 

224 if len(row["biasSerialProfile"]) > maxSerialLen: 

225 maxSerialLen = len(row["biasSerialProfile"]) 

226 if len(row["biasParallelProfile"]) > maxParallelLen: 

227 maxParallelLen = len(row["biasParallelProfile"]) 

228 

229 for row in rowList: 

230 if len(row["biasSerialProfile"]) < maxSerialLen: 

231 row["biasSerialProfile"] = np.pad( 

232 row["biasSerialProfile"], 

233 (0, maxSerialLen - len(row["biasSerialProfile"])), 

234 constant_values=np.nan, 

235 ) 

236 if len(row["biasParallelProfile"]) < maxParallelLen: 

237 row["biasParallelProfile"] = np.pad( 

238 row["biasParallelProfile"], 

239 (0, maxParallelLen - len(row["biasParallelProfile"])), 

240 constant_values=np.nan, 

241 ) 

242 

243 return pipeBase.Struct( 

244 rowList=rowList, 

245 matrixList=corrStats, 

246 ) 

247 

248 

249class CpVerifyRepackDarkTask(CpVerifyRepackTask): 

250 stageName = "dark" 

251 

252 def repackDetStats(self, detectorStats, detectorDims): 

253 rowList = [] 

254 

255 for detStats, detDims in zip(detectorStats, detectorDims): 

256 row = {} 

257 instrument = detDims["instrument"] 

258 exposure = detDims["exposure"] 

259 detector = detDims["detector"] 

260 

261 # Get amp stats 

262 # AMP {ampName} [CR_NOISE MEAN NOISE] value 

263 for ampName, stats in detStats["AMP"].items(): 

264 row[ampName] = { 

265 "instrument": instrument, 

266 "exposure": exposure, 

267 "detector": detector, 

268 "amplifier": ampName, 

269 "darkMean": stats["MEAN"], 

270 "darkNoise": stats["NOISE"], 

271 "darkCrNoise": stats["CR_NOISE"] 

272 } 

273 # Get catalog stats 

274 # Get detector stats 

275 # Get metadata stats 

276 for ampName, value in detStats["METADATA"]["RESIDUAL STDEV"].items(): 

277 row[ampName]["darkReadNoise"] = value 

278 

279 # Get verify stats 

280 for ampName, stats in detStats["VERIFY"]["AMP"].items(): 

281 row[ampName]["darkVerifyMean"] = stats["MEAN"] 

282 row[ampName]["darkVerifyNoise"] = stats["NOISE"] 

283 row[ampName]["darkVerifyCrNoise"] = stats["CR_NOISE"] 

284 row[ampName]["darkVerifyReadNoiseConsistent"] = stats["READ_NOISE_CONSISTENT"] 

285 # Get isr stats 

286 for ampName, stats in detStats["ISR"]["CALIBDIST"].items(): 

287 for level in self.config.expectedDistributionLevels: 

288 key = f"LSST CALIB {self.stageName.upper()} {ampName} DISTRIBUTION {level}-PCT" 

289 row[ampName][f"darkDistribution_{level}"] = stats[key] 

290 

291 # Append to output 

292 for ampName, stats in row.items(): 

293 rowList.append(stats) 

294 

295 return pipeBase.Struct( 

296 rowList=rowList, 

297 ) 

298 

299 

300class CpVerifyRepackPhysicalFilterConnections(pipeBase.PipelineTaskConnections, 

301 dimensions={"instrument", "physical_filter"}, 

302 defaultTemplate={}): 

303 """Connections class for calibration statistics with physical_filter 

304 (and instrument) dimensions. 

305 """ 

306 detectorStats = cT.Input( 

307 name="detectorStats", 

308 doc="Input detector statistics.", 

309 storageClass="StructuredDataDict", 

310 dimensions={"instrument", "exposure", "detector"}, 

311 multiple=True, 

312 ) 

313 exposureStats = cT.Input( 

314 name="exposureStats", 

315 doc="Input exposure statistics.", 

316 storageClass="StructuredDataDict", 

317 dimensions={"instrument", "exposure"}, 

318 multiple=True, 

319 ) 

320 runStats = cT.Input( 

321 name="runStats", 

322 doc="Input Run statistics.", 

323 storageClass="StructuredDataDict", 

324 dimensions={"instrument"}, 

325 multiple=True, 

326 ) 

327 

328 outputCatalog = cT.Output( 

329 name="cpvCatalog", 

330 doc="Output merged catalog.", 

331 storageClass="ArrowAstropy", 

332 dimensions={"instrument", "physical_filter"}, 

333 ) 

334 

335 

336class CpVerifyRepackPhysicalFilterConfig(pipeBase.PipelineTaskConfig, 

337 pipelineConnections=CpVerifyRepackPhysicalFilterConnections): 

338 expectedDistributionLevels = pexConfig.ListField( 

339 dtype=float, 

340 doc="Percentile levels expected in the calibration header.", 

341 default=[0, 5, 16, 50, 84, 95, 100], 

342 ) 

343 hasMatrixCatalog = pexConfig.Field( 

344 dtype=bool, 

345 doc="Will a matrix catalog be created?", 

346 default=False, 

347 ) 

348 

349 

350class CpVerifyRepackFlatTask(CpVerifyRepackTask): 

351 ConfigClass = CpVerifyRepackPhysicalFilterConfig 

352 

353 stageName = "flat" 

354 

355 def repackDetStats(self, detectorStats, detectorDims): 

356 rowList = [] 

357 

358 for detStats, detDims in zip(detectorStats, detectorDims): 

359 row = {} 

360 instrument = detDims["instrument"] 

361 exposure = detDims["exposure"] 

362 detector = detDims["detector"] 

363 

364 # Get amp stats 

365 # AMP {ampName} [MEAN NOISE] value 

366 for ampName, stats in detStats["AMP"].items(): 

367 row[ampName] = { 

368 "instrument": instrument, 

369 "exposure": exposure, 

370 "detector": detector, 

371 "amplifier": ampName, 

372 "flatMean": stats["MEAN"], 

373 "flatNoise": stats["NOISE"], 

374 } 

375 # Get catalog stats CATALOG 

376 

377 # Get metadata stats 

378 # METADATA (RESIDUAL STDEV) {ampName} value 

379 

380 # Get verify stats 

381 for ampName, stats in detStats["VERIFY"]["AMP"].items(): 

382 row[ampName]["flatVerifyNoise"] = stats["NOISE"] 

383 # Get isr stats 

384 for ampName, stats in detStats["ISR"]["CALIBDIST"].items(): 

385 for level in self.config.expectedDistributionLevels: 

386 key = f"LSST CALIB {self.stageName.upper()} {ampName} DISTRIBUTION {level}-PCT" 

387 row[ampName][f"flatDistribution_{level}"] = stats[key] 

388 # Get detector stats 

389 # DET 

390 row["detector"] = {"instrument": instrument, 

391 "exposure": exposure, 

392 "detector": detector, 

393 "flatDetMean": detStats["DET"]["MEAN"], 

394 "flatDetScatter": detStats["DET"]["SCATTER"], 

395 } 

396 

397 # Append to output 

398 for ampName, stats in row.items(): 

399 rowList.append(stats) 

400 

401 return pipeBase.Struct( 

402 rowList=rowList, 

403 ) 

404 

405 

406class CpVerifyRepackDefectTask(CpVerifyRepackTask): 

407 stageName = "defects" 

408 

409 def repackDetStats(self, detectorStats, detectorDims): 

410 rowList = [] 

411 for detStats, detDims in zip(detectorStats, detectorDims): 

412 row = {} 

413 instrument = detDims["instrument"] 

414 detector = detDims["detector"] 

415 

416 # Get amp stats 

417 for ampName, stats in detStats["AMP"].items(): 

418 row[ampName] = { 

419 "instrument": instrument, 

420 "detector": detector, 

421 "amplifier": ampName, 

422 } 

423 # Get catalog stats CATALOG 

424 # Get metadata stats METADATA 

425 # Get verify stats VERIFY 

426 # Get isr stats ISR 

427 nBadColumns = np.nan 

428 for ampName, stats in detStats["ISR"]["CALIBDIST"].items(): 

429 if ampName == "detector": 

430 nBadColumns = stats[ampName]["LSST CALIB DEFECTS N_BAD_COLUMNS"] 

431 else: 

432 key = f"LSST CALIB DEFECTS {ampName} N_HOT" 

433 row[ampName]["hotPixels"] = stats[ampName][key] 

434 key = f"LSST CALIB DEFECTS {ampName} N_COLD" 

435 row[ampName]["coldPixels"] = stats[ampName][key] 

436 # Get detector stats DET 

437 row["detector"] = {"instrument": instrument, 

438 "detector": detector, 

439 "nBadColumns": nBadColumns, 

440 } 

441 for ampName, stats in row.items(): 

442 rowList.append(stats) 

443 

444 return rowList 

445 

446 

447class CpVerifyRepackCtiTask(CpVerifyRepackTask): 

448 stageName = "cti" 

449 pass 

450 

451 

452class CpVerifyRepackBfkTask(CpVerifyRepackTask): 

453 stageName = "bfk" 

454 pass 

455 

456 

457class CpVerifyRepackNoExpConnections(pipeBase.PipelineTaskConnections, 

458 dimensions={"instrument"}, 

459 defaultTemplate={}): 

460 detectorStats = cT.Input( 

461 name="detectorStats", 

462 doc="Input detector statistics.", 

463 storageClass="StructuredDataDict", 

464 dimensions={"instrument", "detector"}, 

465 multiple=True, 

466 ) 

467 runStats = cT.Input( 

468 name="runStats", 

469 doc="Input Run statistics.", 

470 storageClass="StructuredDataDict", 

471 dimensions={"instrument"}, 

472 multiple=True, 

473 ) 

474 

475 outputCatalog = cT.Output( 

476 name="cpvCatalog", 

477 doc="Output merged catalog.", 

478 storageClass="ArrowAstropy", 

479 dimensions={"instrument"}, 

480 ) 

481 

482 

483class CpVerifyRepackNoExpConfig(pipeBase.PipelineTaskConfig, 

484 pipelineConnections=CpVerifyRepackNoExpConnections): 

485 

486 expectedDistributionLevels = pexConfig.ListField( 

487 dtype=float, 

488 doc="Percentile levels expected in the calibration header.", 

489 default=[0, 5, 16, 50, 84, 95, 100], 

490 ) 

491 hasMatrixCatalog = pexConfig.Field( 

492 dtype=bool, 

493 doc="Will a matrix catalog be created?", 

494 default=False, 

495 ) 

496 

497 

498class CpVerifyRepackNoExpTask(CpVerifyRepackTask): 

499 """Repack cpVerify statistics for analysis_tools. 

500 

501 Version for "verifyCalib" style results, which have no exposure 

502 dimension. 

503 """ 

504 ConfigClass = CpVerifyRepackNoExpConfig 

505 _DefaultName = "cpVerifyRepack" 

506 

507 def runQuantum(self, butlerQC, inputRefs, outputRefs): 

508 inputs = butlerQC.get(inputRefs) 

509 

510 inputs["detectorDims"] = [dict(exp.dataId.required) for exp in inputRefs.detectorStats] 

511 inputs["exposureDims"] = [] 

512 inputs["exposureStats"] = [] 

513 

514 outputs = self.run(**inputs) 

515 butlerQC.put(outputs, outputRefs) 

516 

517 

518class CpVerifyRepackPtcTask(CpVerifyRepackNoExpTask): 

519 stageName = "ptc" 

520 

521 def repackDetStats(self, detectorStats, detectorDims): 

522 rowList = [] 

523 

524 for detStats, detDims in zip(detectorStats, detectorDims): 

525 row = {} 

526 

527 instrument = detDims["instrument"] 

528 detector = detDims["detector"] 

529 

530 # Get amp stats 

531 for ampName, stats in detStats["AMP"].items(): 

532 row[ampName] = { 

533 "instrument": instrument, 

534 "detector": detector, 

535 "amplifier": ampName, 

536 "ampGain": stats["AMP_GAIN"], 

537 "ampNoise": stats["AMP_NOISE"], 

538 "ptcGain": stats["PTC_GAIN"], 

539 "ptcNoise": stats["PTC_NOISE"], 

540 "ptcTurnoff": stats["PTC_TURNOFF"], 

541 "ptcFitType": stats["PTC_FIT_TYPE"], 

542 "ptcBfeA00": stats["PTC_BFE_A00"], 

543 "ptcRowMeanVariance": stats["PTC_ROW_MEAN_VARIANCE"], 

544 "ptcRowMeanVarianceSlope": stats["PTC_ROW_MEAN_VARIANCE_SLOPE"], 

545 "ptcMaxRawMeans": stats["PTC_MAX_RAW_MEANS"], 

546 "ptcRawMeans": stats["PTC_RAW_MEANS"], 

547 "ptcExpIdmask": stats["PTC_EXP_ID_MASK"], 

548 "ptcCov10": stats["PTC_COV_10"], 

549 "ptcCov10FitSlope": stats["PTC_COV_10_FIT_SLOPE"], 

550 "ptcCov10FitOffset": stats["PTC_COV_10_FIT_OFFSET"], 

551 "ptcCov10FitSuccess": stats["PTC_COV_10_FIT_SUCCESS"], 

552 "ptcCov01": stats["PTC_COV_01"], 

553 "ptcCov01FitSlope": stats["PTC_COV_01_FIT_SLOPE"], 

554 "ptcCov01FitOffset": stats["PTC_COV_01_FIT_OFFSET"], 

555 "ptcCov01FitSuccess": stats["PTC_COV_01_FIT_SUCCESS"], 

556 "ptcCov11": stats["PTC_COV_11"], 

557 "ptcCov11FitSlope": stats["PTC_COV_11_FIT_SLOPE"], 

558 "ptcCov11FitOffset": stats["PTC_COV_11_FIT_OFFSET"], 

559 "ptcCov11FitSuccess": stats["PTC_COV_11_FIT_SUCCESS"], 

560 "ptcCov20": stats["PTC_COV_20"], 

561 "ptcCov20FitSlope": stats["PTC_COV_20_FIT_SLOPE"], 

562 "ptcCov20FitOffset": stats["PTC_COV_20_FIT_OFFSET"], 

563 "ptcCov20FitSuccess": stats["PTC_COV_20_FIT_SUCCESS"], 

564 "ptcCov02": stats["PTC_COV_02"], 

565 "ptcCov02FitSlope": stats["PTC_COV_02_FIT_SLOPE"], 

566 "ptcCov02FitOffset": stats["PTC_COV_02_FIT_OFFSET"], 

567 "ptcCov02FitSuccess": stats["PTC_COV_02_FIT_SUCCESS"], 

568 } 

569 # Get catalog stats 

570 # Get detector stats 

571 # Get metadata stats 

572 # Get verify stats 

573 for ampName, stats in detStats["VERIFY"]["AMP"].items(): 

574 row[ampName]["ptcVerifyGain"] = stats["PTC_GAIN"] 

575 row[ampName]["ptcVerifyNoise"] = stats["PTC_NOISE"] 

576 row[ampName]["ptcVerifyTurnoff"] = stats["PTC_TURNOFF"] 

577 row[ampName]["ptcVerifyBfeA00"] = stats["PTC_BFE_A00"] 

578 

579 # Get isr stats 

580 

581 # Append to output 

582 for ampName, stats in row.items(): 

583 rowList.append(stats) 

584 

585 return pipeBase.Struct( 

586 rowList=rowList, 

587 ) 

588 

589 

590class CpVerifyRepackLinearityTask(CpVerifyRepackTask): 

591 stageName = "linearity" 

592 

593 def repackDetStats(self, detectorStats, detectorDims): 

594 rowList = [] 

595 

596 for detStats, detDims in zip(detectorStats, detectorDims): 

597 row = {} 

598 

599 instrument = detDims["instrument"] 

600 detector = detDims["detector"] 

601 

602 # Get amp stats 

603 for ampName, stats in detStats["AMP"].items(): 

604 centers, values = np.split(stats["LINEARITY_COEFFS"], 2) 

605 row[ampName] = { 

606 "instrument": instrument, 

607 "detector": detector, 

608 "amplifier": ampName, 

609 "fitParams": stats["FIT_PARAMS"], 

610 "fitParamsErr": stats["FIT_PARAMS_ERR"], 

611 "fitResiduals": stats["FIT_RESIDUALS"], 

612 "splineCenters": centers, 

613 "splineValues": values, 

614 "linearityType": stats["LINEARITY_TYPE"], 

615 "linearFit": stats["LINEAR_FIT"], 

616 } 

617 # Get catalog stats 

618 # Get detector stats 

619 # Get metadata stats 

620 # Get verify stats; no need to loop here. 

621 stats = detStats["VERIFY"] 

622 row["detector"] = { 

623 "instrument": instrument, 

624 "detector": detector, 

625 "linearityMaxResidualError": stats["MAX_RESIDUAL_ERROR"], 

626 } 

627 # Get isr stats 

628 

629 # Append to output 

630 for ampName, stats in row.items(): 

631 rowList.append(stats) 

632 

633 return pipeBase.Struct( 

634 rowList=rowList, 

635 ) 

636 

637 

638class CpVerifyRepackCrosstalkTask(CpVerifyRepackTask): 

639 pass