lsst.pipe.tasks  20.0.0-17-g98646ba4+9883c8d2a9
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)
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 
363  else:
364  galImages, starImages = self.processImagesForInsertion(fakeCat, wcs, psf, photoCalib, band,
365  pixelScale)
366 
367  image = self.addFakeSources(image, galImages, "galaxy")
368  image = self.addFakeSources(image, starImages, "star")
369  resultStruct = pipeBase.Struct(imageWithFakes=image)
370 
371  return resultStruct
372 
373  def processImagesForInsertion(self, fakeCat, wcs, psf, photoCalib, band, pixelScale):
374  """Process images from files into the format needed for insertion.
375 
376  Parameters
377  ----------
378  fakeCat : `pandas.core.frame.DataFrame`
379  The catalog of fake sources to be input
380  wcs : `lsst.afw.geom.skyWcs.skyWcs.SkyWc`
381  WCS to use to add fake sources
382  psf : `lsst.meas.algorithms.coaddPsf.coaddPsf.CoaddPsf` or
383  `lsst.meas.extensions.psfex.psfexPsf.PsfexPsf`
384  The PSF information to use to make the PSF images
385  photoCalib : `lsst.afw.image.photoCalib.PhotoCalib`
386  Photometric calibration to be used to calibrate the fake sources
387  band : `str`
388  The filter band that the observation was taken in.
389  pixelScale : `float`
390  The pixel scale of the image the sources are to be added to.
391 
392  Returns
393  -------
394  galImages : `list`
395  A list of tuples of `lsst.afw.image.exposure.exposure.ExposureF` and
396  `lsst.geom.Point2D` of their locations.
397  For sources labelled as galaxy.
398  starImages : `list`
399  A list of tuples of `lsst.afw.image.exposure.exposure.ExposureF` and
400  `lsst.geom.Point2D` of their locations.
401  For sources labelled as star.
402 
403  Notes
404  -----
405  The input fakes catalog needs to contain the absolute path to the image in the
406  band that is being used to add images to. It also needs to have the R.A. and
407  declination of the fake source in radians and the sourceType of the object.
408  """
409  galImages = []
410  starImages = []
411 
412  self.log.info("Processing %d fake images" % len(fakeCat))
413 
414  for (imFile, sourceType, mag, x, y) in zip(fakeCat[band + "imFilename"].array,
415  fakeCat["sourceType"].array,
416  fakeCat[self.config.magVar % band].array,
417  fakeCat["x"].array, fakeCat["y"].array):
418 
419  im = afwImage.ImageF.readFits(imFile)
420 
421  xy = geom.Point2D(x, y)
422 
423  # We put these two PSF calculations within this same try block so that we catch cases
424  # where the object's position is outside of the image.
425  try:
426  correctedFlux = psf.computeApertureFlux(self.config.calibFluxRadius, xy)
427  psfKernel = psf.computeKernelImage(xy).getArray()
428  psfKernel /= correctedFlux
429 
430  except InvalidParameterError:
431  self.log.info("%s at %0.4f, %0.4f outside of image" % (sourceType, x, y))
432  continue
433 
434  psfIm = galsim.InterpolatedImage(galsim.Image(psfKernel), scale=pixelScale)
435  galsimIm = galsim.InterpolatedImage(galsim.Image(im.array), scale=pixelScale)
436  convIm = galsim.Convolve([galsimIm, psfIm])
437 
438  try:
439  outIm = convIm.drawImage(scale=pixelScale, method="real_space").array
440  except (galsim.errors.GalSimFFTSizeError, MemoryError):
441  continue
442 
443  imSum = np.sum(outIm)
444  divIm = outIm/imSum
445 
446  try:
447  flux = photoCalib.magnitudeToInstFlux(mag, xy)
448  except LogicError:
449  flux = 0
450 
451  imWithFlux = flux*divIm
452 
453  if sourceType == b"galaxy":
454  galImages.append((afwImage.ImageF(imWithFlux), xy))
455  if sourceType == b"star":
456  starImages.append((afwImage.ImageF(imWithFlux), xy))
457 
458  return galImages, starImages
459 
460  def addPixCoords(self, fakeCat, wcs):
461 
462  """Add pixel coordinates to the catalog of fakes.
463 
464  Parameters
465  ----------
466  fakeCat : `pandas.core.frame.DataFrame`
467  The catalog of fake sources to be input
468  wcs : `lsst.afw.geom.SkyWcs`
469  WCS to use to add fake sources
470 
471  Returns
472  -------
473  fakeCat : `pandas.core.frame.DataFrame`
474 
475  Notes
476  -----
477  The default option is to use the WCS information from the image. If the ``useUpdatedCalibs`` config
478  option is set then it will use the updated WCS from jointCal.
479  """
480 
481  ras = fakeCat[self.config.raColName].values
482  decs = fakeCat[self.config.decColName].values
483  skyCoords = [SpherePoint(ra, dec, radians) for (ra, dec) in zip(ras, decs)]
484  pixCoords = wcs.skyToPixel(skyCoords)
485  xs = [coord.getX() for coord in pixCoords]
486  ys = [coord.getY() for coord in pixCoords]
487  fakeCat["x"] = xs
488  fakeCat["y"] = ys
489 
490  return fakeCat
491 
492  def trimFakeCat(self, fakeCat, image, wcs):
493  """Trim the fake cat to about the size of the input image.
494 
495  Parameters
496  ----------
497  fakeCat : `pandas.core.frame.DataFrame`
498  The catalog of fake sources to be input
499  image : `lsst.afw.image.exposure.exposure.ExposureF`
500  The image into which the fake sources should be added
501  wcs : `lsst.afw.geom.SkyWcs`
502  WCS to use to add fake sources
503 
504  Returns
505  -------
506  fakeCat : `pandas.core.frame.DataFrame`
507  The original fakeCat trimmed to the area of the image
508  """
509 
510  bbox = Box2D(image.getBBox())
511  corners = bbox.getCorners()
512 
513  skyCorners = wcs.pixelToSky(corners)
514  region = ConvexPolygon([s.getVector() for s in skyCorners])
515 
516  def trim(row):
517  coord = SpherePoint(row[self.config.raColName], row[self.config.decColName], radians)
518  return region.contains(coord.getVector())
519 
520  return fakeCat[fakeCat.apply(trim, axis=1)]
521 
522  def mkFakeGalsimGalaxies(self, fakeCat, band, photoCalib, pixelScale, psf, image):
523  """Make images of fake galaxies using GalSim.
524 
525  Parameters
526  ----------
527  band : `str`
528  pixelScale : `float`
529  psf : `lsst.meas.extensions.psfex.psfexPsf.PsfexPsf`
530  The PSF information to use to make the PSF images
531  fakeCat : `pandas.core.frame.DataFrame`
532  The catalog of fake sources to be input
533  photoCalib : `lsst.afw.image.photoCalib.PhotoCalib`
534  Photometric calibration to be used to calibrate the fake sources
535 
536  Yields
537  -------
538  galImages : `generator`
539  A generator of tuples of `lsst.afw.image.exposure.exposure.ExposureF` and
540  `lsst.geom.Point2D` of their locations.
541 
542  Notes
543  -----
544 
545  Fake galaxies are made by combining two sersic profiles, one for the bulge and one for the disk. Each
546  component has an individual sersic index (n), a, b and position angle (PA). The combined profile is
547  then convolved with the PSF at the specified x, y position on the image.
548 
549  The names of the columns in the ``fakeCat`` are configurable and are the column names from the
550  University of Washington simulations database as default. For more information see the doc strings
551  attached to the config options.
552 
553  See mkFakeStars doc string for an explanation of calibration to instrumental flux.
554  """
555 
556  self.log.info("Making %d fake galaxy images" % len(fakeCat))
557 
558  for (index, row) in fakeCat.iterrows():
559  xy = geom.Point2D(row["x"], row["y"])
560 
561  # We put these two PSF calculations within this same try block so that we catch cases
562  # where the object's position is outside of the image.
563  try:
564  correctedFlux = psf.computeApertureFlux(self.config.calibFluxRadius, xy)
565  psfKernel = psf.computeKernelImage(xy).getArray()
566  psfKernel /= correctedFlux
567 
568  except InvalidParameterError:
569  self.log.info("Galaxy at %0.4f, %0.4f outside of image" % (row["x"], row["y"]))
570  continue
571 
572  try:
573  flux = photoCalib.magnitudeToInstFlux(row[self.config.magVar % band], xy)
574  except LogicError:
575  flux = 0
576 
577  bulge = galsim.Sersic(row[self.config.nBulge], half_light_radius=row[self.config.bulgeHLR])
578  axisRatioBulge = row[self.config.bBulge]/row[self.config.aBulge]
579  bulge = bulge.shear(q=axisRatioBulge, beta=((90 - row[self.config.paBulge])*galsim.degrees))
580 
581  disk = galsim.Sersic(row[self.config.nDisk], half_light_radius=row[self.config.diskHLR])
582  axisRatioDisk = row[self.config.bDisk]/row[self.config.aDisk]
583  disk = disk.shear(q=axisRatioDisk, beta=((90 - row[self.config.paDisk])*galsim.degrees))
584 
585  gal = disk + bulge
586  gal = gal.withFlux(flux)
587 
588  psfIm = galsim.InterpolatedImage(galsim.Image(psfKernel), scale=pixelScale)
589  gal = galsim.Convolve([gal, psfIm])
590  try:
591  galIm = gal.drawImage(scale=pixelScale, method="real_space").array
592  except (galsim.errors.GalSimFFTSizeError, MemoryError):
593  continue
594 
595  yield (afwImage.ImageF(galIm), xy)
596 
597  def mkFakeStars(self, fakeCat, band, photoCalib, psf, image):
598 
599  """Make fake stars based off the properties in the fakeCat.
600 
601  Parameters
602  ----------
603  band : `str`
604  psf : `lsst.meas.extensions.psfex.psfexPsf.PsfexPsf`
605  The PSF information to use to make the PSF images
606  fakeCat : `pandas.core.frame.DataFrame`
607  The catalog of fake sources to be input
608  image : `lsst.afw.image.exposure.exposure.ExposureF`
609  The image into which the fake sources should be added
610  photoCalib : `lsst.afw.image.photoCalib.PhotoCalib`
611  Photometric calibration to be used to calibrate the fake sources
612 
613  Yields
614  -------
615  starImages : `generator`
616  A generator of tuples of `lsst.afw.image.ImageF` of fake stars and
617  `lsst.geom.Point2D` of their locations.
618 
619  Notes
620  -----
621  To take a given magnitude and translate to the number of counts in the image
622  we use photoCalib.magnitudeToInstFlux, which returns the instrumental flux for the
623  given calibration radius used in the photometric calibration step.
624  Thus `calibFluxRadius` should be set to this same radius so that we can normalize
625  the PSF model to the correct instrumental flux within calibFluxRadius.
626  """
627 
628  self.log.info("Making %d fake star images" % len(fakeCat))
629 
630  for (index, row) in fakeCat.iterrows():
631  xy = geom.Point2D(row["x"], row["y"])
632 
633  # We put these two PSF calculations within this same try block so that we catch cases
634  # where the object's position is outside of the image.
635  try:
636  correctedFlux = psf.computeApertureFlux(self.config.calibFluxRadius, xy)
637  starIm = psf.computeImage(xy)
638  starIm /= correctedFlux
639 
640  except InvalidParameterError:
641  self.log.info("Star at %0.4f, %0.4f outside of image" % (row["x"], row["y"]))
642  continue
643 
644  try:
645  flux = photoCalib.magnitudeToInstFlux(row[self.config.magVar % band], xy)
646  except LogicError:
647  flux = 0
648 
649  starIm *= flux
650  yield ((starIm.convertF(), xy))
651 
652  def cleanCat(self, fakeCat):
653  """Remove rows from the fakes catalog which have HLR = 0 for either the buldge or disk component,
654  also remove rows that have Sersic index outside the galsim min and max 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 
661  Returns
662  -------
663  fakeCat : `pandas.core.frame.DataFrame`
664  The input catalog of fake sources but with the bad objects removed
665 
666  Notes
667  -----
668  If the config option sourceSelectionColName is set then only objects with this column set to True
669  will be added.
670  """
671 
672  rowsToKeep = ((fakeCat[self.config.bulgeHLR] != 0.0) & (fakeCat[self.config.diskHLR] != 0.0))
673  numRowsNotUsed = len(fakeCat) - len(rowsToKeep)
674  self.log.info("Removing %d rows with HLR = 0 for either the bulge or disk" % numRowsNotUsed)
675  fakeCat = fakeCat[rowsToKeep]
676 
677  minN = galsim.Sersic._minimum_n
678  maxN = galsim.Sersic._maximum_n
679  rowsToKeep = ((fakeCat[self.config.nBulge] >= minN) & (fakeCat[self.config.nBulge] <= maxN)
680  & (fakeCat[self.config.nDisk] >= minN) & (fakeCat[self.config.nDisk] <= maxN))
681  numRowsNotUsed = len(fakeCat) - len(rowsToKeep)
682  self.log.info("Removing %d rows with nBulge or nDisk outside of %0.2f <= n <= %0.2f" %
683  (numRowsNotUsed, minN, maxN))
684 
685  if self.config.doSubSelectSources:
686  try:
687  rowsToKeep = (fakeCat[self.config.sourceSelectionColName])
688  except KeyError:
689  raise KeyError("Given column, %s, for source selection not found." %
690  self.config.sourceSelectionColName)
691  numRowsNotUsed = len(fakeCat) - len(rowsToKeep)
692  self.log.info("Removing %d rows which were not designated as template sources" % numRowsNotUsed)
693 
694  return fakeCat[rowsToKeep]
695 
696  def addFakeSources(self, image, fakeImages, sourceType):
697  """Add the fake sources to the given image
698 
699  Parameters
700  ----------
701  image : `lsst.afw.image.exposure.exposure.ExposureF`
702  The image into which the fake sources should be added
703  fakeImages : `typing.Iterator` [`tuple` ['lsst.afw.image.ImageF`, `lsst.geom.Point2d`]]
704  An iterator of tuples that contains (or generates) images of fake sources,
705  and the locations they are to be inserted at.
706  sourceType : `str`
707  The type (star/galaxy) of fake sources input
708 
709  Returns
710  -------
711  image : `lsst.afw.image.exposure.exposure.ExposureF`
712 
713  Notes
714  -----
715  Uses the x, y information in the ``fakeCat`` to position an image of the fake interpolated onto the
716  pixel grid of the image. Sets the ``FAKE`` mask plane for the pixels added with the fake source.
717  """
718 
719  imageBBox = image.getBBox()
720  imageMI = image.maskedImage
721 
722  for (fakeImage, xy) in fakeImages:
723  X0 = xy.getX() - fakeImage.getWidth()/2 + 0.5
724  Y0 = xy.getY() - fakeImage.getHeight()/2 + 0.5
725  self.log.debug("Adding fake source at %d, %d" % (xy.getX(), xy.getY()))
726  if sourceType == "galaxy":
727  interpFakeImage = afwMath.offsetImage(fakeImage, X0, Y0, "lanczos3")
728  interpFakeImBBox = interpFakeImage.getBBox()
729  else:
730  interpFakeImage = fakeImage
731  interpFakeImBBox = fakeImage.getBBox()
732 
733  interpFakeImBBox.clip(imageBBox)
734  imageMIView = imageMI.Factory(imageMI, interpFakeImBBox)
735 
736  if interpFakeImBBox.getArea() > 0:
737  clippedFakeImage = interpFakeImage.Factory(interpFakeImage, interpFakeImBBox)
738  clippedFakeImageMI = afwImage.MaskedImageF(clippedFakeImage)
739  clippedFakeImageMI.mask.set(self.bitmask)
740  imageMIView += clippedFakeImageMI
741 
742  return image
743 
744  def _getMetadataName(self):
745  """Disable metadata writing"""
746  return None
lsst::afw::image
lsst.pipe.tasks.insertFakes.trimFakeCat
def trimFakeCat(self, fakeCat, image, wcs)
Definition: insertFakes.py:492
lsst.pipe.tasks.insertFakes.InsertFakesConnections
Definition: insertFakes.py:45
lsst.pipe.tasks.insertFakes.addPixCoords
def addPixCoords(self, fakeCat, wcs)
Definition: insertFakes.py:460
lsst::sphgeom::ConvexPolygon
lsst.pipe.tasks.assembleCoadd.run
def run(self, skyInfo, tempExpRefList, imageScalerList, weightList, altMaskList=None, mask=None, supplementaryData=None)
Definition: assembleCoadd.py:712
lsst.pipe.tasks.insertFakes.addFakeSources
def addFakeSources(self, image, fakeImages, sourceType)
Definition: insertFakes.py:696
lsst.pipe.tasks.insertFakes.mkFakeGalsimGalaxies
def mkFakeGalsimGalaxies(self, fakeCat, band, photoCalib, pixelScale, psf, image)
Definition: insertFakes.py:522
lsst::geom
lsst::afw::math
Point< double, 2 >
lsst.pipe.tasks.insertFakes.mkFakeStars
def mkFakeStars(self, fakeCat, band, photoCalib, psf, image)
Definition: insertFakes.py:597
lsst::pex::exceptions
lsst::sphgeom
lsst::geom::SpherePoint
lsst::coadd::utils::coaddDataIdContainer
lsst::geom::Box2D
lsst.pipe::base
lsst.pipe::base::connectionTypes
lsst.pipe.tasks.insertFakes.cleanCat
def cleanCat(self, fakeCat)
Definition: insertFakes.py:652