23 Insert fakes into deepCoadds
26 from astropy.table
import Table
35 from lsst.pipe.base import CmdLineTask, PipelineTask, PipelineTaskConfig, PipelineTaskConnections
39 from lsst.geom import SpherePoint, radians, Box2D
41 __all__ = [
"InsertFakesConfig",
"InsertFakesTask"]
44 def _add_fake_sources(exposure, objects, calibFluxRadius=12.0, logger=None):
45 """Add fake sources to the given exposure
49 exposure : `lsst.afw.image.exposure.exposure.ExposureF`
50 The exposure into which the fake sources should be added
51 objects : `typing.Iterator` [`tuple` ['lsst.geom.SpherePoint`, `galsim.GSObject`]]
52 An iterator of tuples that contains (or generates) locations and object
53 surface brightness profiles to inject.
54 calibFluxRadius : `float`, optional
55 Aperture radius (in pixels) used to define the calibration for this
56 exposure+catalog. This is used to produce the correct instrumental fluxes
57 within the radius. The value should match that of the field defined in
58 slot_CalibFlux_instFlux.
59 logger : `lsst.log.log.log.Log` or `logging.Logger`, optional
62 exposure.mask.addMaskPlane(
"FAKE")
63 bitmask = exposure.mask.getPlaneBitMask(
"FAKE")
65 logger.info(f
"Adding mask plane with bitmask {bitmask}")
67 wcs = exposure.getWcs()
68 psf = exposure.getPsf()
70 bbox = exposure.getBBox()
71 fullBounds = galsim.BoundsI(bbox.minX, bbox.maxX, bbox.minY, bbox.maxY)
72 gsImg = galsim.Image(exposure.image.array, bounds=fullBounds)
74 for spt, gsObj
in objects:
75 pt = wcs.skyToPixel(spt)
76 posd = galsim.PositionD(pt.x, pt.y)
77 posi = galsim.PositionI(pt.x//1, pt.y//1)
79 logger.debug(f
"Adding fake source at {pt}")
81 mat = wcs.linearizePixelToSky(spt, geom.arcseconds).getMatrix()
82 gsWCS = galsim.JacobianWCS(mat[0, 0], mat[0, 1], mat[1, 0], mat[1, 1])
84 psfArr = psf.computeKernelImage(pt).array
85 apCorr = psf.computeApertureFlux(calibFluxRadius)
87 gsPSF = galsim.InterpolatedImage(galsim.Image(psfArr), wcs=gsWCS)
89 conv = galsim.Convolve(gsObj, gsPSF)
90 stampSize = conv.getGoodImageSize(gsWCS.minLinearScale())
91 subBounds = galsim.BoundsI(posi).withBorder(stampSize//2)
92 subBounds &= fullBounds
94 if subBounds.area() > 0:
95 subImg = gsImg[subBounds]
96 offset = posd - subBounds.true_center
112 exposure[subBox].mask.array |= bitmask
115 def _isWCSGalsimDefault(wcs, hdr):
116 """Decide if wcs = galsim.PixelScale(1.0) is explicitly present in header,
117 or if it's just the galsim default.
122 Potentially default WCS.
123 hdr : galsim.fits.FitsHeader
124 Header as read in by galsim.
129 True if default, False if explicitly set in header.
131 if wcs != galsim.PixelScale(1.0):
133 if hdr.get(
'GS_WCS')
is not None:
135 if hdr.get(
'CTYPE1',
'LINEAR') ==
'LINEAR':
136 return not any(k
in hdr
for k
in [
'CD1_1',
'CDELT1'])
137 for wcs_type
in galsim.fitswcs.fits_wcs_types:
140 wcs_type._readHeader(hdr)
145 return not any(k
in hdr
for k
in [
'CD1_1',
'CDELT1'])
149 defaultTemplates={
"coaddName":
"deep",
150 "fakesType":
"fakes_"},
151 dimensions=(
"tract",
"patch",
"band",
"skymap")):
154 doc=
"Image into which fakes are to be added.",
155 name=
"{coaddName}Coadd",
156 storageClass=
"ExposureF",
157 dimensions=(
"tract",
"patch",
"band",
"skymap")
161 doc=
"Catalog of fake sources to draw inputs from.",
162 name=
"{fakesType}fakeSourceCat",
163 storageClass=
"DataFrame",
164 dimensions=(
"tract",
"skymap")
167 imageWithFakes = cT.Output(
168 doc=
"Image with fake sources added.",
169 name=
"{fakesType}{coaddName}Coadd",
170 storageClass=
"ExposureF",
171 dimensions=(
"tract",
"patch",
"band",
"skymap")
175 class InsertFakesConfig(PipelineTaskConfig,
176 pipelineConnections=InsertFakesConnections):
177 """Config for inserting fake sources
181 The default column names are those from the University of Washington sims database.
184 raColName = pexConfig.Field(
185 doc=
"RA column name used in the fake source catalog.",
190 decColName = pexConfig.Field(
191 doc=
"Dec. column name used in the fake source catalog.",
196 doCleanCat = pexConfig.Field(
197 doc=
"If true removes bad sources from the catalog.",
202 diskHLR = pexConfig.Field(
203 doc=
"Column name for the disk half light radius used in the fake source catalog.",
205 default=
"DiskHalfLightRadius",
208 bulgeHLR = pexConfig.Field(
209 doc=
"Column name for the bulge half light radius used in the fake source catalog.",
211 default=
"BulgeHalfLightRadius",
214 magVar = pexConfig.Field(
215 doc=
"The column name for the magnitude calculated taking variability into account. In the format "
216 "``filter name``magVar, e.g. imagVar for the magnitude in the i band.",
221 nDisk = pexConfig.Field(
222 doc=
"The column name for the sersic index of the disk component used in the fake source catalog.",
227 nBulge = pexConfig.Field(
228 doc=
"The column name for the sersic index of the bulge component used in the fake source catalog.",
233 aDisk = pexConfig.Field(
234 doc=
"The column name for the semi major axis length of the disk component used in the fake source"
240 aBulge = pexConfig.Field(
241 doc=
"The column name for the semi major axis length of the bulge component.",
246 bDisk = pexConfig.Field(
247 doc=
"The column name for the semi minor axis length of the disk component.",
252 bBulge = pexConfig.Field(
253 doc=
"The column name for the semi minor axis length of the bulge component used in the fake source "
259 paDisk = pexConfig.Field(
260 doc=
"The column name for the PA of the disk component used in the fake source catalog.",
265 paBulge = pexConfig.Field(
266 doc=
"The column name for the PA of the bulge component used in the fake source catalog.",
271 sourceType = pexConfig.Field(
272 doc=
"The column name for the source type used in the fake source catalog.",
274 default=
"sourceType",
277 fakeType = pexConfig.Field(
278 doc=
"What type of fake catalog to use, snapshot (includes variability in the magnitudes calculated "
279 "from the MJD of the image), static (no variability) or filename for a user defined fits"
285 calibFluxRadius = pexConfig.Field(
286 doc=
"Aperture radius (in pixels) that was used to define the calibration for this image+catalog. "
287 "This will be used to produce the correct instrumental fluxes within the radius. "
288 "This value should match that of the field defined in slot_CalibFlux_instFlux.",
293 coaddName = pexConfig.Field(
294 doc=
"The name of the type of coadd used",
299 doSubSelectSources = pexConfig.Field(
300 doc=
"Set to True if you wish to sub select sources to be input based on the value in the column"
301 "set in the sourceSelectionColName config option.",
306 sourceSelectionColName = pexConfig.Field(
307 doc=
"The name of the column in the input fakes catalogue to be used to determine which sources to"
308 "add, default is none and when this is used all sources are added.",
310 default=
"templateSource"
313 insertImages = pexConfig.Field(
314 doc=
"Insert images directly? True or False.",
319 doProcessAllDataIds = pexConfig.Field(
320 doc=
"If True, all input data IDs will be processed, even those containing no fake sources.",
325 trimBuffer = pexConfig.Field(
326 doc=
"Size of the pixel buffer surrounding the image. Only those fake sources with a centroid"
327 "falling within the image+buffer region will be considered for fake source injection.",
333 class InsertFakesTask(PipelineTask, CmdLineTask):
334 """Insert fake objects into images.
336 Add fake stars and galaxies to the given image, read in through the dataRef. Galaxy parameters are read in
337 from the specified file and then modelled using galsim.
339 `InsertFakesTask` has five functions that make images of the fake sources and then add them to the
343 Use the WCS information to add the pixel coordinates of each source.
344 `mkFakeGalsimGalaxies`
345 Use Galsim to make fake double sersic galaxies for each set of galaxy parameters in the input file.
347 Use the PSF information from the image to make a fake star using the magnitude information from the
350 Remove rows of the input fake catalog which have half light radius, of either the bulge or the disk,
351 that are 0. Also removes rows that have Sersic index outside of galsim's allowed paramters. If
352 the config option sourceSelectionColName is set then this function limits the catalog of input fakes
353 to only those which are True in this column.
355 Add the fake sources to the image.
359 _DefaultName =
"insertFakes"
360 ConfigClass = InsertFakesConfig
362 def runDataRef(self, dataRef):
363 """Read in/write out the required data products and add fake sources to the deepCoadd.
367 dataRef : `lsst.daf.persistence.butlerSubset.ButlerDataRef`
368 Data reference defining the image to have fakes added to it
369 Used to access the following data products:
373 infoStr =
"Adding fakes to: tract: %d, patch: %s, filter: %s" % (dataRef.dataId[
"tract"],
374 dataRef.dataId[
"patch"],
375 dataRef.dataId[
"filter"])
376 self.log.info(infoStr)
380 if self.config.fakeType ==
"static":
381 fakeCat = dataRef.get(
"deepCoadd_fakeSourceCat").toDataFrame()
384 self.fakeSourceCatType =
"deepCoadd_fakeSourceCat"
386 fakeCat = Table.read(self.config.fakeType).to_pandas()
388 coadd = dataRef.get(
"deepCoadd")
390 photoCalib = coadd.getPhotoCalib()
392 imageWithFakes = self.run(fakeCat, coadd, wcs, photoCalib)
394 dataRef.put(imageWithFakes.imageWithFakes,
"fakes_deepCoadd")
396 def runQuantum(self, butlerQC, inputRefs, outputRefs):
397 inputs = butlerQC.get(inputRefs)
398 inputs[
"wcs"] = inputs[
"image"].getWcs()
399 inputs[
"photoCalib"] = inputs[
"image"].getPhotoCalib()
401 outputs = self.run(**inputs)
402 butlerQC.put(outputs, outputRefs)
405 def _makeArgumentParser(cls):
406 parser = pipeBase.ArgumentParser(name=cls._DefaultName)
407 parser.add_id_argument(name=
"--id", datasetType=
"deepCoadd",
408 help=
"data IDs for the deepCoadd, e.g. --id tract=12345 patch=1,2 filter=r",
409 ContainerClass=ExistingCoaddDataIdContainer)
412 def run(self, fakeCat, image, wcs, photoCalib):
413 """Add fake sources to an image.
417 fakeCat : `pandas.core.frame.DataFrame`
418 The catalog of fake sources to be input
419 image : `lsst.afw.image.exposure.exposure.ExposureF`
420 The image into which the fake sources should be added
421 wcs : `lsst.afw.geom.SkyWcs`
422 WCS to use to add fake sources
423 photoCalib : `lsst.afw.image.photoCalib.PhotoCalib`
424 Photometric calibration to be used to calibrate the fake sources
428 resultStruct : `lsst.pipe.base.struct.Struct`
429 contains : image : `lsst.afw.image.exposure.exposure.ExposureF`
433 Adds pixel coordinates for each source to the fakeCat and removes objects with bulge or disk half
434 light radius = 0 (if ``config.doCleanCat = True``).
436 Adds the ``Fake`` mask plane to the image which is then set by `addFakeSources` to mark where fake
437 sources have been added. Uses the information in the ``fakeCat`` to make fake galaxies (using galsim)
438 and fake stars, using the PSF models from the PSF information for the image. These are then added to
439 the image and the image with fakes included returned.
441 The galsim galaxies are made using a double sersic profile, one for the bulge and one for the disk,
442 this is then convolved with the PSF at that point.
446 origWcs = image.getWcs()
447 origPhotoCalib = image.getPhotoCalib()
449 image.setPhotoCalib(photoCalib)
451 fakeCat = self.addPixCoords(fakeCat, image)
452 fakeCat = self.trimFakeCat(fakeCat, image)
455 if isinstance(fakeCat[self.config.sourceType].iloc[0], str):
456 galCheckVal =
"galaxy"
457 starCheckVal =
"star"
458 elif isinstance(fakeCat[self.config.sourceType].iloc[0], bytes):
459 galCheckVal = b
"galaxy"
460 starCheckVal = b
"star"
461 elif isinstance(fakeCat[self.config.sourceType].iloc[0], (int, float)):
465 raise TypeError(
"sourceType column does not have required type, should be str, bytes or int")
467 if not self.config.insertImages:
468 if self.config.doCleanCat:
469 fakeCat = self.cleanCat(fakeCat, starCheckVal)
471 generator = self._generateGSObjectsFromCatalog(image, fakeCat, galCheckVal, starCheckVal)
473 generator = self._generateGSObjectsFromImages(image, fakeCat)
474 _add_fake_sources(image, generator, calibFluxRadius=self.config.calibFluxRadius, logger=self.log)
475 elif len(fakeCat) == 0
and self.config.doProcessAllDataIds:
476 self.log.warn(
"No fakes found for this dataRef; processing anyway.")
478 raise RuntimeError(
"No fakes found for this dataRef.")
481 image.setWcs(origWcs)
482 image.setPhotoCalib(origPhotoCalib)
484 resultStruct = pipeBase.Struct(imageWithFakes=image)
488 def _generateGSObjectsFromCatalog(self, exposure, fakeCat, galCheckVal, starCheckVal):
489 """Process catalog to generate `galsim.GSObject` s.
493 exposure : `lsst.afw.image.exposure.exposure.ExposureF`
494 The exposure into which the fake sources should be added
495 fakeCat : `pandas.core.frame.DataFrame`
496 The catalog of fake sources to be input
497 galCheckVal : `str`, `bytes` or `int`
498 The value that is set in the sourceType column to specifiy an object is a galaxy.
499 starCheckVal : `str`, `bytes` or `int`
500 The value that is set in the sourceType column to specifiy an object is a star.
504 gsObjects : `generator`
505 A generator of tuples of `lsst.geom.SpherePoint` and `galsim.GSObject`.
507 band = exposure.getFilterLabel().bandLabel
508 wcs = exposure.getWcs()
509 photoCalib = exposure.getPhotoCalib()
511 self.log.info(f
"Making {len(fakeCat)} objects for insertion")
513 for (index, row)
in fakeCat.iterrows():
514 ra = row[self.config.raColName]
515 dec = row[self.config.decColName]
517 xy = wcs.skyToPixel(skyCoord)
520 flux = photoCalib.magnitudeToInstFlux(row[self.config.magVar % band], xy)
524 sourceType = row[self.config.sourceType]
525 if sourceType == galCheckVal:
526 bulge = galsim.Sersic(n=row[self.config.nBulge], half_light_radius=row[self.config.bulgeHLR])
527 axisRatioBulge = row[self.config.bBulge]/row[self.config.aBulge]
528 bulge = bulge.shear(q=axisRatioBulge, beta=((90 - row[self.config.paBulge])*galsim.degrees))
530 disk = galsim.Sersic(n=row[self.config.nDisk], half_light_radius=row[self.config.diskHLR])
531 axisRatioDisk = row[self.config.bDisk]/row[self.config.aDisk]
532 disk = disk.shear(q=axisRatioDisk, beta=((90 - row[self.config.paDisk])*galsim.degrees))
535 gal = gal.withFlux(flux)
538 elif sourceType == starCheckVal:
539 star = galsim.DeltaFunction()
540 star = star.withFlux(flux)
543 raise TypeError(f
"Unknown sourceType {sourceType}")
545 def _generateGSObjectsFromImages(self, exposure, fakeCat):
546 """Process catalog to generate `galsim.GSObject` s.
550 exposure : `lsst.afw.image.exposure.exposure.ExposureF`
551 The exposure into which the fake sources should be added
552 fakeCat : `pandas.core.frame.DataFrame`
553 The catalog of fake sources to be input
557 gsObjects : `generator`
558 A generator of tuples of `lsst.geom.SpherePoint` and `galsim.GSObject`.
560 band = exposure.getFilterLabel().bandLabel
561 wcs = exposure.getWcs()
562 photoCalib = exposure.getPhotoCalib()
564 self.log.info(f
"Processing {len(fakeCat)} fake images")
566 for (index, row)
in fakeCat.iterrows():
567 ra = row[self.config.raColName]
568 dec = row[self.config.decColName]
570 xy = wcs.skyToPixel(skyCoord)
573 flux = photoCalib.magnitudeToInstFlux(row[self.config.magVar % band], xy)
577 imFile = row[band+
"imFilename"]
579 imFile = imFile.decode(
"utf-8")
580 except AttributeError:
582 imFile = imFile.strip()
583 im = galsim.fits.read(imFile, read_header=
True)
591 if _isWCSGalsimDefault(im.wcs, im.header):
592 im.wcs = galsim.PixelScale(
593 wcs.getPixelScale().asArcseconds()
596 obj = galsim.InterpolatedImage(im)
597 obj = obj.withFlux(flux)
601 """Process images from files into the format needed for insertion.
605 fakeCat : `pandas.core.frame.DataFrame`
606 The catalog of fake sources to be input
607 wcs : `lsst.afw.geom.skyWcs.skyWcs.SkyWc`
608 WCS to use to add fake sources
609 psf : `lsst.meas.algorithms.coaddPsf.coaddPsf.CoaddPsf` or
610 `lsst.meas.extensions.psfex.psfexPsf.PsfexPsf`
611 The PSF information to use to make the PSF images
612 photoCalib : `lsst.afw.image.photoCalib.PhotoCalib`
613 Photometric calibration to be used to calibrate the fake sources
615 The filter band that the observation was taken in.
617 The pixel scale of the image the sources are to be added to.
622 A list of tuples of `lsst.afw.image.exposure.exposure.ExposureF` and
623 `lsst.geom.Point2D` of their locations.
624 For sources labelled as galaxy.
626 A list of tuples of `lsst.afw.image.exposure.exposure.ExposureF` and
627 `lsst.geom.Point2D` of their locations.
628 For sources labelled as star.
632 The input fakes catalog needs to contain the absolute path to the image in the
633 band that is being used to add images to. It also needs to have the R.A. and
634 declination of the fake source in radians and the sourceType of the object.
639 self.log.info(
"Processing %d fake images" % len(fakeCat))
641 for (imFile, sourceType, mag, x, y)
in zip(fakeCat[band +
"imFilename"].array,
642 fakeCat[
"sourceType"].array,
643 fakeCat[self.config.magVar % band].array,
644 fakeCat[
"x"].array, fakeCat[
"y"].array):
646 im = afwImage.ImageF.readFits(imFile)
653 correctedFlux = psf.computeApertureFlux(self.config.calibFluxRadius, xy)
654 psfKernel = psf.computeKernelImage(xy).getArray()
655 psfKernel /= correctedFlux
657 except InvalidParameterError:
658 self.log.info(
"%s at %0.4f, %0.4f outside of image" % (sourceType, x, y))
661 psfIm = galsim.InterpolatedImage(galsim.Image(psfKernel), scale=pixelScale)
662 galsimIm = galsim.InterpolatedImage(galsim.Image(im.array), scale=pixelScale)
663 convIm = galsim.Convolve([galsimIm, psfIm])
666 outIm = convIm.drawImage(scale=pixelScale, method=
"real_space").array
667 except (galsim.errors.GalSimFFTSizeError, MemoryError):
670 imSum = np.sum(outIm)
674 flux = photoCalib.magnitudeToInstFlux(mag, xy)
678 imWithFlux = flux*divIm
680 if sourceType == b
"galaxy":
681 galImages.append((afwImage.ImageF(imWithFlux), xy))
682 if sourceType == b
"star":
683 starImages.append((afwImage.ImageF(imWithFlux), xy))
685 return galImages, starImages
689 """Add pixel coordinates to the catalog of fakes.
693 fakeCat : `pandas.core.frame.DataFrame`
694 The catalog of fake sources to be input
695 image : `lsst.afw.image.exposure.exposure.ExposureF`
696 The image into which the fake sources should be added
700 fakeCat : `pandas.core.frame.DataFrame`
703 ras = fakeCat[self.config.raColName].values
704 decs = fakeCat[self.config.decColName].values
705 xs, ys = wcs.skyToPixelArray(ras, decs)
712 """Trim the fake cat to about the size of the input image.
714 `fakeCat` must be processed with addPixCoords before using this method.
718 fakeCat : `pandas.core.frame.DataFrame`
719 The catalog of fake sources to be input
720 image : `lsst.afw.image.exposure.exposure.ExposureF`
721 The image into which the fake sources should be added
725 fakeCat : `pandas.core.frame.DataFrame`
726 The original fakeCat trimmed to the area of the image
729 bbox =
Box2D(image.getBBox()).dilatedBy(self.config.trimBuffer)
730 xs = fakeCat[
"x"].values
731 ys = fakeCat[
"y"].values
733 isContained = xs >= bbox.minX
734 isContained &= xs <= bbox.maxX
735 isContained &= ys >= bbox.minY
736 isContained &= ys <= bbox.maxY
738 return fakeCat[isContained]
741 """Make images of fake galaxies using GalSim.
747 psf : `lsst.meas.extensions.psfex.psfexPsf.PsfexPsf`
748 The PSF information to use to make the PSF images
749 fakeCat : `pandas.core.frame.DataFrame`
750 The catalog of fake sources to be input
751 photoCalib : `lsst.afw.image.photoCalib.PhotoCalib`
752 Photometric calibration to be used to calibrate the fake sources
756 galImages : `generator`
757 A generator of tuples of `lsst.afw.image.exposure.exposure.ExposureF` and
758 `lsst.geom.Point2D` of their locations.
763 Fake galaxies are made by combining two sersic profiles, one for the bulge and one for the disk. Each
764 component has an individual sersic index (n), a, b and position angle (PA). The combined profile is
765 then convolved with the PSF at the specified x, y position on the image.
767 The names of the columns in the ``fakeCat`` are configurable and are the column names from the
768 University of Washington simulations database as default. For more information see the doc strings
769 attached to the config options.
771 See mkFakeStars doc string for an explanation of calibration to instrumental flux.
774 self.log.info(
"Making %d fake galaxy images" % len(fakeCat))
776 for (index, row)
in fakeCat.iterrows():
782 correctedFlux = psf.computeApertureFlux(self.config.calibFluxRadius, xy)
783 psfKernel = psf.computeKernelImage(xy).getArray()
784 psfKernel /= correctedFlux
786 except InvalidParameterError:
787 self.log.info(
"Galaxy at %0.4f, %0.4f outside of image" % (row[
"x"], row[
"y"]))
791 flux = photoCalib.magnitudeToInstFlux(row[self.config.magVar % band], xy)
795 bulge = galsim.Sersic(row[self.config.nBulge], half_light_radius=row[self.config.bulgeHLR])
796 axisRatioBulge = row[self.config.bBulge]/row[self.config.aBulge]
797 bulge = bulge.shear(q=axisRatioBulge, beta=((90 - row[self.config.paBulge])*galsim.degrees))
799 disk = galsim.Sersic(row[self.config.nDisk], half_light_radius=row[self.config.diskHLR])
800 axisRatioDisk = row[self.config.bDisk]/row[self.config.aDisk]
801 disk = disk.shear(q=axisRatioDisk, beta=((90 - row[self.config.paDisk])*galsim.degrees))
804 gal = gal.withFlux(flux)
806 psfIm = galsim.InterpolatedImage(galsim.Image(psfKernel), scale=pixelScale)
807 gal = galsim.Convolve([gal, psfIm])
809 galIm = gal.drawImage(scale=pixelScale, method=
"real_space").array
810 except (galsim.errors.GalSimFFTSizeError, MemoryError):
813 yield (afwImage.ImageF(galIm), xy)
817 """Make fake stars based off the properties in the fakeCat.
822 psf : `lsst.meas.extensions.psfex.psfexPsf.PsfexPsf`
823 The PSF information to use to make the PSF images
824 fakeCat : `pandas.core.frame.DataFrame`
825 The catalog of fake sources to be input
826 image : `lsst.afw.image.exposure.exposure.ExposureF`
827 The image into which the fake sources should be added
828 photoCalib : `lsst.afw.image.photoCalib.PhotoCalib`
829 Photometric calibration to be used to calibrate the fake sources
833 starImages : `generator`
834 A generator of tuples of `lsst.afw.image.ImageF` of fake stars and
835 `lsst.geom.Point2D` of their locations.
839 To take a given magnitude and translate to the number of counts in the image
840 we use photoCalib.magnitudeToInstFlux, which returns the instrumental flux for the
841 given calibration radius used in the photometric calibration step.
842 Thus `calibFluxRadius` should be set to this same radius so that we can normalize
843 the PSF model to the correct instrumental flux within calibFluxRadius.
846 self.log.info(
"Making %d fake star images" % len(fakeCat))
848 for (index, row)
in fakeCat.iterrows():
854 correctedFlux = psf.computeApertureFlux(self.config.calibFluxRadius, xy)
855 starIm = psf.computeImage(xy)
856 starIm /= correctedFlux
858 except InvalidParameterError:
859 self.log.info(
"Star at %0.4f, %0.4f outside of image" % (row[
"x"], row[
"y"]))
863 flux = photoCalib.magnitudeToInstFlux(row[self.config.magVar % band], xy)
868 yield ((starIm.convertF(), xy))
871 """Remove rows from the fakes catalog which have HLR = 0 for either the buldge or disk component,
872 also remove galaxies that have Sersic index outside the galsim min and max
873 allowed (0.3 <= n <= 6.2).
877 fakeCat : `pandas.core.frame.DataFrame`
878 The catalog of fake sources to be input
879 starCheckVal : `str`, `bytes` or `int`
880 The value that is set in the sourceType column to specifiy an object is a star.
884 fakeCat : `pandas.core.frame.DataFrame`
885 The input catalog of fake sources but with the bad objects removed
889 If the config option sourceSelectionColName is set then only objects with this column set to True
893 rowsToKeep = (((fakeCat[self.config.bulgeHLR] != 0.0) & (fakeCat[self.config.diskHLR] != 0.0))
894 | (fakeCat[self.config.sourceType] == starCheckVal))
895 numRowsNotUsed = len(fakeCat) - len(np.where(rowsToKeep)[0])
896 self.log.info(
"Removing %d rows with HLR = 0 for either the bulge or disk" % numRowsNotUsed)
897 fakeCat = fakeCat[rowsToKeep]
899 minN = galsim.Sersic._minimum_n
900 maxN = galsim.Sersic._maximum_n
901 rowsWithGoodSersic = (((fakeCat[self.config.nBulge] >= minN) & (fakeCat[self.config.nBulge] <= maxN)
902 & (fakeCat[self.config.nDisk] >= minN) & (fakeCat[self.config.nDisk] <= maxN))
903 | (fakeCat[self.config.sourceType] == starCheckVal))
904 numRowsNotUsed = len(fakeCat) - len(np.where(rowsWithGoodSersic)[0])
905 self.log.info(
"Removing %d rows of galaxies with nBulge or nDisk outside of %0.2f <= n <= %0.2f" %
906 (numRowsNotUsed, minN, maxN))
907 fakeCat = fakeCat[rowsWithGoodSersic]
909 if self.config.doSubSelectSources:
911 rowsSelected = (fakeCat[self.config.sourceSelectionColName])
913 raise KeyError(
"Given column, %s, for source selection not found." %
914 self.config.sourceSelectionColName)
915 numRowsNotUsed = len(fakeCat) - len(rowsSelected)
916 self.log.info(
"Removing %d rows which were not designated as template sources" % numRowsNotUsed)
917 fakeCat = fakeCat[rowsSelected]
922 """Add the fake sources to the given image
926 image : `lsst.afw.image.exposure.exposure.ExposureF`
927 The image into which the fake sources should be added
928 fakeImages : `typing.Iterator` [`tuple` ['lsst.afw.image.ImageF`, `lsst.geom.Point2d`]]
929 An iterator of tuples that contains (or generates) images of fake sources,
930 and the locations they are to be inserted at.
932 The type (star/galaxy) of fake sources input
936 image : `lsst.afw.image.exposure.exposure.ExposureF`
940 Uses the x, y information in the ``fakeCat`` to position an image of the fake interpolated onto the
941 pixel grid of the image. Sets the ``FAKE`` mask plane for the pixels added with the fake source.
944 imageBBox = image.getBBox()
945 imageMI = image.maskedImage
947 for (fakeImage, xy)
in fakeImages:
948 X0 = xy.getX() - fakeImage.getWidth()/2 + 0.5
949 Y0 = xy.getY() - fakeImage.getHeight()/2 + 0.5
950 self.log.debug(
"Adding fake source at %d, %d" % (xy.getX(), xy.getY()))
951 if sourceType ==
"galaxy":
952 interpFakeImage = afwMath.offsetImage(fakeImage, X0, Y0,
"lanczos3")
954 interpFakeImage = fakeImage
956 interpFakeImBBox = interpFakeImage.getBBox()
957 interpFakeImBBox.clip(imageBBox)
959 if interpFakeImBBox.getArea() > 0:
960 imageMIView = imageMI[interpFakeImBBox]
961 clippedFakeImage = interpFakeImage[interpFakeImBBox]
962 clippedFakeImageMI = afwImage.MaskedImageF(clippedFakeImage)
963 clippedFakeImageMI.mask.set(self.bitmask)
964 imageMIView += clippedFakeImageMI
968 def _getMetadataName(self):
969 """Disable metadata writing"""
def run(self, skyInfo, tempExpRefList, imageScalerList, weightList, altMaskList=None, mask=None, supplementaryData=None)
def addPixCoords(self, fakeCat, image)
def mkFakeStars(self, fakeCat, band, photoCalib, psf, image)
def mkFakeGalsimGalaxies(self, fakeCat, band, photoCalib, pixelScale, psf, image)
def cleanCat(self, fakeCat, starCheckVal)
def processImagesForInsertion(self, fakeCat, wcs, psf, photoCalib, band, pixelScale)
def trimFakeCat(self, fakeCat, image)
def addFakeSources(self, image, fakeImages, sourceType)