23 Insert fakes into deepCoadds 26 from astropy.table
import Table
34 from lsst.pipe.base import CmdLineTask, PipelineTask, PipelineTaskConfig
37 from lsst.geom import SpherePoint, radians, Box2D
40 __all__ = [
"InsertFakesConfig",
"InsertFakesTask"]
44 """Config for inserting fake sources 48 The default column names are those from the University of Washington sims database. 51 raColName = pexConfig.Field(
52 doc=
"RA column name used in the fake source catalog.",
57 decColName = pexConfig.Field(
58 doc=
"Dec. column name used in the fake source catalog.",
63 doCleanCat = pexConfig.Field(
64 doc=
"If true removes bad sources from the catalog.",
69 diskHLR = pexConfig.Field(
70 doc=
"Column name for the disk half light radius used in the fake source catalog.",
72 default=
"DiskHalfLightRadius",
75 bulgeHLR = pexConfig.Field(
76 doc=
"Column name for the bulge half light radius used in the fake source catalog.",
78 default=
"BulgeHalfLightRadius",
81 magVar = pexConfig.Field(
82 doc=
"The column name for the magnitude calculated taking variability into account. In the format " 83 "``filter name``magVar, e.g. imagVar for the magnitude in the i band.",
88 nDisk = pexConfig.Field(
89 doc=
"The column name for the sersic index of the disk component used in the fake source catalog.",
94 nBulge = pexConfig.Field(
95 doc=
"The column name for the sersic index of the bulge component used in the fake source catalog.",
100 aDisk = pexConfig.Field(
101 doc=
"The column name for the semi major axis length of the disk component used in the fake source" 107 aBulge = pexConfig.Field(
108 doc=
"The column name for the semi major axis length of the bulge component.",
113 bDisk = pexConfig.Field(
114 doc=
"The column name for the semi minor axis length of the disk component.",
119 bBulge = pexConfig.Field(
120 doc=
"The column name for the semi minor axis length of the bulge component used in the fake source " 126 paDisk = pexConfig.Field(
127 doc=
"The column name for the PA of the disk component used in the fake source catalog.",
132 paBulge = pexConfig.Field(
133 doc=
"The column name for the PA of the bulge component used in the fake source catalog.",
138 fakeType = pexConfig.Field(
139 doc=
"What type of fake catalog to use, snapshot (includes variability in the magnitudes calculated " 140 "from the MJD of the image), static (no variability) or filename for a user defined fits" 146 calibFluxRadius = pexConfig.Field(
147 doc=
"Radius for the calib flux (in pixels).",
152 image = pipeBase.InputDatasetField(
153 doc=
"Image into which fakes are to be added.",
154 nameTemplate=
"{CoaddName}Coadd",
156 storageClass=
"ExposureF",
157 dimensions=(
"Tract",
"Patch",
"AbstractFilter",
"SkyMap")
160 fakeCat = pipeBase.InputDatasetField(
161 doc=
"Catalog of fake sources to draw inputs from.",
162 nameTemplate=
"{CoaddName}Coadd_fakeSourceCat",
164 storageClass=
"Parquet",
165 dimensions=(
"Tract",
"SkyMap")
168 imageWithFakes = pipeBase.OutputDatasetField(
169 doc=
"Image with fake sources added.",
170 nameTemplate=
"fakes_{CoaddName}Coadd",
172 storageClass=
"ExposureF",
173 dimensions=(
"Tract",
"Patch",
"AbstractFilter",
"SkyMap")
176 coaddName = pexConfig.Field(
177 doc=
"The name of the type of coadd used",
184 self.
quantum.dimensions = (
"Tract",
"Patch",
"AbstractFilter",
"SkyMap")
189 """Insert fake objects into images. 191 Add fake stars and galaxies to the given image, read in through the dataRef. Galaxy parameters are read in 192 from the specified file and then modelled using galsim. 194 `InsertFakesTask` has five functions that make images of the fake sources and then add them to the 198 Use the WCS information to add the pixel coordinates of each source. 199 `mkFakeGalsimGalaxies` 200 Use Galsim to make fake double sersic galaxies for each set of galaxy parameters in the input file. 202 Use the PSF information from the image to make a fake star using the magnitude information from the 205 Remove rows of the input fake catalog which have half light radius, of either the bulge or the disk, 208 Add the fake sources to the image. 212 _DefaultName =
"insertFakes" 213 ConfigClass = InsertFakesConfig
216 """Read in/write out the required data products and add fake sources to the deepCoadd. 220 dataRef : `lsst.daf.persistence.butlerSubset.ButlerDataRef` 221 Data reference defining the image to have fakes added to it 222 Used to access the following data products: 228 if self.
config.fakeType ==
"static":
229 fakeCat = dataRef.get(
"deepCoadd_fakeSourceCat").toDataFrame()
234 fakeCat = Table.read(self.
config.fakeType).to_pandas()
236 coadd = dataRef.get(
"deepCoadd")
238 photoCalib = coadd.getPhotoCalib()
240 imageWithFakes = self.
run(fakeCat, coadd, wcs, photoCalib)
242 dataRef.put(imageWithFakes.imageWithFakes,
"fakes_deepCoadd")
245 inputData[
"wcs"] = inputData[
"image"].getWcs()
246 inputData[
"photoCalib"] = inputData[
"image"].getPhotoCalib()
248 return self.
run(**inputData)
251 def _makeArgumentParser(cls):
253 parser.add_id_argument(name=
"--id", datasetType=
"deepCoadd",
254 help=
"data IDs for the deepCoadd, e.g. --id tract=12345 patch=1,2 filter=r",
255 ContainerClass=ExistingCoaddDataIdContainer)
258 def run(self, fakeCat, image, wcs, photoCalib):
259 """Add fake sources to an image. 263 fakeCat : `pandas.core.frame.DataFrame` 264 The catalog of fake sources to be input 265 image : `lsst.afw.image.exposure.exposure.ExposureF` 266 The image into which the fake sources should be added 267 wcs : `lsst.afw.geom.skyWcs.skyWcs.SkyWcs` 268 WCS to use to add fake sources 269 photoCalib : `lsst.afw.image.photoCalib.PhotoCalib` 270 Photometric calibration to be used to calibrate the fake sources 274 resultStruct : `lsst.pipe.base.struct.Struct` 275 contains : image : `lsst.afw.image.exposure.exposure.ExposureF` 279 Adds pixel coordinates for each source to the fakeCat and removes objects with bulge or disk half 280 light radius = 0 (if ``config.doCleanCat = True``). 282 Adds the ``Fake`` mask plane to the image which is then set by `addFakeSources` to mark where fake 283 sources have been added. Uses the information in the ``fakeCat`` to make fake galaxies (using galsim) 284 and fake stars, using the PSF models from the PSF information for the image. These are then added to 285 the image and the image with fakes included returned. 287 The galsim galaxies are made using a double sersic profile, one for the bulge and one for the disk, 288 this is then convolved with the PSF at that point. 291 image.mask.addMaskPlane(
"FAKE")
292 self.
bitmask = image.mask.getPlaneBitMask(
"FAKE")
296 if self.
config.doCleanCat:
300 band = image.getFilter().
getName()
301 pixelScale = wcs.getPixelScale().asArcseconds()
304 galaxies = (fakeCat[
"sourceType"] ==
"galaxy")
305 galImages = self.
mkFakeGalsimGalaxies(fakeCat[galaxies], band, photoCalib, pixelScale, psf, image)
308 stars = (fakeCat[
"sourceType"] ==
"star")
309 starImages = self.
mkFakeStars(fakeCat[stars], band, photoCalib, psf, image)
311 resultStruct = pipeBase.Struct(imageWithFakes=image)
317 """Add pixel coordinates to the catalog of fakes. 321 fakeCat : `pandas.core.frame.DataFrame` 322 The catalog of fake sources to be input 323 wcs : `lsst.afw.geom.skyWcs.skyWcs.SkyWcs` 324 WCS to use to add fake sources 328 fakeCat : `pandas.core.frame.DataFrame` 332 The default option is to use the WCS information from the image. If the ``useUpdatedCalibs`` config 333 option is set then it will use the updated WCS from jointCal. 336 ras = fakeCat[self.
config.raColName].values
337 decs = fakeCat[self.
config.decColName].values
338 skyCoords = [
SpherePoint(ra, dec, radians)
for (ra, dec)
in zip(ras, decs)]
339 pixCoords = wcs.skyToPixel(skyCoords)
340 xs = [coord.getX()
for coord
in pixCoords]
341 ys = [coord.getY()
for coord
in pixCoords]
348 """Trim the fake cat to about the size of the input image. 352 fakeCat : `pandas.core.frame.DataFrame` 353 The catalog of fake sources to be input 354 image : `lsst.afw.image.exposure.exposure.ExposureF` 355 The image into which the fake sources should be added 356 wcs : `lsst.afw.geom.skyWcs.skyWcs.SkyWcs` 357 WCS to use to add fake sources 361 fakeCat : `pandas.core.frame.DataFrame` 362 The original fakeCat trimmed to the area of the image 365 bbox =
Box2D(image.getBBox())
366 corners = bbox.getCorners()
368 skyCorners = wcs.pixelToSky(corners)
373 return region.contains(coord.getVector())
375 return fakeCat[fakeCat.apply(trim, axis=1)]
378 """Make images of fake galaxies using GalSim. 384 psf : `lsst.meas.extensions.psfex.psfexPsf.PsfexPsf` 385 The PSF information to use to make the PSF images 386 fakeCat : `pandas.core.frame.DataFrame` 387 The catalog of fake sources to be input 388 photoCalib : `lsst.afw.image.photoCalib.PhotoCalib` 389 Photometric calibration to be used to calibrate the fake sources 394 A list of tuples of `lsst.afw.image.exposure.exposure.ExposureF` and 395 `lsst.afw.geom.Point2D` of their locations. 400 Fake galaxies are made by combining two sersic profiles, one for the bulge and one for the disk. Each 401 component has an individual sersic index (n), a, b and position angle (PA). The combined profile is 402 then convolved with the PSF at the specified x, y position on the image. 404 The names of the columns in the ``fakeCat`` are configurable and are the column names from the 405 University of Washington simulations database as default. For more information see the doc strings 406 attached to the config options. 411 self.
log.
info(
"Making %d fake galaxy images" % len(fakeCat))
413 for (index, row)
in fakeCat.iterrows():
419 correctedFlux = psf.computeApertureFlux(self.
config.calibFluxRadius, xy)
420 psfKernel = psf.computeKernelImage(xy).getArray()
421 psfKernel /= correctedFlux
423 except InvalidParameterError:
424 self.
log.
info(
"Galaxy at %0.4f, %0.4f outside of image" % (row[
"x"], row[
"y"]))
428 flux = photoCalib.magnitudeToInstFlux(row[self.
config.magVar % band], xy)
432 bulge = galsim.Sersic(row[self.
config.nBulge], half_light_radius=row[self.
config.bulgeHLR])
433 axisRatioBulge = row[self.
config.bBulge]/row[self.
config.aBulge]
434 bulge = bulge.shear(q=axisRatioBulge, beta=((90 - row[self.
config.paBulge])*galsim.degrees))
436 disk = galsim.Sersic(row[self.
config.nDisk], half_light_radius=row[self.
config.diskHLR])
437 axisRatioDisk = row[self.
config.bDisk]/row[self.
config.aDisk]
438 disk = disk.shear(q=axisRatioDisk, beta=((90 - row[self.
config.paDisk])*galsim.degrees))
441 gal = gal.withFlux(flux)
443 psfIm = galsim.InterpolatedImage(galsim.Image(psfKernel), scale=pixelScale)
444 gal = galsim.Convolve([gal, psfIm])
446 galIm = gal.drawImage(scale=pixelScale, method=
"real_space").array
447 except (galsim.errors.GalSimFFTSizeError, MemoryError):
450 galImages.append((afwImage.ImageF(galIm), xy))
456 """Make fake stars based off the properties in the fakeCat. 461 psf : `lsst.meas.extensions.psfex.psfexPsf.PsfexPsf` 462 The PSF information to use to make the PSF images 463 fakeCat : `pandas.core.frame.DataFrame` 464 The catalog of fake sources to be input 465 image : `lsst.afw.image.exposure.exposure.ExposureF` 466 The image into which the fake sources should be added 467 photoCalib : `lsst.afw.image.photoCalib.PhotoCalib` 468 Photometric calibration to be used to calibrate the fake sources 473 A list of tuples of `lsst.afw.image.image.image.ImageF` of fake stars and 474 `lsst.afw.geom.Point2D` of their locations. 479 self.
log.
info(
"Making %d fake star images" % len(fakeCat))
481 for (index, row)
in fakeCat.iterrows():
487 correctedFlux = psf.computeApertureFlux(self.
config.calibFluxRadius, xy)
488 starIm = psf.computeImage(xy)
489 starIm /= correctedFlux
491 except InvalidParameterError:
492 self.
log.
info(
"Star at %0.4f, %0.4f outside of image" % (row[
"x"], row[
"y"]))
496 flux = photoCalib.magnitudeToInstFlux(row[band +
"magVar"], xy)
501 starImages.append((starIm.convertF(), xy))
506 """Remove rows from the fakes catalog which have HLR = 0 for either the buldge or disk component 510 fakeCat : `pandas.core.frame.DataFrame` 511 The catalog of fake sources to be input 515 fakeCat : `pandas.core.frame.DataFrame` 516 The input catalog of fake sources but with the bad objects removed 519 goodRows = ((fakeCat[self.
config.bulgeHLR] != 0.0) & (fakeCat[self.
config.diskHLR] != 0.0))
521 badRows = len(fakeCat) - len(goodRows)
522 self.
log.
info(
"Removing %d rows with HLR = 0 for either the bulge or disk" % badRows)
524 return fakeCat[goodRows]
527 """Add the fake sources to the given image 531 image : `lsst.afw.image.exposure.exposure.ExposureF` 532 The image into which the fake sources should be added 534 A list of tuples of `lsst.afw.image.image.image.ImageF` and `lsst.afw.geom.Point2D, 535 the images and the locations they are to be inserted at. 537 The type (star/galaxy) of fake sources input 541 image : `lsst.afw.image.exposure.exposure.ExposureF` 545 Uses the x, y information in the ``fakeCat`` to position an image of the fake interpolated onto the 546 pixel grid of the image. Sets the ``FAKE`` mask plane for the pixels added with the fake source. 549 imageBBox = image.getBBox()
550 imageMI = image.maskedImage
552 for (fakeImage, xy)
in fakeImages:
553 X0 = xy.getX() - fakeImage.getWidth()/2 + 0.5
554 Y0 = xy.getY() - fakeImage.getHeight()/2 + 0.5
555 self.
log.
debug(
"Adding fake source at %d, %d" % (xy.getX(), xy.getY()))
556 if sourceType ==
"galaxy":
558 interpFakeImBBox = interpFakeImage.getBBox()
560 interpFakeImage = fakeImage
561 interpFakeImBBox = fakeImage.getBBox()
563 interpFakeImBBox.clip(imageBBox)
564 imageMIView = imageMI.Factory(imageMI, interpFakeImBBox)
566 if interpFakeImBBox.getArea() > 0:
567 clippedFakeImage = interpFakeImage.Factory(interpFakeImage, interpFakeImBBox)
568 clippedFakeImageMI = afwImage.MaskedImageF(clippedFakeImage)
569 clippedFakeImageMI.mask.set(self.
bitmask)
570 imageMIView += clippedFakeImageMI
A floating-point coordinate rectangle geometry.
def mkFakeStars(self, fakeCat, band, photoCalib, psf, image)
def formatTemplateNames(self, templateParamsDict)
def cleanCat(self, fakeCat)
def trimFakeCat(self, fakeCat, image, wcs)
ConvexPolygon is a closed convex polygon on the unit sphere.
def run(self, fakeCat, image, wcs, photoCalib)
Point in an unspecified spherical coordinate system.
std::shared_ptr< ImageT > offsetImage(ImageT const &image, float dx, float dy, std::string const &algorithmName="lanczos5", unsigned int buffer=0)
Return an image offset by (dx, dy) using the specified algorithm.
def mkFakeGalsimGalaxies(self, fakeCat, band, photoCalib, pixelScale, psf, image)
def addFakeSources(self, image, fakeImages, sourceType)
def runDataRef(self, dataRef)
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects...
def addPixCoords(self, fakeCat, wcs)
def adaptArgsAndRun(self, inputData, inputDataIds, outputDataIds, butler)