def testBasics(self): """!Test basic functionality of LinearizeLookupTable """ for imageClass in (afwImage.ImageF, afwImage.ImageD): inImage = makeRampImage(bbox=self.bbox, start=-5, stop=250, imageClass=imageClass) table = self.makeTable(inImage) measImage = inImage.Factory(inImage, True) llt = LinearizeLookupTable(table=table, detector=self.detector) linRes = llt(measImage, self.detector) refImage = inImage.Factory(inImage, True) refNumOutOfRange = refLinearize(image=refImage, detector=self.detector, table=table) self.assertEqual(linRes.numAmps, len(self.detector.getAmpInfoCatalog())) self.assertEqual(linRes.numAmps, linRes.numLinearized) self.assertEqual(linRes.numOutOfRange, refNumOutOfRange) self.assertImagesAlmostEqual(refImage, measImage) # make sure logging is accepted log = Log.getLogger("ip.isr.LinearizeLookupTable") linRes = llt(image=measImage, detector=self.detector, log=log)
def testErrorHandling(self): """!Test error handling in LinearizeLookupTable """ image = makeRampImage(bbox=self.bbox, start=-5, stop=250) table = self.makeTable(image) llt = LinearizeLookupTable(table=table, detector=self.detector) # bad name detBadName = self.makeDetector(detName="bad_detector_name") with self.assertRaises(RuntimeError): llt(image, detBadName) # bad serial detBadSerial = self.makeDetector(detSerial="bad_detector_serial") with self.assertRaises(RuntimeError): llt(image, detBadSerial) # bad number of amplifiers badNumAmps = (self.numAmps[0] - 1, self.numAmps[1]) detBadNumMaps = self.makeDetector(numAmps=badNumAmps) with self.assertRaises(RuntimeError): llt(image, detBadNumMaps) # bad linearity type detBadLinType = self.makeDetector(linearityType="bad_linearity_type") with self.assertRaises(RuntimeError): llt(image, detBadLinType)
def makeLinearizerDecam(fromFile, force=False, verbose=False): """Convert the specified DECam linearity FITS table to standard LSST format Details: - Input format is one table per CCD, HDU is amplifier number, the table has 3 columns: ADU, ADU_LINEAR_A, ADU_LINEAR_B. The values of ADU contiguous (0, 1, 2...) but check and error out if not. The values of the latter two are replacements (0+delta0, 1+delta1, 2+delta2...) and this is converted to offsets for the LSST linearization tables (delta0, delta1, delta2...) - Output is a set of LinearizeLookupTable instances, one per CCD, saved as dataset type "linearizer" - The row indices for the linearization lookup table are (row index=amp name): 0=A, 1=B @param[in] fromFile path to DECam linearity table (a FITS file with one HDU per amplifier) """ print("Making DECam linearizers from %r" % (fromFile, )) butler = Butler(mapper=DecamMapper) linearizerDir = DecamMapper.getLinearizerDir() if os.path.exists(linearizerDir): if not force: print("Output directory %r exists; use --force to replace" % (linearizerDir, )) sys.exit(1) print("Replacing data in linearizer directory %r" % (linearizerDir, )) else: print("Creating linearizer directory %r" % (linearizerDir, )) os.makedirs(linearizerDir) camera = DecamMapper().camera fromHDUs = fits.open(fromFile)[1:] # HDU 0 has no data assert len(fromHDUs) == len(camera) for ccdind, (detector, hdu) in enumerate(zip(camera, fromHDUs)): ccdnum = ccdind + 1 if verbose: print("ccdnum=%s; detector=%s" % (ccdnum, detector.getName())) fromData = hdu.data assert len(fromData.dtype) == 3 lsstTable = np.zeros((2, len(fromData)), dtype=np.float32) uncorr = fromData["ADU"] if not np.allclose(uncorr, np.arange(len(fromData))): raise RuntimeError( "ADU data not a range of integers starting at 0") for i, ampName in enumerate("AB"): # convert DECam replacement table to LSST offset table if verbose: print("DECam table for %s=%s..." % ( ampName, fromData["ADU_LINEAR_" + ampName][0:5], )) lsstTable[i, :] = fromData["ADU_LINEAR_" + ampName] - uncorr if verbose: print("LSST table for %s=%s..." % ( ampName, lsstTable[i, 0:5], )) linearizer = LinearizeLookupTable(table=lsstTable, detector=detector) butler.put(linearizer, "linearizer", dataId=dict(ccdnum=ccdnum)) print("Wrote %s linearizers" % (ccdind + 1, ))
def testKnown(self): """!Test a few known values """ numAmps = (2, 2) bbox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(4, 4)) # make a 4x4 image with 4 identical 2x2 subregions that flatten to -1, 0, 1, 2 im = afwImage.ImageF(bbox) imArr = im.getArray() imArr[:, :] = np.array( ((-1, 0, -1, 0), (1, 2, 1, 2), (-1, 0, -1, 0), (1, 2, 1, 2)), dtype=imArr.dtype) def castAndReshape(arr): arr = np.array(arr, dtype=float) arr.shape = numAmps return arr rowInds = castAndReshape( (3, 2, 1, 0)) # avoid the trivial mapping to exercise more of the code colIndOffsets = castAndReshape((0, 0, 1, 1)) detector = self.makeDetector(bbox=bbox, numAmps=numAmps, rowInds=rowInds, colIndOffsets=colIndOffsets) ampInfoCat = detector.getAmpInfoCatalog() # note: table rows are reversed relative to amplifier order because rowInds is a descending ramp table = np.array( ((7, 6, 5, 4), (1, 1, 1, 1), (5, 4, 3, 2), (0, 0, 0, 0)), dtype=imArr.dtype) llt = LinearizeLookupTable(table=table, detector=detector) lltRes = llt(image=im, detector=detector) self.assertEqual(lltRes.numOutOfRange, 2) # amp 0 is a constant correction of 0; one image value is out of range, but it doesn't matter imArr0 = im.Factory(im, ampInfoCat[0].getBBox()).getArray() self.assertFloatsAlmostEqual(imArr0.flatten(), (-1, 0, 1, 2)) # amp 1 is a correction of (5, 4, 3, 2), but the first image value is under range imArr1 = im.Factory(im, ampInfoCat[1].getBBox()).getArray() self.assertFloatsAlmostEqual(imArr1.flatten(), (4, 5, 5, 5)) # amp 2 is a constant correction of +1; all image values are in range, but it doesn't matter imArr2 = im.Factory(im, ampInfoCat[2].getBBox()).getArray() self.assertFloatsAlmostEqual(imArr2.flatten(), (0, 1, 2, 3)) # amp 3 is a correction of (7, 6, 5, 4); all image values in range imArr1 = im.Factory(im, ampInfoCat[3].getBBox()).getArray() self.assertFloatsAlmostEqual(imArr1.flatten(), (6, 6, 6, 6))
def testPickle(self): """!Test that a LinearizeLookupTable can be pickled and unpickled """ inImage = makeRampImage(bbox=self.bbox, start=-5, stop=2500) table = self.makeTable(inImage) llt = LinearizeLookupTable(table=table, detector=self.detector) refImage = inImage.Factory(inImage, True) refNumOutOfRange = llt(refImage, self.detector) pickledStr = pickle.dumps(llt) restoredLlt = pickle.loads(pickledStr) measImage = inImage.Factory(inImage, True) measNumOutOfRange = restoredLlt(measImage, self.detector) self.assertEqual(refNumOutOfRange, measNumOutOfRange) self.assertImagesAlmostEqual(refImage, measImage)