lsst.pipe.tasks  20.0.0-19-g3be7e53d+e431f4b42b
insertFakes.py
Go to the documentation of this file.
1 # This file is part of pipe tasks
2 #
3 # Developed for the LSST Data Management System.
4 # This product includes software developed by the LSST Project
5 # (http://www.lsst.org).
6 # See the COPYRIGHT file at the top-level directory of this distribution
7 # for details of code ownership.
8 #
9 # This program is free software: you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation, either version 3 of the License, or
12 # (at your option) any later version.
13 #
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
18 #
19 # You should have received a copy of the GNU General Public License
20 # along with this program. If not, see <http://www.gnu.org/licenses/>.
21 
22 """
23 Insert fakes into deepCoadds
24 """
25 import galsim
26 from astropy.table import Table
27 import numpy as np
28 
29 import lsst.geom as geom
30 import lsst.afw.image as afwImage
31 import lsst.afw.math as afwMath
32 import lsst.pex.config as pexConfig
33 import lsst.pipe.base as pipeBase
34 
35 from lsst.pipe.base import CmdLineTask, PipelineTask, PipelineTaskConfig, PipelineTaskConnections
37 from lsst.pex.exceptions import LogicError, InvalidParameterError
38 from lsst.coadd.utils.coaddDataIdContainer import ExistingCoaddDataIdContainer
39 from lsst.geom import SpherePoint, radians, Box2D
40 from lsst.sphgeom import ConvexPolygon
41 
42 __all__ = ["InsertFakesConfig", "InsertFakesTask"]
43 
44 
45 class InsertFakesConnections(PipelineTaskConnections, defaultTemplates={"CoaddName": "deep"},
46  dimensions=("tract", "patch", "abstract_filter", "skymap")):
47 
48  image = cT.Input(
49  doc="Image into which fakes are to be added.",
50  name="{CoaddName}Coadd",
51  storageClass="ExposureF",
52  dimensions=("tract", "patch", "abstract_filter", "skymap")
53  )
54 
55  fakeCat = cT.Input(
56  doc="Catalog of fake sources to draw inputs from.",
57  name="{CoaddName}Coadd_fakeSourceCat",
58  storageClass="Parquet",
59  dimensions=("tract", "skymap")
60  )
61 
62  imageWithFakes = cT.Output(
63  doc="Image with fake sources added.",
64  name="fakes_{CoaddName}Coadd",
65  storageClass="ExposureF",
66  dimensions=("tract", "patch", "abstract_filter", "skymap")
67  )
68 
69 
70 class InsertFakesConfig(PipelineTaskConfig,
71  pipelineConnections=InsertFakesConnections):
72  """Config for inserting fake sources
73 
74  Notes
75  -----
76  The default column names are those from the University of Washington sims database.
77  """
78 
79  raColName = pexConfig.Field(
80  doc="RA column name used in the fake source catalog.",
81  dtype=str,
82  default="raJ2000",
83  )
84 
85  decColName = pexConfig.Field(
86  doc="Dec. column name used in the fake source catalog.",
87  dtype=str,
88  default="decJ2000",
89  )
90 
91  doCleanCat = pexConfig.Field(
92  doc="If true removes bad sources from the catalog.",
93  dtype=bool,
94  default=True,
95  )
96 
97  diskHLR = pexConfig.Field(
98  doc="Column name for the disk half light radius used in the fake source catalog.",
99  dtype=str,
100  default="DiskHalfLightRadius",
101  )
102 
103  bulgeHLR = pexConfig.Field(
104  doc="Column name for the bulge half light radius used in the fake source catalog.",
105  dtype=str,
106  default="BulgeHalfLightRadius",
107  )
108 
109  magVar = pexConfig.Field(
110  doc="The column name for the magnitude calculated taking variability into account. In the format "
111  "``filter name``magVar, e.g. imagVar for the magnitude in the i band.",
112  dtype=str,
113  default="%smagVar",
114  )
115 
116  nDisk = pexConfig.Field(
117  doc="The column name for the sersic index of the disk component used in the fake source catalog.",
118  dtype=str,
119  default="disk_n",
120  )
121 
122  nBulge = pexConfig.Field(
123  doc="The column name for the sersic index of the bulge component used in the fake source catalog.",
124  dtype=str,
125  default="bulge_n",
126  )
127 
128  aDisk = pexConfig.Field(
129  doc="The column name for the semi major axis length of the disk component used in the fake source"
130  "catalog.",
131  dtype=str,
132  default="a_d",
133  )
134 
135  aBulge = pexConfig.Field(
136  doc="The column name for the semi major axis length of the bulge component.",
137  dtype=str,
138  default="a_b",
139  )
140 
141  bDisk = pexConfig.Field(
142  doc="The column name for the semi minor axis length of the disk component.",
143  dtype=str,
144  default="b_d",
145  )
146 
147  bBulge = pexConfig.Field(
148  doc="The column name for the semi minor axis length of the bulge component used in the fake source "
149  "catalog.",
150  dtype=str,
151  default="b_b",
152  )
153 
154  paDisk = pexConfig.Field(
155  doc="The column name for the PA of the disk component used in the fake source catalog.",
156  dtype=str,
157  default="pa_disk",
158  )
159 
160  paBulge = pexConfig.Field(
161  doc="The column name for the PA of the bulge component used in the fake source catalog.",
162  dtype=str,
163  default="pa_bulge",
164  )
165 
166  sourceType = pexConfig.Field(
167  doc="The column name for the source type used in the fake source catalog.",
168  dtype=str,
169  default="sourceType",
170  )
171 
172  fakeType = pexConfig.Field(
173  doc="What type of fake catalog to use, snapshot (includes variability in the magnitudes calculated "
174  "from the MJD of the image), static (no variability) or filename for a user defined fits"
175  "catalog.",
176  dtype=str,
177  default="static",
178  )
179 
180  calibFluxRadius = pexConfig.Field(
181  doc="Aperture radius (in pixels) that was used to define the calibration for this image+catalog. "
182  "This will be used to produce the correct instrumental fluxes within the radius. "
183  "This value should match that of the field defined in slot_CalibFlux_instFlux.",
184  dtype=float,
185  default=12.0,
186  )
187 
188  coaddName = pexConfig.Field(
189  doc="The name of the type of coadd used",
190  dtype=str,
191  default="deep",
192  )
193 
194  doSubSelectSources = pexConfig.Field(
195  doc="Set to True if you wish to sub select sources to be input based on the value in the column"
196  "set in the sourceSelectionColName config option.",
197  dtype=bool,
198  default=False
199  )
200 
201  sourceSelectionColName = pexConfig.Field(
202  doc="The name of the column in the input fakes catalogue to be used to determine which sources to"
203  "add, default is none and when this is used all sources are added.",
204  dtype=str,
205  default="templateSource"
206  )
207 
208  insertImages = pexConfig.Field(
209  doc="Insert images directly? True or False.",
210  dtype=bool,
211  default=False,
212  )
213 
214 
215 class InsertFakesTask(PipelineTask, CmdLineTask):
216  """Insert fake objects into images.
217 
218  Add fake stars and galaxies to the given image, read in through the dataRef. Galaxy parameters are read in
219  from the specified file and then modelled using galsim.
220 
221  `InsertFakesTask` has five functions that make images of the fake sources and then add them to the
222  image.
223 
224  `addPixCoords`
225  Use the WCS information to add the pixel coordinates of each source.
226  `mkFakeGalsimGalaxies`
227  Use Galsim to make fake double sersic galaxies for each set of galaxy parameters in the input file.
228  `mkFakeStars`
229  Use the PSF information from the image to make a fake star using the magnitude information from the
230  input file.
231  `cleanCat`
232  Remove rows of the input fake catalog which have half light radius, of either the bulge or the disk,
233  that are 0. Also removes rows that have Sersic index outside of galsim's allowed paramters. If
234  the config option sourceSelectionColName is set then this function limits the catalog of input fakes
235  to only those which are True in this column.
236  `addFakeSources`
237  Add the fake sources to the image.
238 
239  """
240 
241  _DefaultName = "insertFakes"
242  ConfigClass = InsertFakesConfig
243 
244  def runDataRef(self, dataRef):
245  """Read in/write out the required data products and add fake sources to the deepCoadd.
246 
247  Parameters
248  ----------
249  dataRef : `lsst.daf.persistence.butlerSubset.ButlerDataRef`
250  Data reference defining the image to have fakes added to it
251  Used to access the following data products:
252  deepCoadd
253  """
254 
255  infoStr = "Adding fakes to: tract: %d, patch: %s, filter: %s" % (dataRef.dataId["tract"],
256  dataRef.dataId["patch"],
257  dataRef.dataId["filter"])
258  self.log.info(infoStr)
259 
260  # To do: should it warn when asked to insert variable sources into the coadd
261 
262  if self.config.fakeType == "static":
263  fakeCat = dataRef.get("deepCoadd_fakeSourceCat").toDataFrame()
264  # To do: DM-16254, the read and write of the fake catalogs will be changed once the new pipeline
265  # task structure for ref cats is in place.
266  self.fakeSourceCatType = "deepCoadd_fakeSourceCat"
267  else:
268  fakeCat = Table.read(self.config.fakeType).to_pandas()
269 
270  coadd = dataRef.get("deepCoadd")
271  wcs = coadd.getWcs()
272  photoCalib = coadd.getPhotoCalib()
273 
274  imageWithFakes = self.run(fakeCat, coadd, wcs, photoCalib)
275 
276  dataRef.put(imageWithFakes.imageWithFakes, "fakes_deepCoadd")
277 
278  def runQuantum(self, butlerQC, inputRefs, outputRefs):
279  inputs = butlerQC.get(inputRefs)
280  inputs["wcs"] = inputs["image"].getWcs()
281  inputs["photoCalib"] = inputs["image"].getPhotoCalib()
282 
283  outputs = self.run(**inputs)
284  butlerQC.put(outputs, outputRefs)
285 
286  @classmethod
287  def _makeArgumentParser(cls):
288  parser = pipeBase.ArgumentParser(name=cls._DefaultName)
289  parser.add_id_argument(name="--id", datasetType="deepCoadd",
290  help="data IDs for the deepCoadd, e.g. --id tract=12345 patch=1,2 filter=r",
291  ContainerClass=ExistingCoaddDataIdContainer)
292  return parser
293 
294  def run(self, fakeCat, image, wcs, photoCalib):
295  """Add fake sources to an image.
296 
297  Parameters
298  ----------
299  fakeCat : `pandas.core.frame.DataFrame`
300  The catalog of fake sources to be input
301  image : `lsst.afw.image.exposure.exposure.ExposureF`
302  The image into which the fake sources should be added
303  wcs : `lsst.afw.geom.SkyWcs`
304  WCS to use to add fake sources
305  photoCalib : `lsst.afw.image.photoCalib.PhotoCalib`
306  Photometric calibration to be used to calibrate the fake sources
307 
308  Returns
309  -------
310  resultStruct : `lsst.pipe.base.struct.Struct`
311  contains : image : `lsst.afw.image.exposure.exposure.ExposureF`
312 
313  Notes
314  -----
315  Adds pixel coordinates for each source to the fakeCat and removes objects with bulge or disk half
316  light radius = 0 (if ``config.doCleanCat = True``).
317 
318  Adds the ``Fake`` mask plane to the image which is then set by `addFakeSources` to mark where fake
319  sources have been added. Uses the information in the ``fakeCat`` to make fake galaxies (using galsim)
320  and fake stars, using the PSF models from the PSF information for the image. These are then added to
321  the image and the image with fakes included returned.
322 
323  The galsim galaxies are made using a double sersic profile, one for the bulge and one for the disk,
324  this is then convolved with the PSF at that point.
325  """
326 
327  image.mask.addMaskPlane("FAKE")
328  self.bitmask = image.mask.getPlaneBitMask("FAKE")
329  self.log.info("Adding mask plane with bitmask %d" % self.bitmask)
330 
331  fakeCat = self.addPixCoords(fakeCat, wcs)
332  fakeCat = self.trimFakeCat(fakeCat, image, wcs)
333  band = image.getFilter().getName()
334  psf = image.getPsf()
335  pixelScale = wcs.getPixelScale().asArcseconds()
336 
337  if len(fakeCat) == 0:
338  errMsg = "No fakes found for this dataRef."
339  raise RuntimeError(errMsg)
340 
341  if isinstance(fakeCat[self.config.sourceType].iloc[0], str):
342  galCheckVal = "galaxy"
343  starCheckVal = "star"
344  elif isinstance(fakeCat[self.config.sourceType].iloc[0], bytes):
345  galCheckVal = b"galaxy"
346  starCheckVal = b"star"
347  elif isinstance(fakeCat[self.config.sourceType].iloc[0], (int, float)):
348  galCheckVal = 1
349  starCheckVal = 0
350  else:
351  raise TypeError("sourceType column does not have required type, should be str, bytes or int")
352 
353  if not self.config.insertImages:
354  if self.config.doCleanCat:
355  fakeCat = self.cleanCat(fakeCat, starCheckVal)
356 
357  galaxies = (fakeCat[self.config.sourceType] == galCheckVal)
358  galImages = self.mkFakeGalsimGalaxies(fakeCat[galaxies], band, photoCalib, pixelScale, psf, image)
359 
360  stars = (fakeCat[self.config.sourceType] == starCheckVal)
361  starImages = self.mkFakeStars(fakeCat[stars], band, photoCalib, psf, image)
362  else:
363  galImages, starImages = self.processImagesForInsertion(fakeCat, wcs, psf, photoCalib, band,
364  pixelScale)
365 
366  image = self.addFakeSources(image, galImages, "galaxy")
367  image = self.addFakeSources(image, starImages, "star")
368  resultStruct = pipeBase.Struct(imageWithFakes=image)
369 
370  return resultStruct
371 
372  def processImagesForInsertion(self, fakeCat, wcs, psf, photoCalib, band, pixelScale):
373  """Process images from files into the format needed for insertion.
374 
375  Parameters
376  ----------
377  fakeCat : `pandas.core.frame.DataFrame`
378  The catalog of fake sources to be input
379  wcs : `lsst.afw.geom.skyWcs.skyWcs.SkyWc`
380  WCS to use to add fake sources
381  psf : `lsst.meas.algorithms.coaddPsf.coaddPsf.CoaddPsf` or
382  `lsst.meas.extensions.psfex.psfexPsf.PsfexPsf`
383  The PSF information to use to make the PSF images
384  photoCalib : `lsst.afw.image.photoCalib.PhotoCalib`
385  Photometric calibration to be used to calibrate the fake sources
386  band : `str`
387  The filter band that the observation was taken in.
388  pixelScale : `float`
389  The pixel scale of the image the sources are to be added to.
390 
391  Returns
392  -------
393  galImages : `list`
394  A list of tuples of `lsst.afw.image.exposure.exposure.ExposureF` and
395  `lsst.geom.Point2D` of their locations.
396  For sources labelled as galaxy.
397  starImages : `list`
398  A list of tuples of `lsst.afw.image.exposure.exposure.ExposureF` and
399  `lsst.geom.Point2D` of their locations.
400  For sources labelled as star.
401 
402  Notes
403  -----
404  The input fakes catalog needs to contain the absolute path to the image in the
405  band that is being used to add images to. It also needs to have the R.A. and
406  declination of the fake source in radians and the sourceType of the object.
407  """
408  galImages = []
409  starImages = []
410 
411  self.log.info("Processing %d fake images" % len(fakeCat))
412 
413  for (imFile, sourceType, mag, x, y) in zip(fakeCat[band + "imFilename"].array,
414  fakeCat["sourceType"].array,
415  fakeCat[self.config.magVar % band].array,
416  fakeCat["x"].array, fakeCat["y"].array):
417 
418  im = afwImage.ImageF.readFits(imFile)
419 
420  xy = geom.Point2D(x, y)
421 
422  # We put these two PSF calculations within this same try block so that we catch cases
423  # where the object's position is outside of the image.
424  try:
425  correctedFlux = psf.computeApertureFlux(self.config.calibFluxRadius, xy)
426  psfKernel = psf.computeKernelImage(xy).getArray()
427  psfKernel /= correctedFlux
428 
429  except InvalidParameterError:
430  self.log.info("%s at %0.4f, %0.4f outside of image" % (sourceType, x, y))
431  continue
432 
433  psfIm = galsim.InterpolatedImage(galsim.Image(psfKernel), scale=pixelScale)
434  galsimIm = galsim.InterpolatedImage(galsim.Image(im.array), scale=pixelScale)
435  convIm = galsim.Convolve([galsimIm, psfIm])
436 
437  try:
438  outIm = convIm.drawImage(scale=pixelScale, method="real_space").array
439  except (galsim.errors.GalSimFFTSizeError, MemoryError):
440  continue
441 
442  imSum = np.sum(outIm)
443  divIm = outIm/imSum
444 
445  try:
446  flux = photoCalib.magnitudeToInstFlux(mag, xy)
447  except LogicError:
448  flux = 0
449 
450  imWithFlux = flux*divIm
451 
452  if sourceType == b"galaxy":
453  galImages.append((afwImage.ImageF(imWithFlux), xy))
454  if sourceType == b"star":
455  starImages.append((afwImage.ImageF(imWithFlux), xy))
456 
457  return galImages, starImages
458 
459  def addPixCoords(self, fakeCat, wcs):
460 
461  """Add pixel coordinates to the catalog of fakes.
462 
463  Parameters
464  ----------
465  fakeCat : `pandas.core.frame.DataFrame`
466  The catalog of fake sources to be input
467  wcs : `lsst.afw.geom.SkyWcs`
468  WCS to use to add fake sources
469 
470  Returns
471  -------
472  fakeCat : `pandas.core.frame.DataFrame`
473 
474  Notes
475  -----
476  The default option is to use the WCS information from the image. If the ``useUpdatedCalibs`` config
477  option is set then it will use the updated WCS from jointCal.
478  """
479 
480  ras = fakeCat[self.config.raColName].values
481  decs = fakeCat[self.config.decColName].values
482  skyCoords = [SpherePoint(ra, dec, radians) for (ra, dec) in zip(ras, decs)]
483  pixCoords = wcs.skyToPixel(skyCoords)
484  xs = [coord.getX() for coord in pixCoords]
485  ys = [coord.getY() for coord in pixCoords]
486  fakeCat["x"] = xs
487  fakeCat["y"] = ys
488 
489  return fakeCat
490 
491  def trimFakeCat(self, fakeCat, image, wcs):
492  """Trim the fake cat to about the size of the input image.
493 
494  Parameters
495  ----------
496  fakeCat : `pandas.core.frame.DataFrame`
497  The catalog of fake sources to be input
498  image : `lsst.afw.image.exposure.exposure.ExposureF`
499  The image into which the fake sources should be added
500  wcs : `lsst.afw.geom.SkyWcs`
501  WCS to use to add fake sources
502 
503  Returns
504  -------
505  fakeCat : `pandas.core.frame.DataFrame`
506  The original fakeCat trimmed to the area of the image
507  """
508 
509  bbox = Box2D(image.getBBox())
510  corners = bbox.getCorners()
511 
512  skyCorners = wcs.pixelToSky(corners)
513  region = ConvexPolygon([s.getVector() for s in skyCorners])
514 
515  def trim(row):
516  coord = SpherePoint(row[self.config.raColName], row[self.config.decColName], radians)
517  return region.contains(coord.getVector())
518 
519  return fakeCat[fakeCat.apply(trim, axis=1)]
520 
521  def mkFakeGalsimGalaxies(self, fakeCat, band, photoCalib, pixelScale, psf, image):
522  """Make images of fake galaxies using GalSim.
523 
524  Parameters
525  ----------
526  band : `str`
527  pixelScale : `float`
528  psf : `lsst.meas.extensions.psfex.psfexPsf.PsfexPsf`
529  The PSF information to use to make the PSF images
530  fakeCat : `pandas.core.frame.DataFrame`
531  The catalog of fake sources to be input
532  photoCalib : `lsst.afw.image.photoCalib.PhotoCalib`
533  Photometric calibration to be used to calibrate the fake sources
534 
535  Yields
536  -------
537  galImages : `generator`
538  A generator of tuples of `lsst.afw.image.exposure.exposure.ExposureF` and
539  `lsst.geom.Point2D` of their locations.
540 
541  Notes
542  -----
543 
544  Fake galaxies are made by combining two sersic profiles, one for the bulge and one for the disk. Each
545  component has an individual sersic index (n), a, b and position angle (PA). The combined profile is
546  then convolved with the PSF at the specified x, y position on the image.
547 
548  The names of the columns in the ``fakeCat`` are configurable and are the column names from the
549  University of Washington simulations database as default. For more information see the doc strings
550  attached to the config options.
551 
552  See mkFakeStars doc string for an explanation of calibration to instrumental flux.
553  """
554 
555  self.log.info("Making %d fake galaxy images" % len(fakeCat))
556 
557  for (index, row) in fakeCat.iterrows():
558  xy = geom.Point2D(row["x"], row["y"])
559 
560  # We put these two PSF calculations within this same try block so that we catch cases
561  # where the object's position is outside of the image.
562  try:
563  correctedFlux = psf.computeApertureFlux(self.config.calibFluxRadius, xy)
564  psfKernel = psf.computeKernelImage(xy).getArray()
565  psfKernel /= correctedFlux
566 
567  except InvalidParameterError:
568  self.log.info("Galaxy at %0.4f, %0.4f outside of image" % (row["x"], row["y"]))
569  continue
570 
571  try:
572  flux = photoCalib.magnitudeToInstFlux(row[self.config.magVar % band], xy)
573  except LogicError:
574  flux = 0
575 
576  bulge = galsim.Sersic(row[self.config.nBulge], half_light_radius=row[self.config.bulgeHLR])
577  axisRatioBulge = row[self.config.bBulge]/row[self.config.aBulge]
578  bulge = bulge.shear(q=axisRatioBulge, beta=((90 - row[self.config.paBulge])*galsim.degrees))
579 
580  disk = galsim.Sersic(row[self.config.nDisk], half_light_radius=row[self.config.diskHLR])
581  axisRatioDisk = row[self.config.bDisk]/row[self.config.aDisk]
582  disk = disk.shear(q=axisRatioDisk, beta=((90 - row[self.config.paDisk])*galsim.degrees))
583 
584  gal = disk + bulge
585  gal = gal.withFlux(flux)
586 
587  psfIm = galsim.InterpolatedImage(galsim.Image(psfKernel), scale=pixelScale)
588  gal = galsim.Convolve([gal, psfIm])
589  try:
590  galIm = gal.drawImage(scale=pixelScale, method="real_space").array
591  except (galsim.errors.GalSimFFTSizeError, MemoryError):
592  continue
593 
594  yield (afwImage.ImageF(galIm), xy)
595 
596  def mkFakeStars(self, fakeCat, band, photoCalib, psf, image):
597 
598  """Make fake stars based off the properties in the fakeCat.
599 
600  Parameters
601  ----------
602  band : `str`
603  psf : `lsst.meas.extensions.psfex.psfexPsf.PsfexPsf`
604  The PSF information to use to make the PSF images
605  fakeCat : `pandas.core.frame.DataFrame`
606  The catalog of fake sources to be input
607  image : `lsst.afw.image.exposure.exposure.ExposureF`
608  The image into which the fake sources should be added
609  photoCalib : `lsst.afw.image.photoCalib.PhotoCalib`
610  Photometric calibration to be used to calibrate the fake sources
611 
612  Yields
613  -------
614  starImages : `generator`
615  A generator of tuples of `lsst.afw.image.ImageF` of fake stars and
616  `lsst.geom.Point2D` of their locations.
617 
618  Notes
619  -----
620  To take a given magnitude and translate to the number of counts in the image
621  we use photoCalib.magnitudeToInstFlux, which returns the instrumental flux for the
622  given calibration radius used in the photometric calibration step.
623  Thus `calibFluxRadius` should be set to this same radius so that we can normalize
624  the PSF model to the correct instrumental flux within calibFluxRadius.
625  """
626 
627  self.log.info("Making %d fake star images" % len(fakeCat))
628 
629  for (index, row) in fakeCat.iterrows():
630  xy = geom.Point2D(row["x"], row["y"])
631 
632  # We put these two PSF calculations within this same try block so that we catch cases
633  # where the object's position is outside of the image.
634  try:
635  correctedFlux = psf.computeApertureFlux(self.config.calibFluxRadius, xy)
636  starIm = psf.computeImage(xy)
637  starIm /= correctedFlux
638 
639  except InvalidParameterError:
640  self.log.info("Star at %0.4f, %0.4f outside of image" % (row["x"], row["y"]))
641  continue
642 
643  try:
644  flux = photoCalib.magnitudeToInstFlux(row[self.config.magVar % band], xy)
645  except LogicError:
646  flux = 0
647 
648  starIm *= flux
649  yield ((starIm.convertF(), xy))
650 
651  def cleanCat(self, fakeCat, starCheckVal):
652  """Remove rows from the fakes catalog which have HLR = 0 for either the buldge or disk component,
653  also remove galaxies that have Sersic index outside the galsim min and max
654  allowed (0.3 <= n <= 6.2).
655 
656  Parameters
657  ----------
658  fakeCat : `pandas.core.frame.DataFrame`
659  The catalog of fake sources to be input
660  starCheckVal : `str`, `bytes` or `int`
661  The value that is set in the sourceType column to specifiy an object is a star.
662 
663  Returns
664  -------
665  fakeCat : `pandas.core.frame.DataFrame`
666  The input catalog of fake sources but with the bad objects removed
667 
668  Notes
669  -----
670  If the config option sourceSelectionColName is set then only objects with this column set to True
671  will be added.
672  """
673 
674  rowsToKeep = ((fakeCat[self.config.bulgeHLR] != 0.0) & (fakeCat[self.config.diskHLR] != 0.0))
675  numRowsNotUsed = len(fakeCat) - len(np.where(rowsToKeep)[0])
676  self.log.info("Removing %d rows with HLR = 0 for either the bulge or disk" % numRowsNotUsed)
677  fakeCat = fakeCat[rowsToKeep]
678 
679  minN = galsim.Sersic._minimum_n
680  maxN = galsim.Sersic._maximum_n
681  rowsWithGoodSersic = (((fakeCat[self.config.nBulge] >= minN) & (fakeCat[self.config.nBulge] <= maxN)
682  & (fakeCat[self.config.nDisk] >= minN) & (fakeCat[self.config.nDisk] <= maxN))
683  | (fakeCat[self.config.sourceType] == starCheckVal))
684  numRowsNotUsed = len(fakeCat) - len(np.where(rowsWithGoodSersic)[0])
685  self.log.info("Removing %d rows of galaxies with nBulge or nDisk outside of %0.2f <= n <= %0.2f" %
686  (numRowsNotUsed, minN, maxN))
687  fakeCat = fakeCat[rowsWithGoodSersic]
688 
689  if self.config.doSubSelectSources:
690  try:
691  rowsSelected = (fakeCat[self.config.sourceSelectionColName])
692  except KeyError:
693  raise KeyError("Given column, %s, for source selection not found." %
694  self.config.sourceSelectionColName)
695  numRowsNotUsed = len(fakeCat) - len(rowsSelected)
696  self.log.info("Removing %d rows which were not designated as template sources" % numRowsNotUsed)
697  fakeCat = fakeCat[rowsSelected]
698 
699  return fakeCat
700 
701  def addFakeSources(self, image, fakeImages, sourceType):
702  """Add the fake sources to the given image
703 
704  Parameters
705  ----------
706  image : `lsst.afw.image.exposure.exposure.ExposureF`
707  The image into which the fake sources should be added
708  fakeImages : `typing.Iterator` [`tuple` ['lsst.afw.image.ImageF`, `lsst.geom.Point2d`]]
709  An iterator of tuples that contains (or generates) images of fake sources,
710  and the locations they are to be inserted at.
711  sourceType : `str`
712  The type (star/galaxy) of fake sources input
713 
714  Returns
715  -------
716  image : `lsst.afw.image.exposure.exposure.ExposureF`
717 
718  Notes
719  -----
720  Uses the x, y information in the ``fakeCat`` to position an image of the fake interpolated onto the
721  pixel grid of the image. Sets the ``FAKE`` mask plane for the pixels added with the fake source.
722  """
723 
724  imageBBox = image.getBBox()
725  imageMI = image.maskedImage
726 
727  for (fakeImage, xy) in fakeImages:
728  X0 = xy.getX() - fakeImage.getWidth()/2 + 0.5
729  Y0 = xy.getY() - fakeImage.getHeight()/2 + 0.5
730  self.log.debug("Adding fake source at %d, %d" % (xy.getX(), xy.getY()))
731  if sourceType == "galaxy":
732  interpFakeImage = afwMath.offsetImage(fakeImage, X0, Y0, "lanczos3")
733  interpFakeImBBox = interpFakeImage.getBBox()
734  else:
735  interpFakeImage = fakeImage
736  interpFakeImBBox = fakeImage.getBBox()
737 
738  interpFakeImBBox.clip(imageBBox)
739  imageMIView = imageMI.Factory(imageMI, interpFakeImBBox)
740 
741  if interpFakeImBBox.getArea() > 0:
742  clippedFakeImage = interpFakeImage.Factory(interpFakeImage, interpFakeImBBox)
743  clippedFakeImageMI = afwImage.MaskedImageF(clippedFakeImage)
744  clippedFakeImageMI.mask.set(self.bitmask)
745  imageMIView += clippedFakeImageMI
746 
747  return image
748 
749  def _getMetadataName(self):
750  """Disable metadata writing"""
751  return None
lsst::afw::image
lsst.pipe.tasks.insertFakes.trimFakeCat
def trimFakeCat(self, fakeCat, image, wcs)
Definition: insertFakes.py:491
lsst.pipe.tasks.insertFakes.cleanCat
def cleanCat(self, fakeCat, starCheckVal)
Definition: insertFakes.py:651
lsst.pipe.tasks.insertFakes.InsertFakesConnections
Definition: insertFakes.py:45
lsst.pipe.tasks.insertFakes.addPixCoords
def addPixCoords(self, fakeCat, wcs)
Definition: insertFakes.py:459
lsst::sphgeom::ConvexPolygon
lsst.pipe.tasks.assembleCoadd.run
def run(self, skyInfo, tempExpRefList, imageScalerList, weightList, altMaskList=None, mask=None, supplementaryData=None)
Definition: assembleCoadd.py:713
lsst.pipe.tasks.insertFakes.addFakeSources
def addFakeSources(self, image, fakeImages, sourceType)
Definition: insertFakes.py:701
lsst::pex::config
lsst.pipe.tasks.insertFakes.mkFakeGalsimGalaxies
def mkFakeGalsimGalaxies(self, fakeCat, band, photoCalib, pixelScale, psf, image)
Definition: insertFakes.py:521
lsst::geom
lsst::afw::math
Point< double, 2 >
lsst.pipe.tasks.insertFakes.mkFakeStars
def mkFakeStars(self, fakeCat, band, photoCalib, psf, image)
Definition: insertFakes.py:596
lsst::pex::exceptions
lsst::sphgeom
lsst::geom::SpherePoint
lsst::coadd::utils::coaddDataIdContainer
lsst::geom::Box2D
lsst.pipe::base
lsst.pipe::base::connectionTypes