def setUp(self): # Load sample input from disk testDir = os.path.dirname(__file__) self.srcSet = SourceCatalog.readFits(os.path.join(testDir, "v695833-e0-c000.xy.fits")) self.bbox = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(2048, 4612)) # approximate # create an exposure with the right metadata; the closest thing we have is # apparently v695833-e0-c000-a00.sci.fits, which is much too small smallExposure = ExposureF(os.path.join(testDir, "v695833-e0-c000-a00.sci.fits")) self.exposure = ExposureF(self.bbox) self.exposure.setWcs(smallExposure.getWcs()) self.exposure.setFilter(smallExposure.getFilter()) # copy the pixels we can, in case the user wants a debug display mi = self.exposure.getMaskedImage() mi.assign(smallExposure.getMaskedImage(), smallExposure.getBBox()) logLevel = Log.INFO refCatDir = os.path.join(testDir, "data", "sdssrefcat") butler = Butler(refCatDir) refObjLoader = LoadIndexedReferenceObjectsTask(butler=butler) astrometryConfig = AstrometryTask.ConfigClass() self.astrom = AstrometryTask(config=astrometryConfig, refObjLoader=refObjLoader) self.astrom.log.setLevel(logLevel) # Since our sourceSelector is a registry object we have to wait for it to be created # before setting default values. self.astrom.matcher.sourceSelector.config.minSnr = 0
def testPersistence(self): im = ExposureF(10, 10) im.setPsf(self.psf) self.assertEqual(im.getPsf(), self.psf) with lsst.utils.tests.getTempFilePath(".fits") as tmpFile: im.writeFits(tmpFile) newIm = ExposureF(tmpFile) self.assertEqual(newIm.getPsf(), im.getPsf())
def testPersistence(self): for pgp in self.pgps: assert cppLib.isPersistable(pgp) im = ExposureF(10, 10) im.setPsf(pgp) self.assertEqual(im.getPsf(), pgp) with lsst.utils.tests.getTempFilePath(".fits") as tmpFile: im.writeFits(tmpFile) newIm = ExposureF(tmpFile) self.assertEqual(newIm.getPsf(), im.getPsf())
def testClone(self): """Test copying an exposure with an attached Blob. """ im = ExposureF(10, 10) # Extra components must be ALL CAPS for fits storage. im.getInfo().setComponent("BLOB", self.blob) im2 = im.clone() im3 = copy.deepcopy(im) im4 = ExposureF(im, deep=False) im5 = ExposureF(im, deep=True) for i in [im2, im3, im4, im5]: self.assertEqual(i.getInfo().getComponent("BLOB"), self.blob)
def testPersistence(self): """Test persisting an exposure with an attached Blob. """ im = ExposureF(10, 10) # Extra components must be ALL CAPS for fits storage. im.getInfo().setComponent("BLOB", self.blob) with lsst.utils.tests.getTempFilePath(".fits") as tmpFile: im.writeFits(tmpFile) newIm = ExposureF(tmpFile) self.assertEqual(newIm.getInfo().getComponent("BLOB"), self.blob) reader = ExposureFitsReader(tmpFile) newBlob = reader.readComponent("BLOB") self.assertEqual(newBlob, self.blob)
def test_solve(self): exposure = ExposureF(1000, 1000) psfConfig = InstallGaussianPsfConfig() psfConfig.fwhm = 4 psfTask = InstallGaussianPsfTask(config=psfConfig) psfTask.run(exposure=exposure) variance_image = exposure.getMaskedImage().getVariance() variance_image += 50 add_psf_image(exposure, 200.0, 400.0, 600.0) add_psf_image(exposure, 210.0, 210.0, 300.0) # These last two are to catch edge effects. add_psf_image(exposure, 5.0, 210.0, 400.0) add_psf_image(exposure, 300.0, 5.0, 500.0) matrix = CrowdedFieldMatrix(exposure, np.array([200.0, 210.0, 5.0, 300.0]), np.array([400.0, 210.0, 210.0, 5.0])) status = matrix.solve() self.assertEqual(status, matrix.SUCCESS) result = matrix.result() self.assertFloatsAlmostEqual(result, np.array([600.0, 300.0, 400.0, 500.0]), atol=1e-3)
def test_reject_maskedpixels(self): exposure = ExposureF(1000, 1000) psfConfig = InstallGaussianPsfConfig() psfConfig.fwhm = 4 psfTask = InstallGaussianPsfTask(config=psfConfig) psfTask.run(exposure=exposure) variance_image = exposure.getMaskedImage().getVariance() variance_image += 50 add_psf_image(exposure, 200.0, 400.0, 600.0) add_psf_image(exposure, 210.0, 210.0, 300.0) exposure.getMaskedImage().getImage()[200, 400] += 10000 mask_dict = exposure.getMaskedImage().getMask().getMaskPlaneDict() exposure.getMaskedImage().getMask()[200, 400] |= mask_dict['SAT'] matrix = CrowdedFieldMatrix(exposure, np.array([200.0, 210.0]), np.array([400.0, 210.0])) status = matrix.solve() self.assertEqual(status, matrix.SUCCESS) result = matrix.result() self.assertFloatsAlmostEqual(result, np.array([600.0, 300.0]), atol=1e-3)
def test_solve_catalog(self): exposure = ExposureF(1000, 1000) psfConfig = InstallGaussianPsfConfig() psfConfig.fwhm = 4 psfTask = InstallGaussianPsfTask(config=psfConfig) psfTask.run(exposure=exposure) variance_image = exposure.getMaskedImage().getVariance() variance_image += 50 add_psf_image(exposure, 200.0, 400.0, 600.0) add_psf_image(exposure, 210.0, 210.0, 300.0) schema = afwTable.SourceTable.makeMinimalSchema() schema.addField("centroid_x", type=np.float64) schema.addField("centroid_y", type=np.float64) flux_key = schema.addField("flux_flux", type=np.float64) schema.getAliasMap().set("slot_Centroid", "centroid") testCatalog = afwTable.SourceCatalog(schema) for x, y in zip([200.0, 210.0], [400.0, 210]): r = testCatalog.addNew() r["centroid_x"] = x r["centroid_y"] = y matrix = CrowdedFieldMatrix(exposure, testCatalog, flux_key) result = matrix.solve() self.assertFloatsAlmostEqual(testCatalog["flux_flux"], np.array([600.0, 300.0]), atol=1e-3)
def setUp(self): self.exposure = ExposureF(1000, 1000) psfConfig = InstallGaussianPsfConfig() psfConfig.fwhm = 4 psfTask = InstallGaussianPsfTask(config=psfConfig) psfTask.run(exposure=self.exposure) variance_image = self.exposure.getMaskedImage().getVariance() variance_image += 50
def test_solve_centroid(self): exposure = ExposureF(400, 400) psfConfig = InstallGaussianPsfConfig() psfConfig.fwhm = 4 psfTask = InstallGaussianPsfTask(config=psfConfig) psfTask.run(exposure=exposure) variance_image = exposure.getMaskedImage().getVariance() variance_image += 100 exposure.getMaskedImage().getVariance().getArray()[203, 203] = np.nan add_psf_image(exposure, 200.0, 200.0, 600.0) # exposure.image.array += 20*np.random.randn(*exposure.image.array.shape) schema = afwTable.SourceTable.makeMinimalSchema() simultaneousPsfFlux_key = schema.addField( "crowd_psfFlux_flux_instFlux", type=np.float64, doc="PSF Flux from simultaneous fitting") afwTable.Point2DKey.addFields(schema, "coarse_centroid", "Detection peak", "pixels") centroid_key = afwTable.Point2DKey.addFields( schema, "new_centroid", "Measurement of centroid", "pixels") schema.getAliasMap().set("slot_Centroid", "coarse_centroid") schema.getAliasMap().set("slot_PsfFlux", "crowd_psfFlux_flux") source_catalog = afwTable.SourceCatalog(schema) child = source_catalog.addNew() child['coarse_centroid_x'] = 200.0 child['coarse_centroid_y'] = 200.5 # Fit once with fixed positions to get the fluxes matrix = CrowdedFieldMatrix(exposure, source_catalog, simultaneousPsfFlux_key, fitCentroids=False, centroidKey=centroid_key) matrix.solve() # Now that we have rough fluxes, re-fit and allow # centroids to move. matrix = CrowdedFieldMatrix(exposure, source_catalog, simultaneousPsfFlux_key, fitCentroids=True, centroidKey=centroid_key) result = matrix.solve() self.assertFloatsAlmostEqual(source_catalog[0]['new_centroid_x'], 200.0, atol=5e-2) self.assertFloatsAlmostEqual(source_catalog[0]['new_centroid_y'], 200.0, atol=5e-2)
def readFits(cls, path): """Read an external detrended image and create an LSST Exposure object from it. Any significant processing (e.g. pixel interpolation) should probably be done in a ExternalIsrTask instead of here so it can be done once and saved, instead of being done every time the image is loaded. THIS METHOD IS INCOMPLETE; IT MUST BE MODIFIED ACCORDING TO THE FORMAT OF THE DATA BEING LOADED. """ directory, filename = os.path.split(path) match = cls.EXTERNAL_REGEX.match(filename) camera = cls.getCameraFromVisit(match.group("visit")) # Customize the code below based on the camera determined above. # To support more than one camera it may be useful to delegate # to other methods that are specific to certain cameras. # Read the actual image in from the given path using e.g. astropy, # and use it to fill in various arrays below. bbox = Box2I(Point2I(0, 0), Extent2I(..., ...)) # width, height result = ExposureF(bbox) # main image, as a [y, x] numpy.float32 array result.image.array = ... # variance image, as a [y, x] numpy.float32 array result.variance.array = ... # This example includes masking NaN pixels as NO_DATA and pixels above # 1E5 counts as SAT. External information about where bad pixels # should be preferred when available, and obviously that saturation # threshold is just an example (saturation should actually be # determined before flat-fielding, of course). # Interpolating these bad pixels is handled by ExternalIsrTask. noDataBitMask = result.mask.getPlaneBitMask("NO_DATA") satBitMask = result.mask.getPlaneBitMask("SAT") result.mask.array |= noDataBitMask * np.isnan(result.image.array) result.mask.array |= satBitMask * (result.image.array > 1E5) # If you have a better guess at the PSF, we can find a way to use it. # But it'd be a good idea to at least put this in with a guess at the # seeing (RMS in pixels). result.setPsf(SingleGaussianPsf(seeingRMS)) # Add a guess for the WCS, in this case assuming it's in the FITS # header of the first HDU. Need to have something here, even if it # isn't very good (e.g. whatever comes from the telescope). metadata = readMetadata(filename) wcs = SkyWcs(metadata) result.setWcs(wcs) return result
def checkPersistence(self, skyWcs, bbox): """Check persistence of a SkyWcs """ className = "SkyWcs" # check writeString and readString skyWcsStr = skyWcs.writeString() serialVersion, serialClassName, serialRest = skyWcsStr.split(" ", 2) self.assertEqual(int(serialVersion), 1) self.assertEqual(serialClassName, className) badStr1 = " ".join(["2", serialClassName, serialRest]) with self.assertRaises(lsst.pex.exceptions.TypeError): skyWcs.readString(badStr1) badClassName = "x" + serialClassName badStr2 = " ".join(["1", badClassName, serialRest]) with self.assertRaises(lsst.pex.exceptions.TypeError): skyWcs.readString(badStr2) skyWcsFromStr1 = skyWcs.readString(skyWcsStr) self.assertEqual(skyWcs, skyWcsFromStr1) self.assertEqual(type(skyWcs), type(skyWcsFromStr1)) self.assertEqual(skyWcs.getFrameDict(), skyWcsFromStr1.getFrameDict()) pixelPoints = [ Point2D(0, 0), Point2D(1000, 0), Point2D(0, 1000), Point2D(-50, -50), ] skyPoints = skyWcs.pixelToSky(pixelPoints) pixelPoints2 = skyWcs.skyToPixel(skyPoints) assert_allclose(pixelPoints, pixelPoints2, atol=1e-7) # check that WCS is properly saved as part of an exposure FITS file exposure = ExposureF(100, 100, skyWcs) with lsst.utils.tests.getTempFilePath(".fits") as outFile: exposure.writeFits(outFile) exposureRoundTrip = ExposureF(outFile) wcsFromExposure = exposureRoundTrip.getWcs() self.assertWcsAlmostEqualOverBBox(skyWcs, wcsFromExposure, bbox)
def setUp(self): # Set up a Coadd with CoaddInputs tables that have blank filter # columns to be filled in by later test code. self.coadd = ExposureF(30, 90) # WCS is arbitrary, since it'll be the same for all images wcs = makeSkyWcs(crpix=Point2D(0, 0), crval=SpherePoint(45.0, 45.0, degrees), cdMatrix=makeCdMatrix(scale=0.17 * degrees)) self.coadd.setWcs(wcs) schema = ExposureCatalog.Table.makeMinimalSchema() self.filterKey = schema.addField("filter", type=str, doc="", size=16) weightKey = schema.addField("weight", type=float, doc="") # First input image covers the first 2/3, second covers the last 2/3, # so they overlap in the middle 1/3. inputs = ExposureCatalog(schema) self.input1 = inputs.addNew() self.input1.setId(1) self.input1.setBBox(Box2I(Point2I(0, 0), Point2I(29, 59))) self.input1.setWcs(wcs) self.input1.set(weightKey, 2.0) self.input2 = inputs.addNew() self.input2.setId(2) self.input2.setBBox(Box2I(Point2I(0, 30), Point2I(29, 89))) self.input2.setWcs(wcs) self.input2.set(weightKey, 3.0) # Use the same catalog for visits and CCDs since the algorithm we're # testing only cares about CCDs. self.coadd.getInfo().setCoaddInputs(CoaddInputs(inputs, inputs)) # Set up a catalog with centroids and a FilterFraction plugin. # We have one record in each region (first input only, both inputs, # second input only) schema = SourceCatalog.Table.makeMinimalSchema() centroidKey = Point2DKey.addFields(schema, "centroid", doc="position", unit="pixel") schema.getAliasMap().set("slot_Centroid", "centroid") self.plugin = FilterFractionPlugin( config=FilterFractionPlugin.ConfigClass(), schema=schema, name="subaru_FilterFraction", metadata=PropertyList()) catalog = SourceCatalog(schema) self.record1 = catalog.addNew() self.record1.set(centroidKey, Point2D(14.0, 14.0)) self.record12 = catalog.addNew() self.record12.set(centroidKey, Point2D(14.0, 44.0)) self.record2 = catalog.addNew() self.record2.set(centroidKey, Point2D(14.0, 74.0))
def testNoPsf(self): """Test InstallGaussianPsfTask when the input exposure has no PSF.""" for width in (21, 25): for fwhm in (2.8, 7.1): config = InstallGaussianPsfTask.ConfigClass() config.width = width config.fwhm = fwhm task = InstallGaussianPsfTask(config=config) exposure = ExposureF(100, 100) task.run(exposure=exposure) self.assertTrue(exposure.hasPsf()) psf = exposure.getPsf() psfIm = psf.computeImage() self.assertEqual(psfIm.getWidth(), width) self.assertEqual(psfIm.getHeight(), width) measFwhm = psf.computeShape().getDeterminantRadius( ) * FwhmPerSigma self.assertAlmostEqual(measFwhm, fwhm, delta=1e-3)
def adaptArgsAndRun(self, inputData, inputDataIds, outputDataIds, butler): """Operate on in-memory data. Returns ------- `Struct` instance with produced result. """ # calexps = inputData["calexp"] calexpDataIds = inputDataIds["calexp"] coaddDataIds = outputDataIds["coadd"] _LOG.info("executing %s: calexp=%s coadd=%s", self.getName(), calexpDataIds, coaddDataIds) # output data, scalar in this case data = ExposureF(100, 100) # attribute name of struct is the same as a config field name return Struct(coadd=data)
def testMatchSingleGaussianPsf(self): """Test InstallGaussianPsfTask when the input exposure has a single Gaussian PSF """ config = InstallGaussianPsfTask.ConfigClass() task = InstallGaussianPsfTask(config=config) for desWidth, desHeight, desSigma in ( (21, 23, 1.2), (23, 25, 3.5), ): exposure = ExposureF(100, 100) inPsf = SingleGaussianPsf(desWidth, desHeight, desSigma) exposure.setPsf(inPsf) task.run(exposure=exposure) self.assertTrue(exposure.hasPsf()) psf = exposure.getPsf() psfIm = psf.computeImage() self.assertEqual(psfIm.getWidth(), desWidth) self.assertEqual(psfIm.getHeight(), desHeight) self.assertAlmostEqual(psf.computeShape().getDeterminantRadius(), desSigma, delta=1e-3)
def test31035(self): """Test that illegal values in the header can be round-tripped.""" with lsst.utils.tests.getTempFilePath(".fits") as fileName: exp = ExposureF(width=100, height=100) md = exp.getMetadata() md['BORE-RA'] = 'NaN' md['BORE-DEC'] = 'NaN' md['BORE-AZ'] = 'NaN' md['BORE-ALT'] = 'NaN' md['BORE-AIRMASS'] = 'NaN' md['BORE-ROTANG'] = 'NaN' md['OBS-LONG'] = 'NaN' md['OBS-LAT'] = 'NaN' md['OBS-ELEV'] = 'NaN' md['AIRTEMP'] = 'NaN' md['AIRPRESS'] = 'NaN' md['HUMIDITY'] = 'NaN' exp.writeFits(fileName) _ = ExposureF.readFits(fileName)
def testMatchDoubleGaussianPsf(self): """Test InstallGaussianPsfTask when the input exposure has a DoubleGaussian PSF """ config = InstallGaussianPsfTask.ConfigClass() task = InstallGaussianPsfTask(config=config) for doubleGaussParms in ( # width, height, inner sigma, outer sigma, outer/inner peak amplitude (21, 23, 1.2, 3.5, 0.02), (23, 25, 3.5, 9.0, 0.02), ): exposure = ExposureF(100, 100) inPsf = DoubleGaussianPsf(*doubleGaussParms) exposure.setPsf(inPsf) desWidth, desHeight, innerSigma = doubleGaussParms[0:3] task.run(exposure=exposure) self.assertTrue(exposure.hasPsf()) psf = exposure.getPsf() psfIm = psf.computeImage() self.assertEqual(psfIm.getWidth(), desWidth) self.assertEqual(psfIm.getHeight(), desHeight) self.assertAlmostEqual(psf.computeShape().getDeterminantRadius(), innerSigma, delta=0.1)
def setUp(self): self.camera = CameraWrapper().camera self.detector = DetectorWrapper().detector self.crpix = lsst.geom.Point2D(50, 100) self.crval = lsst.geom.SpherePoint(36, 71, lsst.geom.degrees) scale = 1.0 * lsst.geom.arcseconds self.cdMatrix = afwGeom.makeCdMatrix(scale=scale) self.wcs = afwGeom.makeSkyWcs(crpix=self.crpix, crval=self.crval, cdMatrix=self.cdMatrix) self.bbox = lsst.geom.Box2I(lsst.geom.Point2I(-10, 10), lsst.geom.Extent2I(1000, 1022)) self.exposure = ExposureF(self.bbox) # set the few items of ExposureInfo needed by IsrTask.run # when only adding a distortion model exposureInfo = ExposureInfo(photoCalib=PhotoCalib(1.0), detector=self.detector, visitInfo=VisitInfo(exposureTime=1.0), wcs=self.wcs) self.exposure.setInfo(exposureInfo)
def run(self, calexp): """Operate on in-memory data. Returns ------- `Struct` instance with produced result. """ _LOG.info("executing %s: calexp=%s", self.getName(), calexp) # To test lsstDebug function make a debug.py file with this contents # somewhere in PYTHONPATH and run `pipetask` with --debug option: # # import lsstDebug # lsstDebug.Info('lsst.ctrl.mpexec.examples.calexpToCoaddTask').display = True # if lsstDebug.Info(__name__).display: _LOG.info("%s: display enabled", __name__) # output data, scalar in this case data = ExposureF(100, 100) # attribute name of struct is the same as a config field name return Struct(coadd=data)
def run(self, input): """Operate on in-memory data. With default implementation of `runQuantum()` keyword arguments correspond to field names in a config. Parameters ---------- input : `list` List of input data objects Returns ------- `Struct` instance with produced result. """ _LOG.info("executing %s: input=%s", self.getName(), input) # result, scalar in this case, just create 100x100 image data = ExposureF(100, 100) # attribute name of struct is the same as a config field name return Struct(output=data)
def displayAstrometry(refCat=None, sourceCat=None, distortedCentroidKey=None, bbox=None, exposure=None, matches=None, frame=1, title="", pause=True): """Show an astrometry debug image. Parameters ---------- refCat : `lsst.afw.table.SimpleCatalog` reference object catalog; must have fields "centroid_x" an "centroid_y" sourceCat : `lsst.afw.table.SourceCatalg` source catalog; must have field "slot_Centroid_x" and "slot_Centroid_y" distortedCentroidKey : `lsst.afw.table.Key` key for sourceCat with field to use for distorted positions exposure : `lsst.afw.image.Exposure` exposure to display bbox : `lsst.geom.Box2I` bounding box of exposure; Used if the exposure is `None` matches : `list` of `lsst.afw.table.ReferenceMatch` List of matched objects frame : `int` frame number for display title : `str` title for display pause : `bool` pause for inspection of display? This is done by dropping into pdb. Notes ----- - reference objects in refCat are shown as red X - sources in sourceCat are shown as green + - distorted sources in sourceCat (position given by distortedCentroidKey) are shown as green o - matches are shown as a yellow circle around the source and a yellow line connecting the reference object and source - if both exposure and bbox are `None`, no image is displayed """ disp = afwDisplay.getDisplay(frame=frame) if exposure is not None: disp.mtv(exposure, title=title) elif bbox is not None: disp.mtv(exposure=ExposureF(bbox), title=title) with disp.Buffering(): if refCat is not None: refCentroidKey = Point2DKey(refCat.schema["centroid"]) for refObj in refCat: rx, ry = refObj.get(refCentroidKey) disp.dot("x", rx, ry, size=10, ctype=afwDisplay.RED) if sourceCat is not None: sourceCentroidKey = Point2DKey(sourceCat.schema["slot_Centroid"]) for source in sourceCat: sx, sy = source.get(sourceCentroidKey) disp.dot("+", sx, sy, size=10, ctype=afwDisplay.GREEN) if distortedCentroidKey is not None: dx, dy = source.get(distortedCentroidKey) disp.dot("o", dx, dy, size=10, ctype=afwDisplay.GREEN) disp.line([(sx, sy), (dx, dy)], ctype=afwDisplay.GREEN) if matches is not None: refCentroidKey = Point2DKey(matches[0].first.schema["centroid"]) sourceCentroidKey = Point2DKey( matches[0].second.schema["slot_Centroid"]) radArr = np.ndarray(len(matches)) for i, m in enumerate(matches): refCentroid = m.first.get(refCentroidKey) sourceCentroid = m.second.get(sourceCentroidKey) radArr[i] = math.hypot(*(refCentroid - sourceCentroid)) sx, sy = sourceCentroid disp.dot("o", sx, sy, size=10, ctype=afwDisplay.YELLOW) disp.line([refCentroid, sourceCentroid], ctype=afwDisplay.YELLOW) print("<match radius> = %.4g +- %.4g [%d matches]" % (radArr.mean(), radArr.std(), len(matches))) if pause: print( "Dropping into debugger to allow inspection of display. Type 'continue' when done." ) import pdb pdb.set_trace()
from lsst.afw.image import ExposureF from lsst.meas.algorithms.installGaussianPsf import InstallGaussianPsfTask, FwhmPerSigma exposure = ExposureF(100, 100) task = InstallGaussianPsfTask() task.run(exposure=exposure) # This particular exposure had no PSF model to begin with, so the new PSF model # uses the config's FWHM. However, measured FWHM is based on the truncated # PSF image, so it does not exactly match the input measFwhm = exposure.getPsf().computeShape().getDeterminantRadius() * FwhmPerSigma assert abs(measFwhm - task.config.fwhm) < 1e-3
def displayAstrometry(refCat=None, sourceCat=None, distortedCentroidKey=None, bbox=None, exposure=None, matches=None, frame=1, title="", pause=True): """Show an astrometry debug image - reference objects in refCat are shown as red X - sources in sourceCat are shown as green + - distorted sources in sourceCat (position given by distortedCentroidKey) are shown as green o - matches are shown as a yellow circle around the source and a yellow line connecting the reference object and source - if both exposure and bbox are None, no image is displayed @param[in] refCat reference object catalog; must have fields "centroid_x" and "centroid_y" @param[in] sourceCat source catalog; must have field "slot_Centroid_x" and "slot_Centroid_y" @param[in] distortedCentroidKey key for sourceCat with field to use for distorted positions, or None @param[in] exposure exposure to display, or None for a blank exposure @param[in] bbox bounding box of exposure; used if exposure is None for a blank image @param[in] matches a list of lsst.afw.table.ReferenceMatch, or None @param[in] frame frame number for ds9 display @param[in] title title for ds9 display @param[in] pause pause for inspection of display? This is done by dropping into pdb. """ disp = afwDisplay.getDisplay(frame) if exposure is not None: disp.mtv(exposure, title=title) elif bbox is not None: disp.mtv(exposure=ExposureF(bbox), title=title) with disp.Buffering(): if refCat is not None: refCentroidKey = Point2DKey(refCat.schema["centroid"]) for refObj in refCat: rx, ry = refObj.get(refCentroidKey) disp.dot("x", rx, ry, size=10, ctype=afwDisplay.RED) if sourceCat is not None: sourceCentroidKey = Point2DKey(sourceCat.schema["slot_Centroid"]) for source in sourceCat: sx, sy = source.get(sourceCentroidKey) disp.dot("+", sx, sy, size=10, ctype=afwDisplay.GREEN) if distortedCentroidKey is not None: dx, dy = source.get(distortedCentroidKey) disp.dot("o", dx, dy, size=10, ctype=afwDisplay.GREEN) disp.line([(sx, sy), (dx, dy)], ctype=afwDisplay.GREEN) if matches is not None: refCentroidKey = Point2DKey(matches[0].first.schema["centroid"]) sourceCentroidKey = Point2DKey( matches[0].second.schema["slot_Centroid"]) radArr = np.ndarray(len(matches)) for i, m in enumerate(matches): refCentroid = m.first.get(refCentroidKey) sourceCentroid = m.second.get(sourceCentroidKey) radArr[i] = math.hypot(*(refCentroid - sourceCentroid)) sx, sy = sourceCentroid disp.dot("o", sx, sy, size=10, ctype=afwDisplay.YELLOW) disp.line([refCentroid, sourceCentroid], ctype=afwDisplay.YELLOW) print("<match radius> = %.4g +- %.4g [%d matches]" % (radArr.mean(), radArr.std(), len(matches))) if pause: print( "Dropping into debugger to allow inspection of display. Type 'continue' when done." ) import pdb pdb.set_trace()
def setUp(self): """Constructs a CCD with two amplifiers and prepares for ISR""" np.random.seed(12345) baseValue = 100.0 gain = 1.0 readNoise = 123456789.0 saturation = 987654321.0 height = 234 imageSize = Extent2I(123, height) overscanSize = Extent2I(16, height) self.sigma = 1.234 # Set up the various regions overscan1 = Box2I(Point2I(0, 0), overscanSize) image1 = Box2I(Point2I(overscanSize[0], 0), imageSize) image2 = Box2I(Point2I(overscanSize[0] + imageSize[0], 0), imageSize) overscan2 = Box2I(Point2I(overscanSize[0] + 2 * imageSize[0], 0), overscanSize) leftBox = Box2I( overscan1.getMin(), Extent2I(overscan1.getWidth() + image1.getWidth(), height)) rightBox = Box2I( image2.getMin(), Extent2I(image2.getWidth() + overscan2.getWidth(), height)) target1 = Box2I(Point2I(0, 0), imageSize) target2 = Box2I(Point2I(image1.getWidth(), 0), imageSize) # Set the pixels exposure = ExposureF( Box2I(Point2I(0, 0), Extent2I(imageSize[0] * 2 + overscanSize[0] * 2, height))) yy = np.arange(0, height, 1, dtype=np.float32) leftImage = ExposureF(exposure, leftBox) leftImage.image.array[:] = baseValue + yy[:, np.newaxis] rightImage = ExposureF(exposure, rightBox) rightImage.image.array[:] = baseValue - yy[:, np.newaxis] leftOverscan = ExposureF(exposure, overscan1) leftOverscan.image.array += np.random.normal( 0.0, self.sigma, leftOverscan.image.array.shape) rightOverscan = ExposureF(exposure, overscan2) rightOverscan.image.array += np.random.normal( 0.0, self.sigma, leftOverscan.image.array.shape) exposure.mask.array[:] = 0.0 exposure.variance.array[:] = np.nan # Construct the detectors amp1 = makeAmplifier("left", target1, image1, overscan1, gain, readNoise, saturation) amp2 = makeAmplifier("right", target2, image2, overscan2, gain, readNoise, saturation) ccdBox = Box2I(Point2I(0, 0), Extent2I(image1.getWidth() + image2.getWidth(), height)) camBuilder = cameraGeom.Camera.Builder("fakeCam") detBuilder = camBuilder.add("detector", 1) detBuilder.setSerial("det1") detBuilder.setBBox(ccdBox) detBuilder.setPixelSize(Extent2D(1.0, 1.0)) detBuilder.setOrientation(cameraGeom.Orientation()) detBuilder.append(amp1) detBuilder.append(amp2) cam = camBuilder.finish() exposure.setDetector(cam.get('detector')) header = PropertyList() header.add("EXPTIME", 0.0) exposure.getInfo().setVisitInfo(VisitInfo(header)) self.exposure = exposure self.config = IsrTask.ConfigClass() # Disable everything we don't care about self.config.doBias = False self.config.doDark = False self.config.doFlat = False self.config.doFringe = False self.config.doDefect = False self.config.doWrite = False self.config.expectWcs = False self.config.doLinearize = False self.config.doCrosstalk = False self.config.doBrighterFatter = False self.config.doAttachTransmissionCurve = False self.config.doAssembleCcd = False self.config.doNanMasking = False self.config.doInterpolate = False self.config.maskNegativeVariance = False # This runs on mocks. # Set the things that match our test setup self.config.overscan.fitType = "CHEB" self.config.overscan.order = 1 self.config.doEmpiricalReadNoise = True self.task = IsrTask(config=self.config)