def setUp(self): self.dataDir = os.path.join(os.path.split(__file__)[0], "data") # Check the values below against what was written by comparing with # the code in `afw/tests/data/makeTestExposure.py` nx = ny = 10 image = afwImage.ImageF(np.arange(nx * ny, dtype='f').reshape(nx, ny)) variance = afwImage.ImageF(np.ones((nx, ny), dtype='f')) mask = afwImage.MaskX(nx, ny) mask.array[5, 5] = 5 self.maskedImage = afwImage.MaskedImageF(image, mask, variance) self.v0PhotoCalib = afwImage.makePhotoCalibFromCalibZeroPoint(1e6, 2e4) self.v1PhotoCalib = afwImage.PhotoCalib(1e6, 2e4) self.v1FilterLabel = afwImage.FilterLabel(physical="ha") self.v2FilterLabel = afwImage.FilterLabel(band="N656", physical="ha")
def testMultiple(self, pedestal=0.0): """Test subtraction of multiple fringe frames Paramters --------- pedestal : `float`, optional Pedestal to add into fringe frame. """ xFreqList = [0.1, 0.13, 0.06] xOffsetList = [0.0, 0.1, 0.2] yFreqList = [0.09, 0.12, 0.07] yOffsetList = [0.3, 0.2, 0.1] fringeList = [ createFringe(self.size, self.size, xFreq, xOffset, yFreq, yOffset) for xFreq, xOffset, yFreq, yOffset in zip( xFreqList, xOffsetList, yFreqList, yOffsetList) ] for fringe in fringeList: fMi = fringe.getMaskedImage() fMi += pedestal # Generate science frame scales = [0.33, 0.33, 0.33] image = afwImage.ImageF(self.size, self.size) image.set(0) for s, f in zip(scales, fringeList): image.scaledPlus(s, f.getMaskedImage().getImage()) mi = afwImage.makeMaskedImage(image) exp = afwImage.makeExposure(mi) exp.setFilter(afwImage.FilterLabel(physical='FILTER')) task = FringeTask(name="multiFringe", config=self.config) self.checkFringe(task, exp, fringeList, stddevMax=1.0e-2)
def test_multiFringes(self): """Test that multi-fringe results are handled correctly by the task. """ self.config.large = 16 task = FringeTask(name="multiFringeMock", config=self.config) config = isrMock.IsrMockConfig() config.fringeScale = [750.0, 240.0, 220.0] config.fringeX0 = [100.0, 150.0, 200.0] config.fringeY0 = [0.0, 200.0, 0.0] dataRef = isrMock.FringeDataRefMock(config=config) exp = dataRef.get("raw") exp.setFilter(afwImage.FilterLabel(physical='FILTER')) medianBefore = np.nanmedian(exp.getImage().getArray()) fringes = task.readFringes(dataRef, assembler=None) solution, rms = task.run(exp, **fringes.getDict()) medianAfter = np.nanmedian(exp.getImage().getArray()) stdAfter = np.nanstd(exp.getImage().getArray()) self.assertLess(medianAfter, medianBefore) self.assertFloatsAlmostEqual(medianAfter, 3000.925, atol=1e-4) self.assertFloatsAlmostEqual(stdAfter, 3549.9885, atol=1e-4) deviation = np.abs(solution - config.fringeScale) self.assertTrue(np.all(deviation / rms < 1.0))
def setUp(self): super().setUp() afwImage.Filter.reset() afwImage.FilterProperty.reset() defineFilter("g", 470.0) self.wcs = afwGeom.makeSkyWcs( lsst.geom.Point2D(0.0, 0.0), lsst.geom.SpherePoint(2.0, 34.0, lsst.geom.degrees), np.identity(2), ) self.photoCalib = afwImage.PhotoCalib(1.5) self.psf = DummyPsf(2.0) self.detector = DetectorWrapper().detector self.summaryStats = afwImage.ExposureSummaryStats(ra=100.0) self.polygon = afwGeom.Polygon( lsst.geom.Box2D(lsst.geom.Point2D(0.0, 0.0), lsst.geom.Point2D(25.0, 20.0))) self.coaddInputs = afwImage.CoaddInputs() self.apCorrMap = afwImage.ApCorrMap() self.transmissionCurve = afwImage.TransmissionCurve.makeIdentity() self.exposureInfo = afwImage.ExposureInfo() gFilter = afwImage.Filter("g") gFilterLabel = afwImage.FilterLabel(band="g") self.exposureInfo.setFilter(gFilter) self.exposureInfo.setFilterLabel(gFilterLabel)
def testVisitInfoFitsPersistence(self): """Test saving an exposure to FITS and reading it back in preserves (some) VisitInfo fields""" exposureId = 5 exposureTime = 12.3 boresightRotAngle = 45.6 * lsst.geom.degrees weather = Weather(1.1, 2.2, 0.3) visitInfo = afwImage.VisitInfo( exposureId=exposureId, exposureTime=exposureTime, boresightRotAngle=boresightRotAngle, weather=weather, ) photoCalib = afwImage.PhotoCalib(3.4, 5.6) exposureInfo = afwImage.ExposureInfo() exposureInfo.setVisitInfo(visitInfo) exposureInfo.setPhotoCalib(photoCalib) exposureInfo.setDetector(self.detector) gFilter = afwImage.Filter("g") gFilterLabel = afwImage.FilterLabel(band="g") exposureInfo.setFilter(gFilter) exposureInfo.setFilterLabel(gFilterLabel) maskedImage = afwImage.MaskedImageF(inFilePathSmall) exposure = afwImage.ExposureF(maskedImage, exposureInfo) with lsst.utils.tests.getTempFilePath(".fits") as tmpFile: exposure.writeFits(tmpFile) rtExposure = afwImage.ExposureF(tmpFile) rtVisitInfo = rtExposure.getInfo().getVisitInfo() self.assertEqual(rtVisitInfo.getWeather(), weather) self.assertEqual(rtExposure.getPhotoCalib(), photoCalib) self.assertEqual(rtExposure.getFilter(), gFilter) self.assertEqual(rtExposure.getFilterLabel(), gFilterLabel)
def testExposureInfoConstructor(self): """Test the Exposure(maskedImage, exposureInfo) constructor""" exposureInfo = afwImage.ExposureInfo() exposureInfo.setWcs(self.wcs) exposureInfo.setDetector(self.detector) gFilter = afwImage.Filter("g") gFilterLabel = afwImage.FilterLabel(band="g") exposureInfo.setFilter(gFilter) exposureInfo.setFilterLabel(gFilterLabel) maskedImage = afwImage.MaskedImageF(inFilePathSmall) exposure = afwImage.ExposureF(maskedImage, exposureInfo) self.assertTrue(exposure.hasWcs()) self.assertEqual(exposure.getWcs().getPixelOrigin(), self.wcs.getPixelOrigin()) self.assertEqual(exposure.getDetector().getName(), self.detector.getName()) self.assertEqual(exposure.getDetector().getSerial(), self.detector.getSerial()) self.assertEqual(exposure.getFilter(), gFilter) self.assertEqual(exposure.getFilterLabel(), gFilterLabel) self.assertTrue(exposure.getInfo().hasWcs()) self.assertEqual(exposure.getInfo().getWcs().getPixelOrigin(), self.wcs.getPixelOrigin()) self.assertEqual(exposure.getInfo().getDetector().getName(), self.detector.getName()) self.assertEqual(exposure.getInfo().getDetector().getSerial(), self.detector.getSerial()) self.assertEqual(exposure.getInfo().getFilter(), gFilter) self.assertEqual(exposure.getInfo().getFilterLabel(), gFilterLabel)
def createFringe(width, height, xFreq, xOffset, yFreq, yOffset): """Create a fringe frame. Parameters ---------- width, height : `int` Size of image. xFreq, yFreq : `float` Frequency of sinusoids in x and y. xOffset, yOffset : `float` Phase of sinusoids in x and y. Returns ------- exp : `lsst.afw.image.ExposureF` Fringe frame. """ image = afwImage.ImageF(width, height) array = image.getArray() x, y = np.indices(array.shape) array[x, y] = np.sin(xFreq * x + xOffset) + np.sin(yFreq * y + yOffset) mi = afwImage.makeMaskedImage(image) exp = afwImage.makeExposure(mi) exp.setFilter(afwImage.FilterLabel(band='y', physical='FILTER')) return exp
def main(just_wfs=False, detector_list=None): if (just_wfs is True) and (detector_list is not None): raise RuntimeError("--just_wfs and --detector_list are exclusive.") camera = LsstCam().getCamera() if just_wfs: ccd_list = [ camera[name] for name in [ "R00_SW0", "R00_SW1", "R04_SW0", "R04_SW1", "R44_SW0", "R44_SW1", "R40_SW0", 'R40_SW1' ] ] elif (detector_list is not None): ccd_list = [camera[name] for name in detector_list] else: ccd_list = camera for filt_name in 'ugrizy': for ccd in ccd_list: name = ccd.getName() CHIPID = "".join([c for c in name if c != "," and c != ":"]) CHIPID = "_".join(CHIPID.split()) image = afwImage.ImageF(ccd.getBBox()) for amp in ccd: subim = afwImage.ImageF(image, amp.getBBox()) subim[:] = 1 / amp.getGain() print(amp.getName(), amp.getGain()) # need to flip the image to match the result of phosim repackager oldImageArray = image.array.copy() image.array[:] = np.flipud(oldImageArray) expInfo = afwImage.ExposureInfo() inFilter = afwImage.FilterLabel(filt_name) expInfo.setFilterLabel(inFilter) exp = afwImage.ExposureF(afwImage.MaskedImageF(image), expInfo) md = exp.getMetadata() md.set('CHIPID', CHIPID) # Set place holder date md.set('MJD-OBS', 53005.0) md.set('OBSTYPE', 'flat') # arbitrary for flats md.set('EXPTIME', 100) # need to be able to specify any filter md.set('CALDATE', 53005.0) # Add the CALIB_ID header card md.set( 'CALIB_ID', 'raftName=%s detectorName=%s detector=%i filter=%s calibDate=%s' % (CHIPID.split('_')[0], CHIPID.split('_')[1], ccd.getId(), filt_name, datetime.now())) exp.setMetadata(md) exp.writeFits("%(name)s_%(filter)s.fits" % ({ 'name': CHIPID, 'filter': filt_name }))
def __init__(self, shape=geom.Extent2I(201, 301), offset=geom.Point2I(-123, -45), backgroundLevel=314.592, seed=42, nSrc=37, fluxRange=2., noiseLevel=5, sourceSigma=200., minPsfSize=1.5, maxPsfSize=3., pixelScale=0.2 * arcseconds, ra=209. * degrees, dec=-20.25 * degrees, ccd=37, patch=42, patchGen2="2,3", tract=0): self.ra = ra self.dec = dec self.pixelScale = pixelScale self.patch = patch self.patchGen2 = patchGen2 self.tract = tract self.filterLabel = afwImage.FilterLabel(band="gTest", physical="gTest") self.rngData = np.random.default_rng(seed) self.rngMods = np.random.default_rng(seed + 1) self.bbox = geom.Box2I(offset, shape) if not self.bbox.contains(0, 0): raise ValueError( f"The bounding box must contain the coordinate (0, 0). {repr(self.bbox)}" ) self.wcs = self.makeDummyWcs() # Set up properties of the simulations nSigmaForKernel = 5 self.kernelSize = (int(maxPsfSize * nSigmaForKernel + 0.5) // 2) * 2 + 1 # make sure it is odd bufferSize = self.kernelSize // 2 x0, y0 = self.bbox.getBegin() xSize, ySize = self.bbox.getDimensions() # Set the pixel coordinates and fluxes of the simulated sources. self.xLoc = self.rngData.random(nSrc) * ( xSize - 2 * bufferSize) + bufferSize + x0 self.yLoc = self.rngData.random(nSrc) * ( ySize - 2 * bufferSize) + bufferSize + y0 self.flux = (self.rngData.random(nSrc) * (fluxRange - 1.) + 1.) * sourceSigma * noiseLevel self.backgroundLevel = backgroundLevel self.noiseLevel = noiseLevel self.minPsfSize = minPsfSize self.maxPsfSize = maxPsfSize self.detector = DetectorWrapper(name=f"detector {ccd}", id=ccd).detector
def setUp(self): np.random.seed(1234) self.cutoutSize = 35 self.center = lsst.geom.Point2D(50.1, 49.8) self.bbox = lsst.geom.Box2I(lsst.geom.Point2I(-20, -30), lsst.geom.Extent2I(140, 160)) self.dataset = lsst.meas.base.tests.TestDataset(self.bbox) self.dataset.addSource(100000.0, self.center) exposure, catalog = self.dataset.realize( 10.0, self.dataset.makeMinimalSchema(), randomSeed=0) self.exposure = exposure detector = DetectorWrapper(id=23, bbox=exposure.getBBox()).detector self.exposure.setDetector(detector) visit = afwImage.VisitInfo(exposureId=1234, exposureTime=200., date=dafBase.DateTime( "2014-05-13T17:00:00.000000000", dafBase.DateTime.Timescale.TAI)) self.exposure.info.id = 1234 self.exposure.getInfo().setVisitInfo(visit) self.exposure.setFilter( afwImage.FilterLabel(band='g', physical="g.MP9401")) diaObjects = makeDiaObjects(2, self.exposure) diaSourceHistory = makeDiaSources(10, diaObjects["diaObjectId"], self.exposure) diaForcedSources = makeDiaForcedSources(10, diaObjects["diaObjectId"], self.exposure) self.diaObjects, diaSourceHistory, self.diaForcedSources = _roundTripThroughApdb( diaObjects, diaSourceHistory, diaForcedSources, self.exposure.getInfo().getVisitInfo().getDate()) self.diaObjects.replace(to_replace=[None], value=np.nan, inplace=True) diaSourceHistory.replace(to_replace=[None], value=np.nan, inplace=True) self.diaForcedSources.replace(to_replace=[None], value=np.nan, inplace=True) diaSourceHistory["programId"] = 0 self.diaSources = diaSourceHistory.loc[[(1, "g", 9), (2, "g", 10)], :] self.diaSources["bboxSize"] = self.cutoutSize self.diaSourceHistory = diaSourceHistory.drop(labels=[(1, "g", 9), (2, "g", 10)]) self.cutoutWcs = wcs.WCS(naxis=2) self.cutoutWcs.wcs.crpix = [self.center[0], self.center[1]] self.cutoutWcs.wcs.crval = [ self.exposure.getWcs().getSkyOrigin().getRa().asDegrees(), self.exposure.getWcs().getSkyOrigin().getDec().asDegrees() ] self.cutoutWcs.wcs.cd = self.exposure.getWcs().getCdMatrix() self.cutoutWcs.wcs.ctype = ["RA---TAN", "DEC--TAN"]
def testNullWarpExposure(self, interpLength=10): """Test that warpExposure maps an image onto itself. Note: - NO_DATA and off-CCD pixels must be ignored - bad mask pixels get smeared out so we have to excluded all bad mask pixels from the output image when comparing masks. """ originalExposure = afwImage.ExposureF(originalExposurePath) originalExposure.getInfo().setId(10313423) originalExposure.getInfo().setVisitInfo(makeVisitInfo()) originalFilterLabel = afwImage.FilterLabel(band="i") originalPhotoCalib = afwImage.PhotoCalib(1.0e5, 1.0e3) originalExposure.setFilter(originalFilterLabel) originalExposure.setPhotoCalib(originalPhotoCalib) afwWarpedExposure = afwImage.ExposureF(originalExposure.getBBox(), originalExposure.getWcs()) warpingControl = afwMath.WarpingControl("lanczos4", "", 0, interpLength) afwMath.warpExposure(afwWarpedExposure, originalExposure, warpingControl) if SAVE_FITS_FILES: afwWarpedExposure.writeFits("afwWarpedExposureNull.fits") self.assertEqual(afwWarpedExposure.getFilter().bandLabel, originalFilterLabel.bandLabel) self.assertEqual(afwWarpedExposure.getPhotoCalib(), originalPhotoCalib) self.assertEqual(afwWarpedExposure.getInfo().getVisitInfo(), originalExposure.getInfo().getVisitInfo()) afwWarpedMaskedImage = afwWarpedExposure.getMaskedImage() afwWarpedMask = afwWarpedMaskedImage.getMask() noDataBitMask = afwWarpedMask.getPlaneBitMask("NO_DATA") afwWarpedMaskedImageArrSet = afwWarpedMaskedImage.getArrays() afwWarpedMaskArr = afwWarpedMaskedImageArrSet[1] # compare all non-DATA pixels of image and variance, but relax specs a bit # because of minor noise introduced by bad pixels noDataMaskArr = afwWarpedMaskArr & noDataBitMask msg = "afw null-warped MaskedImage (all pixels, relaxed tolerance)" self.assertMaskedImagesAlmostEqual(afwWarpedMaskedImage, originalExposure.getMaskedImage(), doMask=False, skipMask=noDataMaskArr, atol=1e-5, msg=msg) # compare good pixels (mask=0) of image, mask and variance using full # tolerance msg = "afw null-warped MaskedImage (good pixels, max tolerance)" self.assertMaskedImagesAlmostEqual(afwWarpedMaskedImage, originalExposure.getMaskedImage(), skipMask=afwWarpedMask, msg=msg)
def testSetMembers(self): """ Test that the MaskedImage and the WCS of an Exposure can be set. """ exposure = afwImage.ExposureF() maskedImage = afwImage.MaskedImageF(inFilePathSmall) exposure.setMaskedImage(maskedImage) exposure.setWcs(self.wcs) exposure.setDetector(self.detector) exposure.setFilter(afwImage.Filter("g")) exposure.setFilterLabel(afwImage.FilterLabel(band="g")) self.assertEqual(exposure.getDetector().getName(), self.detector.getName()) self.assertEqual(exposure.getDetector().getSerial(), self.detector.getSerial()) self.assertEqual(exposure.getFilter().getName(), "g") self.assertEqual(exposure.getFilterLabel().bandLabel, "g") self.assertEqual(exposure.getWcs(), self.wcs) # The PhotoCalib tests are in test_photoCalib.py; # here we just check that it's gettable and settable. self.assertIsNone(exposure.getPhotoCalib()) photoCalib = afwImage.PhotoCalib(511.1, 44.4) exposure.setPhotoCalib(photoCalib) self.assertEqual(exposure.getPhotoCalib(), photoCalib) # Psfs next self.assertFalse(exposure.hasPsf()) exposure.setPsf(self.psf) self.assertTrue(exposure.hasPsf()) exposure.setPsf(DummyPsf(1.0)) # we can reset the Psf # extras next info = exposure.getInfo() for key, value in self.extras.items(): self.assertFalse(info.hasComponent(key)) self.assertIsNone(info.getComponent(key)) info.setComponent(key, value) self.assertTrue(info.hasComponent(key)) self.assertEqual(info.getComponent(key), value) info.removeComponent(key) self.assertFalse(info.hasComponent(key)) # Test that we can set the MaskedImage and WCS of an Exposure # that already has both self.exposureMiWcs.setMaskedImage(maskedImage) exposure.setWcs(self.wcs)
def setUp(self): # Load sample input from disk testDir = os.path.dirname(__file__) self.srcCat = afwTable.SourceCatalog.readFits( os.path.join(testDir, "data", "v695833-e0-c000.xy.fits")) self.srcCat["slot_ApFlux_instFluxErr"] = 1 self.srcCat["slot_PsfFlux_instFluxErr"] = 1 # The .xy.fits file has sources in the range ~ [0,2000],[0,4500] # which is bigger than the exposure self.bbox = geom.Box2I(geom.Point2I(0, 0), geom.Extent2I(2048, 4612)) smallExposure = afwImage.ExposureF( os.path.join(testDir, "data", "v695833-e0-c000-a00.sci.fits")) self.exposure = afwImage.ExposureF(self.bbox) self.exposure.setWcs(smallExposure.getWcs()) self.exposure.setFilter( afwImage.FilterLabel(band="i", physical="test-i")) self.exposure.setPhotoCalib(smallExposure.getPhotoCalib()) coordKey = self.srcCat.getCoordKey() centroidKey = self.srcCat.getCentroidSlot().getMeasKey() wcs = self.exposure.getWcs() for src in self.srcCat: src.set(coordKey, wcs.pixelToSky(src.get(centroidKey))) # Make a reference loader filenames = sorted( glob.glob( os.path.join(RefCatDir, 'ref_cats', 'cal_ref_cat', '??????.fits'))) self.refObjLoader = MockReferenceObjectLoaderFromFiles(filenames, htmLevel=8) self.log = logging.getLogger('lsst.testPhotoCal') self.log.setLevel(TRACE) self.config = PhotoCalConfig() self.config.match.matchRadius = 0.5 self.config.match.referenceSelection.doMagLimit = True self.config.match.referenceSelection.magLimit.maximum = 22.0 self.config.match.referenceSelection.magLimit.fluxField = "i_flux" self.config.match.referenceSelection.doFlags = True self.config.match.referenceSelection.flags.good = ['photometric'] self.config.match.referenceSelection.flags.bad = ['resolved'] self.config.match.sourceSelection.doUnresolved = False # Don't have star/galaxy in the srcCat # The test and associated data have been prepared on the basis that we # use the PsfFlux to perform photometry. self.config.fluxField = "base_PsfFlux_instFlux"
def testFilter(self): """Test that the same (patched) filter is returned through all Butler retrieval paths. """ mapper = MinMapper2(root=ROOT) butler = dafPersist.ButlerFactory(mapper=mapper).create() image = butler.get("someExp", ccd=35) filter = butler.get("someExp_filterLabel", ccd=35) # Test only valid with a complete filter self.assertEqual(image.getFilterLabel(), afwImage.FilterLabel(band="r", physical="r.MP9601")) # Datasets should give consistent answers self.assertEqual(filter, image.getFilterLabel())
def _setFilter(self, mapping, item, dataId): """To ensure that ctio0m9 exposures get both physical and band set. Notes ----- ctio0m9 has very non-typical filters, and uses the physical filter name in the refcat loader filterMap, so we want to duplicate the physical name into the band name here. These filters don't have a standard "band" like "g", so these band names won't get confused with anything else. """ idFilter = mapping.need(['filter'], dataId)['filter'] item.setFilterLabel( afwImage.FilterLabel(physical=idFilter, band=idFilter))
def testStandardizeFiltersFilterNoDefs(self): testLabels = [ None, afwImage.FilterLabel(band="i", physical="i.MP9701"), afwImage.FilterLabel(band="i"), afwImage.FilterLabel(physical="i.MP9701"), afwImage.FilterLabel(band="i", physical="old-i"), afwImage.FilterLabel(physical="old-i"), afwImage.FilterLabel(physical="i2"), ] testIds = [{ "visit": 12345, "ccd": 42, "filter": f } for f in { "i", "i.MP9701", "old-i", "i2", }] testData = [] # Resolve special combinations where the expected output is different for input in testLabels: for dataId in testIds: if input is None: # Can still get some filter info out of the Filter registry if dataId["filter"] == "i2": data = (input, dataId, afwImage.FilterLabel(band="i", physical="HSC-I2")) else: # Data ID maps to filter(s) with aliases; can't # unambiguously determine physical filter. data = (input, dataId, afwImage.FilterLabel(band="i")) else: data = (input, dataId, input) testData.append(data) mapper = MinMapper1(root=ROOT) for label, dataId, corrected in testData: exposure = afwImage.ExposureF() exposure.setFilterLabel(label) mapper._setFilter(mapper.exposures['raw'], exposure, dataId) self.assertEqual(exposure.getFilterLabel(), corrected, msg=f"Started from {label} and {dataId}")
def __init__(self, root, **kwargs): self.storage = lsst.daf.persistence.Storage.makeFromURI(root) super(SimpleMapper, self).__init__(**kwargs) self.root = root self.camera = makeSimpleCamera(nX=1, nY=2, sizeX=400, sizeY=200, gapX=2, gapY=2) # NOTE: we set band/physical here because CoaddsTestCase.testCoaddInputs() # expects "r" for both the input dataIds (gen2 dataIds could be either # physical or band) and the output CoaddInputRecords. # The original data had just `Filter("r")`, so this has always assumed # that physicalLabel==bandLabel, even though CoaddInputRecords are physical. self.filterLabel = afwImage.FilterLabel(band="r", physical="r") self.update()
def testCopyExposure(self): """Copy an Exposure (maybe changing type)""" exposureU = afwImage.ExposureU(inFilePathSmall, allowUnsafe=True) exposureU.setWcs(self.wcs) exposureU.setDetector(self.detector) exposureU.setFilter(afwImage.Filter("g")) exposureU.setFilterLabel(afwImage.FilterLabel(band="g")) exposureU.setPsf(DummyPsf(4.0)) infoU = exposureU.getInfo() for key, value in self.extras.items(): infoU.setComponent(key, value) exposureF = exposureU.convertF() self.cmpExposure(exposureF, exposureU) nexp = exposureF.Factory(exposureF, False) self.cmpExposure(exposureF, nexp)
def run(self, inputExp, inputSources): """XXX Docs """ # TODO: Change this to doing this the proper way referenceFilterName = self.config.referenceFilterOverride referenceFilterLabel = afwImage.FilterLabel( physical=referenceFilterName, band=referenceFilterName) # there's a better way of doing this with the task I think originalFilterLabel = inputExp.getFilterLabel() inputExp.setFilterLabel(referenceFilterLabel) successfulFit = False try: astromResult = self.astrometry.run(sourceCat=inputSources, exposure=inputExp) scatter = astromResult.scatterOnSky.asArcseconds() inputExp.setFilterLabel(originalFilterLabel) if scatter < 1: successfulFit = True except (RuntimeError, TaskError): self.log.warn("Solver failed to run completely") inputExp.setFilterLabel(originalFilterLabel) if successfulFit: target = inputExp.getMetadata()['OBJECT'] centroid = getTargetCentroidFromWcs(inputExp, target, logger=self.log) else: result = self.qfmTask.run(inputExp) centroid = result.brightestObjCentroid centroidTuple = (centroid[0], centroid[1] ) # unify Point2D or tuple to tuple self.log.info( f"Centroid of main star found at {centroidTuple} found" f" via {'astrometry' if successfulFit else 'QuickFrameMeasurement'}" ) result = pipeBase.Struct(atmospecCentroid={ 'centroid': centroidTuple, 'astrometricMatch': successfulFit }) return result
def make_exp(gsimage, bmask, noise, galsim_wcs, galsim_psf, psf_dim): dm_wcs = make_dm_wcs(galsim_wcs) dm_psf = make_dm_psf(psf=galsim_psf, psf_dim=psf_dim, wcs=galsim_wcs) ny, nx = gsimage.array.shape masked_image = afw_image.MaskedImageF(width=nx, height=ny) masked_image.image.array[:, :] = gsimage.array masked_image.variance.array[:, :] = noise**2 masked_image.mask.array[:, :] = bmask.array exp = afw_image.ExposureF(masked_image) filter_label = afw_image.FilterLabel(band='i', physical='i') exp.setFilterLabel(filter_label) exp.setPsf(dm_psf) exp.setWcs(dm_wcs) return exp
def runAstrometry(self, butler, exp, icSrc): refObjLoaderConfig = LoadIndexedReferenceObjectsTask.ConfigClass() refObjLoaderConfig.ref_dataset_name = 'gaia_dr2_20191105' refObjLoaderConfig.pixelMargin = 1000 refObjLoader = LoadIndexedReferenceObjectsTask( butler=butler, config=refObjLoaderConfig) astromConfig = AstrometryTask.ConfigClass() astromConfig.wcsFitter.retarget(FitAffineWcsTask) astromConfig.referenceSelector.doMagLimit = True magLimit = MagnitudeLimit() magLimit.minimum = 1 magLimit.maximum = 15 astromConfig.referenceSelector.magLimit = magLimit astromConfig.referenceSelector.magLimit.fluxField = "phot_g_mean_flux" astromConfig.matcher.maxRotationDeg = 5.99 astromConfig.matcher.maxOffsetPix = 3000 astromConfig.sourceSelector['matcher'].minSnr = 10 solver = AstrometryTask(config=astromConfig, refObjLoader=refObjLoader) # TODO: Change this to doing this the proper way referenceFilterName = self.config.referenceFilterOverride referenceFilterLabel = afwImage.FilterLabel( physical=referenceFilterName, band=referenceFilterName) originalFilterLabel = exp.getFilterLabel( ) # there's a better way of doing this with the task I think exp.setFilterLabel(referenceFilterLabel) try: astromResult = solver.run(sourceCat=icSrc, exposure=exp) exp.setFilterLabel(originalFilterLabel) except (RuntimeError, TaskError): self.log.warn("Solver failed to run completely") exp.setFilterLabel(originalFilterLabel) return None scatter = astromResult.scatterOnSky.asArcseconds() if scatter < 1: return astromResult else: self.log.warn("Failed to find an acceptable match") return None
def setUp(self): refCatDir = os.path.join(os.path.dirname(__file__), "data", "sdssrefcat") self.bbox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(3001, 3001)) crpix = lsst.geom.Box2D(self.bbox).getCenter() self.tanWcs = afwGeom.makeSkyWcs( crpix=crpix, crval=lsst.geom.SpherePoint(215.5, 53.0, lsst.geom.degrees), cdMatrix=afwGeom.makeCdMatrix(scale=5.1e-5 * lsst.geom.degrees)) self.exposure = afwImage.ExposureF(self.bbox) self.exposure.setWcs(self.tanWcs) self.exposure.setFilter( afwImage.FilterLabel(band="r", physical="rTest")) filenames = sorted( glob.glob( os.path.join(refCatDir, 'ref_cats', 'cal_ref_cat', '??????.fits'))) self.refObjLoader = MockReferenceObjectLoaderFromFiles(filenames, htmLevel=8)
def testBBox(self): """Test that the default bounding box includes all warped pixels """ kernelName = "lanczos2" warper = afwMath.Warper(kernelName) originalExposure, swarpedImage, swarpedWcs = self.getSwarpedImage( kernelName=kernelName, useSubregion=True, useDeepCopy=False) originalFilterLabel = afwImage.FilterLabel(band="i") originalPhotoCalib = afwImage.PhotoCalib(1.0e5, 1.0e3) originalExposure.setFilterLabel(originalFilterLabel) originalExposure.setPhotoCalib(originalPhotoCalib) warpedExposure1 = warper.warpExposure(destWcs=swarpedWcs, srcExposure=originalExposure) # the default size must include all good pixels, so growing the bbox # should not add any warpedExposure2 = warper.warpExposure(destWcs=swarpedWcs, srcExposure=originalExposure, border=1) # a bit of excess border is allowed, but surely not as much as 10 (in # fact it is approx. 5) warpedExposure3 = warper.warpExposure(destWcs=swarpedWcs, srcExposure=originalExposure, border=-10) # assert that warpedExposure and warpedExposure2 have the same number of non-no_data pixels # and that warpedExposure3 has fewer noDataBitMask = afwImage.Mask.getPlaneBitMask("NO_DATA") mask1Arr = warpedExposure1.getMaskedImage().getMask().getArray() mask2Arr = warpedExposure2.getMaskedImage().getMask().getArray() mask3Arr = warpedExposure3.getMaskedImage().getMask().getArray() nGood1 = (mask1Arr & noDataBitMask == 0).sum() nGood2 = (mask2Arr & noDataBitMask == 0).sum() nGood3 = (mask3Arr & noDataBitMask == 0).sum() self.assertEqual(nGood1, nGood2) self.assertLess(nGood3, nGood1) self.assertEqual(warpedExposure1.getFilterLabel().bandLabel, originalFilterLabel.bandLabel) self.assertEqual(warpedExposure1.getPhotoCalib(), originalPhotoCalib)
def std_raw(self, item, dataId, filter=True): """Standardize a raw dataset by converting it to an `~lsst.afw.image.Exposure` instead of an `~lsst.afw.image.Image`.""" exp = self._standardizeExposure( self.exposures['raw'], item, dataId, trimmed=False, setVisitInfo=False, # it's already set, and the metadata's stripped setExposureId=False, filter=False) if filter: obsInfo = ObservationInfo(exp.getMetadata(), translator_class=self.translatorClass) band = self.filterDefinitions.physical_to_band[ obsInfo.physical_filter] filt = afwImage.FilterLabel(physical=obsInfo.physical_filter, band=band) exp.setFilterLabel(filt) return exp
def make_exp( *, rng, band, noise, objlist, shifts, dim, psf, psf_dim, g1, g2, star_objlist=None, star_shifts=None, draw_stars=True, bright_objlist=None, bright_shifts=None, bright_mags=None, coadd_bbox_cen_gs_skypos, dither=False, rotate=False, mask_threshold=None, cosmic_rays=False, bad_columns=False, star_bleeds=False, sky_n_sigma=None, draw_method='auto', ): """ Make an SEObs Parameters ---------- rng: numpy.random.RandomState The random number generator band: str Band as a string, e.g. 'i' noise: float Gaussian noise level objlist: list List of GSObj shifts: array List of PositionD representing offsets dim: int Dimension of image psf: GSObject or PowerSpectrumPSF the psf psf_dim: int Dimensions of psf image that will be drawn when psf func is called coadd_bbox_cen_gs_skypos: galsim.CelestialCoord The sky position of the center (origin) of the coadd we will make, as a galsim object not stack object dither: bool If set to True, dither randomly by a pixel width rotate: bool If set to True, rotate the image randomly star_objlist: list List of GSObj for stars star_shifts: array List of PositionD for stars representing offsets draw_stars: bool, optional Draw the stars, don't just mask bright ones. Default True. bright_objlist: list, optional List of GSObj for bright objects bright_shifts: array, optional List of PositionD for stars representing offsets bright_mags: array, optional Mags for the bright objects mask_threshold: float Bright masks are created such that the profile goes out to this threshold cosmic_rays: bool If True, put in cosmic rays bad_columns: bool If True, put in bad columns star_bleeds: bool If True, add bleed trails to stars sky_n_sigma: float Number of sigma to set the sky value. Can be negative to mock up a sky oversubtraction. Default None. draw_method: string Draw method for galsim objects, default 'auto'. Set to 'phot' to get poisson noise. Note this is much slower. Returns ------- exp: lsst.afw.image.ExposureF Exposure data bright_info: list of structured arrays fields are ra, dec: sky position of bright stars radius_pixels: radius of mask in pixels has_bleed: bool, True if there is a bleed trail """ shear = galsim.Shear(g1=g1, g2=g2) dims = [dim] * 2 cen = (np.array(dims) - 1) / 2 se_origin = galsim.PositionD(x=cen[1], y=cen[0]) if dither: dither_range = 0.5 off = rng.uniform(low=-dither_range, high=dither_range, size=2) offset = galsim.PositionD(x=off[0], y=off[1]) se_origin = se_origin + offset if rotate: theta = rng.uniform(low=0, high=2 * np.pi) else: theta = None # galsim wcs se_wcs = make_wcs( scale=SCALE, theta=theta, image_origin=se_origin, world_origin=coadd_bbox_cen_gs_skypos, ) image = galsim.Image(dim, dim, wcs=se_wcs) _draw_objects( image, objlist, shifts, psf, draw_method, coadd_bbox_cen_gs_skypos, rng, shear=shear, ) if star_objlist is not None and draw_stars: assert star_shifts is not None, 'send star_shifts with star_objlist' _draw_objects( image, star_objlist, star_shifts, psf, draw_method, coadd_bbox_cen_gs_skypos, rng, ) image.array[:, :] += rng.normal(scale=noise, size=dims) if sky_n_sigma is not None: image.array[:, :] += sky_n_sigma * noise # pixels flagged as bad cols and cosmics will get # set to np.nan bmask = get_bmask_and_set_image( image=image, rng=rng, cosmic_rays=cosmic_rays, bad_columns=bad_columns, ) if bright_objlist is not None: bright_info = _draw_bright_objects( image=image, noise=noise, origin=se_origin, bmask=bmask, band=band, objlist=bright_objlist, shifts=bright_shifts, mags=bright_mags, psf=psf, coadd_bbox_cen_gs_skypos=coadd_bbox_cen_gs_skypos, mask_threshold=mask_threshold, rng=rng, star_bleeds=star_bleeds, draw_stars=draw_stars, ) else: bright_info = [] dm_wcs = make_dm_wcs(se_wcs) dm_psf = make_dm_psf(psf=psf, psf_dim=psf_dim, wcs=se_wcs) variance = image.copy() variance.array[:, :] = noise**2 masked_image = afw_image.MaskedImageF(dim, dim) masked_image.image.array[:, :] = image.array masked_image.variance.array[:, :] = variance.array masked_image.mask.array[:, :] = bmask.array exp = afw_image.ExposureF(masked_image) filter_label = afw_image.FilterLabel(band=band, physical=band) exp.setFilterLabel(filter_label) exp.setPsf(dm_psf) exp.setWcs(dm_wcs) detector = DetectorWrapper().detector exp.setDetector(detector) return exp, bright_info
def makeExposure(flipX=False, flipY=False): """Create an exposure and flip the x or y (or both) coordinates. Returns bounding boxes that are right or left handed around the bounding polygon. Parameters ---------- flipX : `bool` Flip the x coordinate in the WCS. flipY : `bool` Flip the y coordinate in the WCS. Returns ------- exposure : `lsst.afw.image.Exposure` Exposure with a valid bounding box and wcs. """ metadata = dafBase.PropertySet() metadata.set("SIMPLE", "T") metadata.set("BITPIX", -32) metadata.set("NAXIS", 2) metadata.set("NAXIS1", 1024) metadata.set("NAXIS2", 1153) metadata.set("RADECSYS", 'FK5') metadata.set("EQUINOX", 2000.) metadata.setDouble("CRVAL1", 215.604025685476) metadata.setDouble("CRVAL2", 53.1595451514076) metadata.setDouble("CRPIX1", 1109.99981456774) metadata.setDouble("CRPIX2", 560.018167811613) metadata.set("CTYPE1", 'RA---SIN') metadata.set("CTYPE2", 'DEC--SIN') xFlip = 1 if flipX: xFlip = -1 yFlip = 1 if flipY: yFlip = -1 metadata.setDouble("CD1_1", xFlip * 5.10808596133527E-05) metadata.setDouble("CD1_2", yFlip * 1.85579539217196E-07) metadata.setDouble("CD2_2", yFlip * -5.10281493481982E-05) metadata.setDouble("CD2_1", xFlip * -8.27440751733828E-07) wcs = afwGeom.makeSkyWcs(metadata) exposure = afwImage.makeExposure( afwImage.makeMaskedImageFromArrays(np.ones((1024, 1153))), wcs) detector = DetectorWrapper(id=23, bbox=exposure.getBBox()).detector visit = afwImage.VisitInfo(exposureId=1234, exposureTime=200., date=dafBase.DateTime( "2014-05-13T17:00:00.000000000", dafBase.DateTime.Timescale.TAI)) exposure.info.id = 1234 exposure.setDetector(detector) exposure.getInfo().setVisitInfo(visit) exposure.setFilter(afwImage.FilterLabel(band='g')) return exposure
def _computeReferenceOffsets(self, stdCat, lutCat, physicalFilterMap, bands): """ Compute offsets relative to a reference catalog. This method splits the star catalog into healpix pixels and computes the calibration transfer for a sample of these pixels to approximate the 'absolute' calibration values (on for each band) to apply to transfer the absolute scale. Parameters ---------- stdCat : `lsst.afw.table.SimpleCatalog` FGCM standard stars lutCat : `lsst.afw.table.SimpleCatalog` FGCM Look-up table physicalFilterMap : `dict` Dictionary of mappings from physical filter to FGCM band. bands : `list` [`str`] List of band names from FGCM output Returns ------- offsets : `numpy.array` of floats Per band zeropoint offsets """ # Only use stars that are observed in all the bands that were actually used # This will ensure that we use the same healpix pixels for the absolute # calibration of each band. minObs = stdCat['ngood'].min(axis=1) goodStars = (minObs >= 1) stdCat = stdCat[goodStars] self.log.info( "Found %d stars with at least 1 good observation in each band" % (len(stdCat))) # Associate each band with the appropriate physicalFilter and make # filterLabels filterLabels = [] lutPhysicalFilters = lutCat[0]['physicalFilters'].split(',') lutStdPhysicalFilters = lutCat[0]['stdPhysicalFilters'].split(',') physicalFilterMapBands = list(physicalFilterMap.values()) physicalFilterMapFilters = list(physicalFilterMap.keys()) for band in bands: # Find a physical filter associated from the band by doing # a reverse lookup on the physicalFilterMap dict physicalFilterMapIndex = physicalFilterMapBands.index(band) physicalFilter = physicalFilterMapFilters[physicalFilterMapIndex] # Find the appropriate fgcm standard physicalFilter lutPhysicalFilterIndex = lutPhysicalFilters.index(physicalFilter) stdPhysicalFilter = lutStdPhysicalFilters[lutPhysicalFilterIndex] filterLabels.append( afwImage.FilterLabel(band=band, physical=stdPhysicalFilter)) # We have to make a table for each pixel with flux/fluxErr # This is a temporary table generated for input to the photoCal task. # These fluxes are not instFlux (they are top-of-the-atmosphere approximate and # have had chromatic corrections applied to get to the standard system # specified by the atmosphere/instrumental parameters), nor are they # in Jansky (since they don't have a proper absolute calibration: the overall # zeropoint is estimated from the telescope size, etc.) sourceMapper = afwTable.SchemaMapper(stdCat.schema) sourceMapper.addMinimalSchema(afwTable.SimpleTable.makeMinimalSchema()) sourceMapper.editOutputSchema().addField( 'instFlux', type=np.float64, doc="instrumental flux (counts)") sourceMapper.editOutputSchema().addField( 'instFluxErr', type=np.float64, doc="instrumental flux error (counts)") badStarKey = sourceMapper.editOutputSchema().addField('flag_badStar', type='Flag', doc="bad flag") # Split up the stars # Note that there is an assumption here that the ra/dec coords stored # on-disk are in radians, and therefore that starObs['coord_ra'] / # starObs['coord_dec'] return radians when used as an array of numpy float64s. theta = np.pi / 2. - stdCat['coord_dec'] phi = stdCat['coord_ra'] ipring = hp.ang2pix(self.config.referencePixelizationNside, theta, phi) h, rev = esutil.stat.histogram(ipring, rev=True) gdpix, = np.where(h >= self.config.referencePixelizationMinStars) self.log.info( "Found %d pixels (nside=%d) with at least %d good stars" % (gdpix.size, self.config.referencePixelizationNside, self.config.referencePixelizationMinStars)) if gdpix.size < self.config.referencePixelizationNPixels: self.log.warning( "Found fewer good pixels (%d) than preferred in configuration (%d)" % (gdpix.size, self.config.referencePixelizationNPixels)) else: # Sample out the pixels we want to use gdpix = np.random.choice( gdpix, size=self.config.referencePixelizationNPixels, replace=False) results = np.zeros(gdpix.size, dtype=[('hpix', 'i4'), ('nstar', 'i4', len(bands)), ('nmatch', 'i4', len(bands)), ('zp', 'f4', len(bands)), ('zpErr', 'f4', len(bands))]) results['hpix'] = ipring[rev[rev[gdpix]]] # We need a boolean index to deal with catalogs... selected = np.zeros(len(stdCat), dtype=bool) refFluxFields = [None] * len(bands) for p_index, pix in enumerate(gdpix): i1a = rev[rev[pix]:rev[pix + 1]] # the stdCat afwTable can only be indexed with boolean arrays, # and not numpy index arrays (see DM-16497). This little trick # converts the index array into a boolean array selected[:] = False selected[i1a] = True for b_index, filterLabel in enumerate(filterLabels): struct = self._computeOffsetOneBand(sourceMapper, badStarKey, b_index, filterLabel, stdCat, selected, refFluxFields) results['nstar'][p_index, b_index] = len(i1a) results['nmatch'][p_index, b_index] = len(struct.arrays.refMag) results['zp'][p_index, b_index] = struct.zp results['zpErr'][p_index, b_index] = struct.sigma # And compute the summary statistics offsets = np.zeros(len(bands)) for b_index, band in enumerate(bands): # make configurable ok, = np.where( results['nmatch'][:, b_index] >= self.config.referenceMinMatch) offsets[b_index] = np.median(results['zp'][ok, b_index]) # use median absolute deviation to estimate Normal sigma # see https://en.wikipedia.org/wiki/Median_absolute_deviation madSigma = 1.4826 * np.median( np.abs(results['zp'][ok, b_index] - offsets[b_index])) self.log.info( "Reference catalog offset for %s band: %.12f +/- %.12f", band, offsets[b_index], madSigma) return offsets
def bypass_deepCoadd_filterLabel(self, *args, **kwargs): """To return a useful filterLabel for MergeDetectionsTask.""" return afwImage.FilterLabel(band=self.filterLabel.bandLabel)
def setUp(self): # metadata taken from CFHT data # v695856-e0/v695856-e0-c000-a00.sci_img.fits self.metadata = dafBase.PropertySet() self.metadata.set("SIMPLE", "T") self.metadata.set("BITPIX", -32) self.metadata.set("NAXIS", 2) self.metadata.set("NAXIS1", 1024) self.metadata.set("NAXIS2", 1153) self.metadata.set("RADECSYS", 'FK5') self.metadata.set("EQUINOX", 2000.) self.metadata.setDouble("CRVAL1", 215.604025685476) self.metadata.setDouble("CRVAL2", 53.1595451514076) self.metadata.setDouble("CRPIX1", 1109.99981456774) self.metadata.setDouble("CRPIX2", 560.018167811613) self.metadata.set("CTYPE1", 'RA---SIN') self.metadata.set("CTYPE2", 'DEC--SIN') self.metadata.setDouble("CD1_1", 5.10808596133527E-05) self.metadata.setDouble("CD1_2", 1.85579539217196E-07) self.metadata.setDouble("CD2_2", -5.10281493481982E-05) self.metadata.setDouble("CD2_1", -8.27440751733828E-07) self.wcs = afwGeom.makeSkyWcs(self.metadata) self.calibration = 10000 self.calibrationErr = 100 self.exposureId = 1234 self.exposureTime = 200. self.imageSize = [1024, 1153] self.dateTime = "2014-05-13T17:00:00.000000000" # Make images with one source in them and distinct values and # variance for each image. # Direct Image source_image = afwImage.MaskedImageF( lsst.geom.ExtentI(self.imageSize[0] + 1, self.imageSize[1] + 1)) source_image.image[100, 100, afwImage.LOCAL] = 10 source_image.getVariance().set(1) bbox = lsst.geom.BoxI( lsst.geom.PointI(1, 1), lsst.geom.ExtentI(self.imageSize[0], self.imageSize[1])) masked_image = afwImage.MaskedImageF(source_image, bbox, afwImage.LOCAL) self.exposure = afwImage.makeExposure(masked_image, self.wcs) detector = DetectorWrapper( id=23, bbox=self.exposure.getBBox()).detector visit = afwImage.VisitInfo( exposureId=self.exposureId, exposureTime=self.exposureTime, date=dafBase.DateTime(self.dateTime, dafBase.DateTime.Timescale.TAI)) self.exposure.info.id = self.exposureId self.exposure.setDetector(detector) self.exposure.getInfo().setVisitInfo(visit) self.exposure.setFilter(afwImage.FilterLabel(band='g', physical='g.MP9401')) self.exposure.setPhotoCalib(afwImage.PhotoCalib(self.calibration, self.calibrationErr)) # Difference Image source_image = afwImage.MaskedImageF( lsst.geom.ExtentI(self.imageSize[0] + 1, self.imageSize[1] + 1)) source_image.image[100, 100, afwImage.LOCAL] = 20 source_image.getVariance().set(2) bbox = lsst.geom.BoxI( lsst.geom.PointI(1, 1), lsst.geom.ExtentI(self.imageSize[0], self.imageSize[1])) masked_image = afwImage.MaskedImageF(source_image, bbox, afwImage.LOCAL) self.diffim = afwImage.makeExposure(masked_image, self.wcs) self.diffim.info.id = self.exposureId self.diffim.setDetector(detector) self.diffim.getInfo().setVisitInfo(visit) self.diffim.setFilter(afwImage.FilterLabel(band='g', physical='g.MP9401')) self.diffim.setPhotoCalib(afwImage.PhotoCalib(self.calibration, self.calibrationErr)) self.expIdBits = 16 FWHM = 5 psf = measAlg.DoubleGaussianPsf(15, 15, FWHM/(2*np.sqrt(2*np.log(2)))) self.exposure.setPsf(psf) self.diffim.setPsf(psf) self.testDiaObjects = create_test_dia_objects(5, self.wcs) # Add additional diaObjects that are outside of the above difference # and calexp visit images. objects = [ (10000000, self.wcs.pixelToSky(-100000, -100000)), # xy outside (10000001, self.wcs.pixelToSky(100, -100000)), # y outside (10000002, self.wcs.pixelToSky(-100000, 100)), # x outside ] extra = pandas.DataFrame({ "diaObjectId": np.array([id for id, point in objects], dtype=np.int64), "ra": [point.getRa().asDegrees() for id, point in objects], "decl": [point.getDec().asDegrees() for id, point in objects] }) self.testDiaObjects = pd.concat([self.testDiaObjects, extra], ignore_index=True) # Ids of objects that were "updated" during "ap_association" # processing. self.updatedTestIds = np.array([1, 2, 3, 4, 10000001], dtype=np.uint64) # Expecdted number of sources is the number of updated ids plus # any that are within the CCD footprint but are not in the # above list of ids. self.expectedDiaForcedSources = 6 self.expected_n_columns = 11
def testStandardizeFiltersFilterDefs(self): testLabels = [ (None, None), (afwImage.FilterLabel(band="i", physical="i.MP9701"), afwImage.FilterLabel(band="i", physical="i.MP9701")), (afwImage.FilterLabel(band="i"), afwImage.FilterLabel(band="r", physical="i.MP9701")), (afwImage.FilterLabel(physical="i.MP9701"), afwImage.FilterLabel(band="i", physical="i.MP9701")), (afwImage.FilterLabel(band="i", physical="old-i"), afwImage.FilterLabel(band="i", physical="i.MP9701")), (afwImage.FilterLabel(physical="old-i"), afwImage.FilterLabel(band="i", physical="i.MP9701")), (afwImage.FilterLabel(physical="i2"), afwImage.FilterLabel(band="i", physical="HSC-I2")), ] testIds = [{ "visit": 12345, "ccd": 42, "filter": f } for f in { "i", "i.MP9701", "old-i", "i2", }] testData = [] # Resolve special combinations where the expected output is different for input, corrected in testLabels: for dataId in testIds: if input is None: if dataId["filter"] == "i": data = (input, dataId, afwImage.FilterLabel(band="i")) elif dataId["filter"] == "i2": data = (input, dataId, afwImage.FilterLabel(band="i", physical="HSC-I2")) else: data = (input, dataId, afwImage.FilterLabel(band="i", physical="i.MP9701")) elif input == afwImage.FilterLabel(band="i"): if dataId["filter"] == "i": # There are two "i" filters, can't tell which data = (input, dataId, input) elif dataId["filter"] == "i2": data = (input, dataId, afwImage.FilterLabel(band="i", physical="HSC-I2")) elif corrected.physicalLabel == "HSC-I2" and dataId[ "filter"] in ("i.MP9701", "old-i"): # Contradictory inputs, leave as-is data = (input, dataId, input) elif corrected.physicalLabel == "i.MP9701" and dataId[ "filter"] == "i2": # Contradictory inputs, leave as-is data = (input, dataId, input) else: data = (input, dataId, corrected) testData.append(data) mapper = MinMapper2(root=ROOT) for label, dataId, corrected in testData: exposure = afwImage.ExposureF() exposure.setFilterLabel(label) mapper._setFilter(mapper.exposures['raw'], exposure, dataId) self.assertEqual(exposure.getFilterLabel(), corrected, msg=f"Started from {label} and {dataId}")