def check(self, expectFactor): schema = SourceTable.makeMinimalSchema() task = DynamicDetectionTask(config=self.config, schema=schema) table = SourceTable.make(schema) results = task.run(table, self.exposure, expId=12345) self.assertFloatsAlmostEqual(results.factor, expectFactor, rtol=self.rtol)
def __init__(self, butler=None, refObjLoader=None, schema=None, **kwargs): """!Construct a CharacterizeImageTask @param[in] butler A butler object is passed to the refObjLoader constructor in case it is needed to load catalogs. May be None if a catalog-based star selector is not used, if the reference object loader constructor does not require a butler, or if a reference object loader is passed directly via the refObjLoader argument. @param[in] refObjLoader An instance of LoadReferenceObjectsTasks that supplies an external reference catalog to a catalog-based star selector. May be None if a catalog star selector is not used or the loader can be constructed from the butler argument. @param[in,out] schema initial schema (an lsst.afw.table.SourceTable), or None @param[in,out] kwargs other keyword arguments for lsst.pipe.base.CmdLineTask """ pipeBase.CmdLineTask.__init__(self, **kwargs) if schema is None: schema = SourceTable.makeMinimalSchema() self.schema = schema self.makeSubtask("background") self.makeSubtask("installSimplePsf") self.makeSubtask("repair") self.makeSubtask("measurePsf", schema=self.schema) if self.config.doMeasurePsf and self.measurePsf.usesMatches: if not refObjLoader: self.makeSubtask('refObjLoader', butler=butler) refObjLoader = self.refObjLoader self.makeSubtask("astrometry", refObjLoader=refObjLoader) self.makeSubtask("detectAndMeasure", schema=self.schema) self._initialFrame = getDebugFrame(self._display, "frame") or 1 self._frame = self._initialFrame self.schema.checkUnits(parse_strict=self.config.checkUnitsParseStrict)
def __init__(self, *args, **kwargs): """Constructor Besides the usual initialisation of configurables, we also set up the forced measurement which is deliberately not represented in this Task's configuration parameters because we're using it as part of the algorithm and we don't want to allow it to be modified. """ SourceDetectionTask.__init__(self, *args, **kwargs) self.makeSubtask("skyObjects") # Set up forced measurement. config = ForcedMeasurementTask.ConfigClass() config.plugins.names = [ 'base_TransformedCentroid', 'base_PsfFlux', 'base_LocalBackground' ] # We'll need the "centroid" and "psfFlux" slots for slot in ("shape", "psfShape", "apFlux", "modelFlux", "gaussianFlux", "calibFlux"): setattr(config.slots, slot, None) config.copyColumns = {} self.skySchema = SourceTable.makeMinimalSchema() self.skyMeasurement = ForcedMeasurementTask(config=config, name="skyMeasurement", parentTask=self, refSchema=self.skySchema)
def check(self, expectFactor): schema = SourceTable.makeMinimalSchema() task = DynamicDetectionTask(config=self.config, schema=schema) table = SourceTable.make(schema) results = task.run(table, self.exposure, expId=12345) self.assertFloatsAlmostEqual(results.factor, expectFactor, rtol=self.rtol)
def __init__(self, schema=None, butler=None, **kwargs): """Initalize things! This should go above in the class docstring """ super().__init__(**kwargs) if schema is None: schema = SourceTable.makeMinimalSchema() self.schema = schema self.makeSubtask("insertFakes") self.makeSubtask("calibrate")
def testNoPsfUsed(self): """Test that the "calib_psfUsed" is required to measure aperture correction I hope someday DetectAndMeasureTask can determine for itself which sources are suitable for measuring aperture correction, at which point I expect this test to be deleted. """ schema = SourceTable.makeMinimalSchema() config = DetectAndMeasureTask.ConfigClass() config.doMeasureApCorr = True with self.assertRaises(Exception): DetectAndMeasureTask(config=config, schema=schema)
def testNoPsfUsed(self): """Test that the "calib_psfUsed" is required to measure aperture correction I hope someday DetectAndMeasureTask can determine for itself which sources are suitable for measuring aperture correction, at which point I expect this test to be deleted. """ schema = SourceTable.makeMinimalSchema() config = DetectAndMeasureTask.ConfigClass() config.doMeasureApCorr = True with self.assertRaises(Exception): DetectAndMeasureTask(config=config, schema=schema)
def testBasics(self): """Test detection and measurement on simple synthesized data """ bbox = Box2I(Point2I(256, 100), Extent2I(128, 127)) minCounts = 5000 maxCounts = 50000 starSigma = 1.5 numX = 5 numY = 5 coordList = self.makeCoordList( bbox=bbox, numX=numX, numY=numY, minCounts=minCounts, maxCounts=maxCounts, sigma=starSigma, ) kwid = 11 # kernel width sky = 2000 # create an exposure without a Wcs; add the Wcs later exposure = plantSources(bbox=bbox, kwid=kwid, sky=sky, coordList=coordList, addPoissonNoise=True) schema = SourceTable.makeMinimalSchema() config = DetectAndMeasureTask.ConfigClass() task = DetectAndMeasureTask(config=config, schema=schema) butler = Butler(root=InputDir) dataRef = butler.dataRef("calexp", dataId=dict(visit=1)) wcs = dataRef.get("raw").getWcs() exposure.setWcs(wcs) exposureIdInfo = dataRef.get("expIdInfo") taskRes = task.run(exposure=exposure, exposureIdInfo=exposureIdInfo) self.assertEqual(len(taskRes.sourceCat), numX * numY) schema = taskRes.sourceCat.schema centroidFlagKey = schema.find("slot_Centroid_flag").getKey() parentKey = schema.find("parent").getKey() psfFluxFlagKey = schema.find("slot_PsfFlux_flag").getKey() psfFluxKey = schema.find("slot_PsfFlux_flux").getKey() for src in taskRes.sourceCat: self.assertFalse(src.get(centroidFlagKey)) # centroid found self.assertEqual(src.get(parentKey), 0) # not debelended self.assertFalse(src.get(psfFluxFlagKey)) # flux measured self.assertGreater(src.get(psfFluxKey), 4000) # flux sane
def __init__(self, butler=None, refObjLoader=None, schema=None, **kwargs): """!Construct a CharacterizeImageTask @param[in] butler A butler object is passed to the refObjLoader constructor in case it is needed to load catalogs. May be None if a catalog-based star selector is not used, if the reference object loader constructor does not require a butler, or if a reference object loader is passed directly via the refObjLoader argument. # TODO DM-34769: remove rebObjLoader kwarg here. @param[in] refObjLoader An instance of LoadReferenceObjectsTasks that supplies an external reference catalog to a catalog-based star selector. May be None if a catalog star selector is not used or the loader can be constructed from the butler argument. @param[in,out] schema initial schema (an lsst.afw.table.SourceTable), or None @param[in,out] kwargs other keyword arguments for lsst.pipe.base.CmdLineTask """ super().__init__(**kwargs) if schema is None: schema = SourceTable.makeMinimalSchema() self.schema = schema self.makeSubtask("background") self.makeSubtask("installSimplePsf") self.makeSubtask("repair") self.makeSubtask("measurePsf", schema=self.schema) # TODO DM-34769: remove this `if` block if self.config.doMeasurePsf and self.measurePsf.usesMatches: if not refObjLoader: self.makeSubtask('refObjLoader', butler=butler) refObjLoader = self.refObjLoader self.makeSubtask("ref_match", refObjLoader=refObjLoader) self.algMetadata = dafBase.PropertyList() self.makeSubtask('detection', schema=self.schema) if self.config.doDeblend: self.makeSubtask("deblend", schema=self.schema) self.makeSubtask('measurement', schema=self.schema, algMetadata=self.algMetadata) if self.config.doApCorr: self.makeSubtask('measureApCorr', schema=self.schema) self.makeSubtask('applyApCorr', schema=self.schema) self.makeSubtask('catalogCalculation', schema=self.schema) self._initialFrame = getDebugFrame(self._display, "frame") or 1 self._frame = self._initialFrame self.schema.checkUnits(parse_strict=self.config.checkUnitsParseStrict) self.outputSchema = afwTable.SourceCatalog(self.schema)
def __init__(self, schema=None, **kwargs): """!Construct a CharacterizeImageTask @param[in,out] schema initial schema (an lsst.afw.table.SourceTable), or None @param[in,out] kwargs other keyword arguments for lsst.pipe.base.CmdLineTask """ pipeBase.CmdLineTask.__init__(self, **kwargs) if schema is None: schema = SourceTable.makeMinimalSchema() self.schema = schema self.makeSubtask("installSimplePsf") self.makeSubtask("repair") self.makeSubtask("measurePsf", schema=self.schema) if self.config.doMeasurePsf and self.measurePsf.usesMatches: self.makeSubtask("astrometry") self.makeSubtask("detectAndMeasure", schema=self.schema) self._initialFrame = getDebugFrame(self._display, "frame") or 1 self._frame = self._initialFrame
def __init__(self, schema=None, butler=None, **kwargs): """Initalize things! This should go above in the class docstring """ super().__init__(**kwargs) if schema is None: schema = SourceTable.makeMinimalSchema() self.schema = schema self.makeSubtask("insertFakes") self.algMetadata = dafBase.PropertyList() self.makeSubtask("detection", schema=self.schema) self.makeSubtask("deblend", schema=self.schema) self.makeSubtask("measurement", schema=self.schema, algMetadata=self.algMetadata) self.makeSubtask("applyApCorr", schema=self.schema) self.makeSubtask("catalogCalculation", schema=self.schema)
def __init__(self, schema=None, **kwargs): """!Construct a CharacterizeImageTask @param[in,out] schema initial schema (an lsst.afw.table.SourceTable), or None @param[in,out] kwargs other keyword arguments for lsst.pipe.base.CmdLineTask """ pipeBase.CmdLineTask.__init__(self, **kwargs) if schema is None: schema = SourceTable.makeMinimalSchema() self.schema = schema self.makeSubtask("installSimplePsf") self.makeSubtask("repair") self.makeSubtask("measurePsf", schema=self.schema) if self.config.doMeasurePsf and self.measurePsf.usesMatches: self.makeSubtask("astrometry") self.makeSubtask("detectAndMeasure", schema=self.schema) self._initialFrame = getDebugFrame(self._display, "frame") or 1 self._frame = self._initialFrame
def testBasics(self): """Test detection and measurement on simple synthesized data """ bbox = Box2I(Point2I(256, 100), Extent2I(128, 127)) minCounts = 5000 maxCounts = 50000 starSigma = 1.5 numX = 5 numY = 5 coordList = self.makeCoordList( bbox=bbox, numX=numX, numY=numY, minCounts=minCounts, maxCounts=maxCounts, sigma=starSigma, ) kwid = 11 # kernel width sky = 2000 # create an exposure without a Wcs; add the Wcs later exposure = plantSources(bbox=bbox, kwid=kwid, sky=sky, coordList=coordList, addPoissonNoise=True) schema = SourceTable.makeMinimalSchema() config = DetectAndMeasureTask.ConfigClass() task = DetectAndMeasureTask(config=config, schema=schema) butler = Butler(root=InputDir) dataRef = butler.dataRef("calexp", dataId=dict(visit=1)) wcs = dataRef.get("raw").getWcs() exposure.setWcs(wcs) exposureIdInfo = dataRef.get("expIdInfo") taskRes = task.run(exposure=exposure, exposureIdInfo=exposureIdInfo) self.assertEqual(len(taskRes.sourceCat), numX * numY) schema = taskRes.sourceCat.schema centroidFlagKey = schema.find("slot_Centroid_flag").getKey() parentKey = schema.find("parent").getKey() psfFluxFlagKey = schema.find("slot_PsfFlux_flag").getKey() psfFluxKey = schema.find("slot_PsfFlux_flux").getKey() for src in taskRes.sourceCat: self.assertFalse(src.get(centroidFlagKey)) # centroid found self.assertEqual(src.get(parentKey), 0) # not debelended self.assertFalse(src.get(psfFluxFlagKey)) # flux measured self.assertGreater(src.get(psfFluxKey), 4000) # flux sane
def __init__(self, *args, **kwargs): SourceDetectionTask.__init__(self, *args, **kwargs) self.makeSubtask("skyObjects") # Set up forced measurement. config = ForcedMeasurementTask.ConfigClass() config.plugins.names = [ 'base_TransformedCentroid', 'base_PsfFlux', 'base_LocalBackground' ] # We'll need the "centroid" and "psfFlux" slots for slot in ("shape", "psfShape", "apFlux", "modelFlux", "gaussianFlux", "calibFlux"): setattr(config.slots, slot, None) config.copyColumns = {} self.skySchema = SourceTable.makeMinimalSchema() self.skyMeasurement = ForcedMeasurementTask(config=config, name="skyMeasurement", parentTask=self, refSchema=self.skySchema)
def __init__(self, *args, **kwargs): """Constructor Besides the usual initialisation of configurables, we also set up the forced measurement which is deliberately not represented in this Task's configuration parameters because we're using it as part of the algorithm and we don't want to allow it to be modified. """ SourceDetectionTask.__init__(self, *args, **kwargs) self.makeSubtask("skyObjects") # Set up forced measurement. config = ForcedMeasurementTask.ConfigClass() config.plugins.names = ['base_TransformedCentroid', 'base_PsfFlux', 'base_LocalBackground'] # We'll need the "centroid" and "psfFlux" slots for slot in ("shape", "psfShape", "apFlux", "modelFlux", "gaussianFlux", "calibFlux"): setattr(config.slots, slot, None) config.copyColumns = {} self.skySchema = SourceTable.makeMinimalSchema() self.skyMeasurement = ForcedMeasurementTask(config=config, name="skyMeasurement", parentTask=self, refSchema=self.skySchema)
def __init__(self, dataPrefix="", schema=None, **kwargs): """Construct a DetectAndMeasureTask Arguments in addition to the standard Task arguments: @param[in] dataPrefix prefix for name of source tables; - for calexp use the default of "" - for coadds use coaddName + "Coadd" @param[in,out] schema schema for sources; if None then one is constructed """ pipeBase.Task.__init__(self, **kwargs) self.dataPrefix = dataPrefix self.algMetadata = dafBase.PropertyList() if schema is None: schema = SourceTable.makeMinimalSchema() self.schema = schema self.makeSubtask("detection", schema=self.schema) if self.config.doDeblend: self.makeSubtask("deblend", schema=self.schema) self.makeSubtask("measurement", schema=self.schema, algMetadata=self.algMetadata) if self.config.doMeasureApCorr: # add field to flag stars useful for measuring aperture correction self.makeSubtask("measureApCorr", schema=schema)
def __init__(self, butler=None, schema=None, **kwargs): """!Construct a CharacterizeSpotsTask @param[in] butler A butler object is passed to the refObjLoader constructor in case it is needed to load catalogs. May be None if a catalog-based star selector is not used, if the reference object loader constructor does not require a butler, or if a reference object loader is passed directly via the refObjLoader argument. @param[in,out] schema initial schema (an lsst.afw.table.SourceTable), or None @param[in,out] kwargs other keyword arguments for lsst.pipe.base.CmdLineTask """ super().__init__(**kwargs) if schema is None: schema = SourceTable.makeMinimalSchema() self.schema = schema self.makeSubtask("installSimplePsf") self.makeSubtask("repair") self.algMetadata = dafBase.PropertyList() self.makeSubtask('measurement', schema=self.schema, algMetadata=self.algMetadata) self.makeSubtask('catalogCalculation', schema=self.schema) self._initialFrame = getDebugFrame(self._display, "frame") or 1 self._frame = self._initialFrame self.schema.checkUnits(parse_strict=self.config.checkUnitsParseStrict) self.outputSchema = afwTable.SourceCatalog(self.schema)
def __init__(self, dataPrefix="", schema=None, **kwargs): """Construct a DetectAndMeasureTask Arguments in addition to the standard Task arguments: @param[in] dataPrefix prefix for name of source tables; - for calexp use the default of "" - for coadds use coaddName + "Coadd" @param[in,out] schema schema for sources; if None then one is constructed """ pipeBase.Task.__init__(self, **kwargs) self.dataPrefix = dataPrefix self.algMetadata = dafBase.PropertyList() if schema is None: schema = SourceTable.makeMinimalSchema() self.schema = schema self.makeSubtask("detection", schema=self.schema) if self.config.doDeblend: self.makeSubtask("deblend", schema=self.schema) self.makeSubtask("measurement", schema=self.schema, algMetadata=self.algMetadata) if self.config.doMeasureApCorr: # add field to flag stars useful for measuring aperture correction self.makeSubtask("measureApCorr", schema=schema)
def execute(self, dataRef): """!Characterize a science image @param dataRef: butler data reference @return a pipeBase Struct containing the results """ self.log.info("Performing Super CharacterizeImage on sensor data ID %s" % (dataRef.dataId,)) self.log.info("Reading input data using dataRef") inputData = self.read_input_data(dataRef) self.log.info("Running operations. The run() method should not take anything Butler") result = CharacterizeImageTask.characterize(CharacterizeImageTask(config=self.config, log=self.log, schema=SourceTable.makeMinimalSchema()), **inputData.getDict()) self.log.info("Writing output data using dataRef") self.write_output_data(dataRef, result) return result
def getClumps(self, sigma=1.0, display=False): if self._num <= 0: raise RuntimeError("No candidate PSF sources") psfImage = self.getImage() # # Embed psfImage into a larger image so we can smooth when measuring it # width, height = psfImage.getWidth(), psfImage.getHeight() largeImg = psfImage.Factory(afwGeom.ExtentI(2 * width, 2 * height)) largeImg.set(0) bbox = afwGeom.BoxI(afwGeom.PointI(width, height), afwGeom.ExtentI(width, height)) largeImg.assign(psfImage, bbox, afwImage.LOCAL) # # Now measure that image, looking for the highest peak. Start by building an Exposure # msk = afwImage.MaskU(largeImg.getDimensions()) msk.set(0) var = afwImage.ImageF(largeImg.getDimensions()) var.set(1) mpsfImage = afwImage.MaskedImageF(largeImg, msk, var) mpsfImage.setXY0(afwGeom.PointI(-width, -height)) del msk del var exposure = afwImage.makeExposure(mpsfImage) # # Next run an object detector # maxVal = afwMath.makeStatistics(psfImage, afwMath.MAX).getValue() threshold = maxVal - sigma * math.sqrt(maxVal) if threshold <= 0.0: threshold = maxVal threshold = afwDetection.Threshold(threshold) ds = afwDetection.FootprintSet(mpsfImage, threshold, "DETECTED") # # And measure it. This policy isn't the one we use to measure # Sources, it's only used to characterize this PSF histogram # schema = SourceTable.makeMinimalSchema() psfImageConfig = SingleFrameMeasurementConfig() psfImageConfig.slots.centroid = "base_SdssCentroid" psfImageConfig.plugins["base_SdssCentroid"].doFootprintCheck = False psfImageConfig.slots.psfFlux = None # "base_PsfFlux" psfImageConfig.slots.apFlux = "base_CircularApertureFlux_3_0" psfImageConfig.slots.modelFlux = None psfImageConfig.slots.instFlux = None psfImageConfig.slots.calibFlux = None psfImageConfig.slots.shape = "base_SdssShape" # Formerly, this code had centroid.sdss, flux.psf, flux.naive, # flags.pixel, and shape.sdss psfImageConfig.algorithms.names = [ "base_SdssCentroid", "base_CircularApertureFlux", "base_SdssShape" ] psfImageConfig.algorithms["base_CircularApertureFlux"].radii = [3.0] psfImageConfig.validate() task = SingleFrameMeasurementTask(schema, config=psfImageConfig) sourceCat = SourceCatalog(schema) gaussianWidth = 1.5 # Gaussian sigma for detection convolution exposure.setPsf(algorithmsLib.DoubleGaussianPsf(11, 11, gaussianWidth)) ds.makeSources(sourceCat) # # Show us the Histogram # if display: frame = 1 dispImage = mpsfImage.Factory( mpsfImage, afwGeom.BoxI(afwGeom.PointI(width, height), afwGeom.ExtentI(width, height)), afwImage.LOCAL) ds9.mtv(dispImage, title="PSF Selection Image", frame=frame) clumps = list() # List of clumps, to return e = None # thrown exception IzzMin = 1.0 # Minimum value for second moments IzzMax = ( self._xSize / 8.0)**2 # Max value ... clump radius should be < clumpImgSize/8 apFluxes = [] task.run( sourceCat, exposure) # notes that this is backwards for the new framework for i, source in enumerate(sourceCat): if source.getCentroidFlag(): continue x, y = source.getX(), source.getY() apFluxes.append(source.getApFlux()) val = mpsfImage.getImage().get(int(x) + width, int(y) + height) psfClumpIxx = source.getIxx() psfClumpIxy = source.getIxy() psfClumpIyy = source.getIyy() if display: if i == 0: ds9.pan(x, y, frame=frame) ds9.dot("+", x, y, ctype=ds9.YELLOW, frame=frame) ds9.dot("@:%g,%g,%g" % (psfClumpIxx, psfClumpIxy, psfClumpIyy), x, y, ctype=ds9.YELLOW, frame=frame) if psfClumpIxx < IzzMin or psfClumpIyy < IzzMin: psfClumpIxx = max(psfClumpIxx, IzzMin) psfClumpIyy = max(psfClumpIyy, IzzMin) if display: ds9.dot("@:%g,%g,%g" % (psfClumpIxx, psfClumpIxy, psfClumpIyy), x, y, ctype=ds9.RED, frame=frame) det = psfClumpIxx * psfClumpIyy - psfClumpIxy * psfClumpIxy try: a, b, c = psfClumpIyy / det, -psfClumpIxy / det, psfClumpIxx / det except ZeroDivisionError: a, b, c = 1e4, 0, 1e4 clumps.append( Clump(peak=val, x=x, y=y, a=a, b=b, c=c, ixx=psfClumpIxx, ixy=psfClumpIxy, iyy=psfClumpIyy)) if len(clumps) == 0: msg = "Failed to determine center of PSF clump" if e: msg += ": %s" % e raise RuntimeError(msg) # if it's all we got return it if len(clumps) == 1: return clumps # which clump is the best? # if we've undistorted the moments, stars should only have 1 clump # use the apFlux from the clump measurement, and take the highest # ... this clump has more psf star candidate neighbours than the others. # get rid of any that are huge, and thus poorly defined goodClumps = [] for clump in clumps: if clump.ixx < IzzMax and clump.iyy < IzzMax: goodClumps.append(clump) # if culling > IzzMax cost us all clumps, we'll have to take what we have if len(goodClumps) == 0: goodClumps = clumps # use the 'brightest' clump iBestClump = numpy.argsort(apFluxes)[0] clumps = [clumps[iBestClump]] return clumps
def run(self, ccdExposure): """Mask negative pixels""" ccd = ccdExposure.getDetector() ccdExposure = self.convertIntToFloat(ccdExposure) self.updateVariance(ccdExposure, ccd[0]) # Treating as having only a single amplifier image = ccdExposure.getMaskedImage().getImage() mask = ccdExposure.getMaskedImage().getMask() bad = mask.getPlaneBitMask("BAD") if False: mask.getArray()[:] = numpy.where(image <= 0, bad, 0) # XXX this causes bad things to happen #from lsst.afw.image.utils import clipImage #clipImage(image,0,10) #exit() """ transfer wcs system to TAN """ matches = ReferenceMatchVector() md = ccdExposure.getMetadata() wcs = ccdExposure.getWcs() refSchema = SimpleTable.makeMinimalSchema() Point2DKey.addFields(refSchema, "centroid", "centroid position", "pixel") refCatalog = SimpleCatalog(refSchema) schema = SourceTable.makeMinimalSchema() centroidKey = Point2DKey.addFields(schema, "centroid", "centroid position", "pixel") imgCatalog = SourceCatalog(schema) imgCatalog.defineCentroid("centroid") # for i in numpy.linspace(10, md.get("ZNAXIS1")-10, 20): # for j in numpy.linspace(10, md.get("ZNAXIS2")-10, 20): for i in numpy.linspace(10, 4000, 10): for j in numpy.linspace(10, 4000, 10): imgcrd = Point2D(i,j) skycrd = wcs.pixelToSky(afwGeom.Point2D(i, j)) # Create the reference catalog (with coordinates on the sky) refSrc = refCatalog.addNew() refSrc.setCoord(skycrd) # Create the position catalog (with positions on the image) imgSrc = imgCatalog.addNew() imgSrc.set(centroidKey, imgcrd) # matches matches.push_back(ReferenceMatch(refSrc, imgSrc, float("NaN"))) # make initial wcs refPix = afwGeom.Point2D(0.5*ccdExposure.getWidth(), 0.5*ccdExposure.getHeight()) refSky = wcs.pixelToSky(refPix) xPixelScale = yPixelScale = (0.2*afwGeom.arcseconds).asDegrees() initanWcs = afwImage.makeWcs(refSky, refPix, xPixelScale, 0.0, 0.0, yPixelScale) # obtain modified wcs with matched catalogs fitter = FitTanSipWcsTask() fitRes = fitter.fitWcs( matches = matches, initWcs = initanWcs, refCat = refCatalog, sourceCat = imgCatalog, ) ccdExposure.setWcs(fitRes.wcs) """ Set zero point, ZP error, exptime """ zp = md.get("MAGZPT") ccdExposure.getCalib().setFluxMag0(10.0**(0.4*zp)) return lsst.pipe.base.Struct(exposure=ccdExposure)
def getClumps(self, sigma=1.0, display=False): if self._num <= 0: raise RuntimeError("No candidate PSF sources") psfImage = self.getImage() # # Embed psfImage into a larger image so we can smooth when measuring it # width, height = psfImage.getWidth(), psfImage.getHeight() largeImg = psfImage.Factory(afwGeom.ExtentI(2*width, 2*height)) largeImg.set(0) bbox = afwGeom.BoxI(afwGeom.PointI(width, height), afwGeom.ExtentI(width, height)) largeImg.assign(psfImage, bbox, afwImage.LOCAL) # # Now measure that image, looking for the highest peak. Start by building an Exposure # msk = afwImage.MaskU(largeImg.getDimensions()) msk.set(0) var = afwImage.ImageF(largeImg.getDimensions()) var.set(1) mpsfImage = afwImage.MaskedImageF(largeImg, msk, var) mpsfImage.setXY0(afwGeom.PointI(-width, -height)) del msk del var exposure = afwImage.makeExposure(mpsfImage) # # Next run an object detector # maxVal = afwMath.makeStatistics(psfImage, afwMath.MAX).getValue() threshold = maxVal - sigma*math.sqrt(maxVal) if threshold <= 0.0: threshold = maxVal threshold = afwDetection.Threshold(threshold) ds = afwDetection.FootprintSet(mpsfImage, threshold, "DETECTED") # # And measure it. This policy isn't the one we use to measure # Sources, it's only used to characterize this PSF histogram # schema = SourceTable.makeMinimalSchema() psfImageConfig = SingleFrameMeasurementConfig() psfImageConfig.doApplyApCorr = "no" psfImageConfig.slots.centroid = "base_SdssCentroid" psfImageConfig.slots.psfFlux = None #"base_PsfFlux" psfImageConfig.slots.apFlux = "base_CircularApertureFlux_3_0" psfImageConfig.slots.modelFlux = None psfImageConfig.slots.instFlux = None psfImageConfig.slots.calibFlux = None psfImageConfig.slots.shape = "base_SdssShape" # Formerly, this code had centroid.sdss, flux.psf, flux.naive, # flags.pixel, and shape.sdss psfImageConfig.algorithms.names = ["base_SdssCentroid", "base_CircularApertureFlux", "base_SdssShape"] psfImageConfig.algorithms["base_CircularApertureFlux"].radii = [3.0] psfImageConfig.validate() task = SingleFrameMeasurementTask(schema, config=psfImageConfig) sourceCat = SourceCatalog(schema) gaussianWidth = 1.5 # Gaussian sigma for detection convolution exposure.setPsf(algorithmsLib.DoubleGaussianPsf(11, 11, gaussianWidth)) ds.makeSources(sourceCat) # # Show us the Histogram # if display: frame = 1 dispImage = mpsfImage.Factory(mpsfImage, afwGeom.BoxI(afwGeom.PointI(width, height), afwGeom.ExtentI(width, height)), afwImage.LOCAL) ds9.mtv(dispImage,title="PSF Selection Image", frame=frame) clumps = list() # List of clumps, to return e = None # thrown exception IzzMin = 1.0 # Minimum value for second moments IzzMax = (self._xSize/8.0)**2 # Max value ... clump r < clumpImgSize/8 # diameter should be < 1/4 clumpImgSize apFluxes = [] task.run(exposure, sourceCat) # notes that this is backwards for the new framework for i, source in enumerate(sourceCat): if source.getCentroidFlag(): continue x, y = source.getX(), source.getY() apFluxes.append(source.getApFlux()) val = mpsfImage.getImage().get(int(x) + width, int(y) + height) psfClumpIxx = source.getIxx() psfClumpIxy = source.getIxy() psfClumpIyy = source.getIyy() if display: if i == 0: ds9.pan(x, y, frame=frame) ds9.dot("+", x, y, ctype=ds9.YELLOW, frame=frame) ds9.dot("@:%g,%g,%g" % (psfClumpIxx, psfClumpIxy, psfClumpIyy), x, y, ctype=ds9.YELLOW, frame=frame) if psfClumpIxx < IzzMin or psfClumpIyy < IzzMin: psfClumpIxx = max(psfClumpIxx, IzzMin) psfClumpIyy = max(psfClumpIyy, IzzMin) if display: ds9.dot("@:%g,%g,%g" % (psfClumpIxx, psfClumpIxy, psfClumpIyy), x, y, ctype=ds9.RED, frame=frame) det = psfClumpIxx*psfClumpIyy - psfClumpIxy*psfClumpIxy try: a, b, c = psfClumpIyy/det, -psfClumpIxy/det, psfClumpIxx/det except ZeroDivisionError: a, b, c = 1e4, 0, 1e4 clumps.append(Clump(peak=val, x=x, y=y, a=a, b=b, c=c, ixx=psfClumpIxx, ixy=psfClumpIxy, iyy=psfClumpIyy)) if len(clumps) == 0: msg = "Failed to determine center of PSF clump" if e: msg += ": %s" % e raise RuntimeError(msg) # if it's all we got return it if len(clumps) == 1: return clumps # which clump is the best? # if we've undistorted the moments, stars should only have 1 clump # use the apFlux from the clump measurement, and take the highest # ... this clump has more psf star candidate neighbours than the others. # get rid of any that are huge, and thus poorly defined goodClumps = [] for clump in clumps: if clump.ixx < IzzMax and clump.iyy < IzzMax: goodClumps.append(clump) # if culling > IzzMax cost us all clumps, we'll have to take what we have if len(goodClumps) == 0: goodClumps = clumps # use the 'brightest' clump iBestClump = numpy.argsort(apFluxes)[0] clumps = [clumps[iBestClump]] return clumps