1199 def run(self, exposure, ctiCalib, gains=None):
1200 """Correct deferred charge/CTI issues.
1201
1202 Parameters
1203 ----------
1204 exposure : `lsst.afw.image.Exposure`
1205 Exposure to correct the deferred charge on.
1206 ctiCalib : `lsst.ip.isr.DeferredChargeCalib`
1207 Calibration object containing the charge transfer
1208 inefficiency model.
1209 gains : `dict` [`str`, `float`]
1210 A dictionary, keyed by amplifier name, of the gains to
1211 use. If gains is None, the nominal gains in the amplifier
1212 object are used.
1213
1214 Returns
1215 -------
1216 exposure : `lsst.afw.image.Exposure`
1217 The corrected exposure.
1218
1219 Notes
1220 -------
1221 This task will read the exposure metadata and determine if
1222 applying gains if necessary. The correction takes place in
1223 units of electrons. If bootstrapping, the gains used
1224 will just be 1.0. and the input/output units will stay in
1225 adu. If the input image is in adu, the output image will be
1226 in units of electrons. If the input image is in electron,
1227 the output image will be in electron.
1228 """
1229 image = exposure.getMaskedImage().image
1230 detector = exposure.getDetector()
1231
1232
1233 imageUnits = exposure.getMetadata().get("LSST ISR UNITS")
1234
1235
1236
1237 applyGains = False
1238 if imageUnits == "adu":
1239 applyGains = True
1240
1241
1242
1243
1244 if applyGains and gains is None:
1245 raise RuntimeError("No gains supplied for deferred charge correction.")
1246
1247 with gainContext(exposure, image, apply=applyGains, gains=gains, isTrimmed=False):
1248
1249 for amp in detector.getAmplifiers():
1250 ampName = amp.getName()
1251
1252 ampImage = image[amp.getRawBBox()]
1253 if self.config.zeroUnusedPixels:
1254
1255
1256 ampImage[amp.getRawParallelOverscanBBox()].array[:, :] = 0.0
1257 ampImage[amp.getRawSerialPrescanBBox()].array[:, :] = 0.0
1258
1259
1260
1261 ampData = self.flipData(ampImage.array, amp)
1262
1263 if ctiCalib.driftScale[ampName] > 0.0:
1264 correctedAmpData = self.local_offset_inverse(ampData,
1265 ctiCalib.driftScale[ampName],
1266 ctiCalib.decayTime[ampName],
1267 self.config.nPixelOffsetCorrection)
1268 else:
1269 correctedAmpData = ampData.copy()
1270
1271 correctedAmpData = self.local_trap_inverse(correctedAmpData,
1272 ctiCalib.serialTraps[ampName],
1273 ctiCalib.globalCti[ampName],
1274 self.config.nPixelTrapCorrection)
1275
1276
1277 correctedAmpData = self.flipData(correctedAmpData, amp)
1278 image[amp.getRawBBox()].array[:, :] = correctedAmpData[:, :]
1279
1280 return exposure
1281