LSST Applications  21.0.0-147-g0e635eb1+1acddb5be5,22.0.0+052faf71bd,22.0.0+1ea9a8b2b2,22.0.0+6312710a6c,22.0.0+729191ecac,22.0.0+7589c3a021,22.0.0+9f079a9461,22.0.1-1-g7d6de66+b8044ec9de,22.0.1-1-g87000a6+536b1ee016,22.0.1-1-g8e32f31+6312710a6c,22.0.1-10-gd060f87+016f7cdc03,22.0.1-12-g9c3108e+df145f6f68,22.0.1-16-g314fa6d+c825727ab8,22.0.1-19-g93a5c75+d23f2fb6d8,22.0.1-19-gb93eaa13+aab3ef7709,22.0.1-2-g8ef0a89+b8044ec9de,22.0.1-2-g92698f7+9f079a9461,22.0.1-2-ga9b0f51+052faf71bd,22.0.1-2-gac51dbf+052faf71bd,22.0.1-2-gb66926d+6312710a6c,22.0.1-2-gcb770ba+09e3807989,22.0.1-20-g32debb5+b8044ec9de,22.0.1-23-gc2439a9a+fb0756638e,22.0.1-3-g496fd5d+09117f784f,22.0.1-3-g59f966b+1e6ba2c031,22.0.1-3-g849a1b8+f8b568069f,22.0.1-3-gaaec9c0+c5c846a8b1,22.0.1-32-g5ddfab5d3+60ce4897b0,22.0.1-4-g037fbe1+64e601228d,22.0.1-4-g8623105+b8044ec9de,22.0.1-5-g096abc9+d18c45d440,22.0.1-5-g15c806e+57f5c03693,22.0.1-7-gba73697+57f5c03693,master-g6e05de7fdc+c1283a92b8,master-g72cdda8301+729191ecac,w.2021.39
LSST Data Management Base Package
processCcdWithFakes.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 fake sources into calexps
24 """
25 from astropy.table import Table
26 import numpy as np
27 import pandas as pd
28 
29 import lsst.pex.config as pexConfig
30 import lsst.pipe.base as pipeBase
31 
32 from .insertFakes import InsertFakesTask
33 from lsst.meas.base import PerTractCcdDataIdContainer
34 from lsst.afw.table import SourceTable
35 from lsst.obs.base import ExposureIdInfo
36 from lsst.pipe.base import PipelineTask, PipelineTaskConfig, CmdLineTask, PipelineTaskConnections
37 import lsst.pipe.base.connectionTypes as cT
38 import lsst.afw.table as afwTable
39 from lsst.pipe.tasks.calibrate import CalibrateTask
40 
41 __all__ = ["ProcessCcdWithFakesConfig", "ProcessCcdWithFakesTask",
42  "ProcessCcdWithVariableFakesConfig", "ProcessCcdWithVariableFakesTask"]
43 
44 
45 class ProcessCcdWithFakesConnections(PipelineTaskConnections,
46  dimensions=("skymap", "tract", "instrument", "visit", "detector"),
47  defaultTemplates={"coaddName": "deep",
48  "wcsName": "jointcal",
49  "photoCalibName": "jointcal",
50  "fakesType": "fakes_"}):
51 
52  exposure = cT.Input(
53  doc="Exposure into which fakes are to be added.",
54  name="calexp",
55  storageClass="ExposureF",
56  dimensions=("instrument", "visit", "detector")
57  )
58 
59  fakeCat = cT.Input(
60  doc="Catalog of fake sources to draw inputs from.",
61  name="{fakesType}fakeSourceCat",
62  storageClass="DataFrame",
63  dimensions=("tract", "skymap")
64  )
65 
66  wcs = cT.Input(
67  doc="WCS information for the input exposure.",
68  name="{wcsName}_wcs",
69  storageClass="Wcs",
70  dimensions=("tract", "skymap", "instrument", "visit", "detector")
71  )
72 
73  photoCalib = cT.Input(
74  doc="Calib information for the input exposure.",
75  name="{photoCalibName}_photoCalib",
76  storageClass="PhotoCalib",
77  dimensions=("tract", "skymap", "instrument", "visit", "detector")
78  )
79 
80  icSourceCat = cT.Input(
81  doc="Catalog of calibration sources",
82  name="icSrc",
83  storageClass="SourceCatalog",
84  dimensions=("instrument", "visit", "detector")
85  )
86 
87  sfdSourceCat = cT.Input(
88  doc="Catalog of calibration sources",
89  name="src",
90  storageClass="SourceCatalog",
91  dimensions=("instrument", "visit", "detector")
92  )
93 
94  outputExposure = cT.Output(
95  doc="Exposure with fake sources added.",
96  name="{fakesType}calexp",
97  storageClass="ExposureF",
98  dimensions=("instrument", "visit", "detector")
99  )
100 
101  outputCat = cT.Output(
102  doc="Source catalog produced in calibrate task with fakes also measured.",
103  name="{fakesType}src",
104  storageClass="SourceCatalog",
105  dimensions=("instrument", "visit", "detector"),
106  )
107 
108  def __init__(self, *, config=None):
109  super().__init__(config=config)
110 
111  if config.doApplyExternalSkyWcs is False:
112  self.inputs.remove("wcs")
113  if config.doApplyExternalPhotoCalib is False:
114  self.inputs.remove("photoCalib")
115 
116 
117 class ProcessCcdWithFakesConfig(PipelineTaskConfig,
118  pipelineConnections=ProcessCcdWithFakesConnections):
119  """Config for inserting fake sources
120 
121  Notes
122  -----
123  The default column names are those from the UW sims database.
124  """
125 
126  doApplyExternalPhotoCalib = pexConfig.Field(
127  dtype=bool,
128  default=False,
129  doc="Whether to apply an external photometric calibration via an "
130  "`lsst.afw.image.PhotoCalib` object. Uses the "
131  "`externalPhotoCalibName` config option to determine which "
132  "calibration to use."
133  )
134 
135  externalPhotoCalibName = pexConfig.ChoiceField(
136  doc="What type of external photo calib to use.",
137  dtype=str,
138  default="jointcal",
139  allowed={"jointcal": "Use jointcal_photoCalib",
140  "fgcm": "Use fgcm_photoCalib",
141  "fgcm_tract": "Use fgcm_tract_photoCalib"}
142  )
143 
144  doApplyExternalSkyWcs = pexConfig.Field(
145  dtype=bool,
146  default=False,
147  doc="Whether to apply an external astrometric calibration via an "
148  "`lsst.afw.geom.SkyWcs` object. Uses the "
149  "`externalSkyWcsName` config option to determine which "
150  "calibration to use."
151  )
152 
153  externalSkyWcsName = pexConfig.ChoiceField(
154  doc="What type of updated WCS calib to use.",
155  dtype=str,
156  default="jointcal",
157  allowed={"jointcal": "Use jointcal_wcs"}
158  )
159 
160  coaddName = pexConfig.Field(
161  doc="The name of the type of coadd used",
162  dtype=str,
163  default="deep",
164  )
165 
166  srcFieldsToCopy = pexConfig.ListField(
167  dtype=str,
168  default=("calib_photometry_reserved", "calib_photometry_used", "calib_astrometry_used",
169  "calib_psf_candidate", "calib_psf_used", "calib_psf_reserved"),
170  doc=("Fields to copy from the `src` catalog to the output catalog "
171  "for matching sources Any missing fields will trigger a "
172  "RuntimeError exception.")
173  )
174 
175  matchRadiusPix = pexConfig.Field(
176  dtype=float,
177  default=3,
178  doc=("Match radius for matching icSourceCat objects to sourceCat objects (pixels)"),
179  )
180 
181  calibrate = pexConfig.ConfigurableField(target=CalibrateTask,
182  doc="The calibration task to use.")
183 
184  insertFakes = pexConfig.ConfigurableField(target=InsertFakesTask,
185  doc="Configuration for the fake sources")
186 
187  def setDefaults(self):
188  super().setDefaults()
189  self.calibrate.measurement.plugins["base_PixelFlags"].masksFpAnywhere.append("FAKE")
190  self.calibrate.measurement.plugins["base_PixelFlags"].masksFpCenter.append("FAKE")
191  self.calibrate.doAstrometry = False
192  self.calibrate.doWriteMatches = False
193  self.calibrate.doPhotoCal = False
194  self.calibrate.detection.reEstimateBackground = False
195 
196 
197 class ProcessCcdWithFakesTask(PipelineTask, CmdLineTask):
198  """Insert fake objects into calexps.
199 
200  Add fake stars and galaxies to the given calexp, specified in the dataRef. Galaxy parameters are read in
201  from the specified file and then modelled using galsim. Re-runs characterize image and calibrate image to
202  give a new background estimation and measurement of the calexp.
203 
204  `ProcessFakeSourcesTask` inherits six functions from insertFakesTask that make images of the fake
205  sources and then add them to the calexp.
206 
207  `addPixCoords`
208  Use the WCS information to add the pixel coordinates of each source
209  Adds an ``x`` and ``y`` column to the catalog of fake sources.
210  `trimFakeCat`
211  Trim the fake cat to about the size of the input image.
212  `mkFakeGalsimGalaxies`
213  Use Galsim to make fake double sersic galaxies for each set of galaxy parameters in the input file.
214  `mkFakeStars`
215  Use the PSF information from the calexp to make a fake star using the magnitude information from the
216  input file.
217  `cleanCat`
218  Remove rows of the input fake catalog which have half light radius, of either the bulge or the disk,
219  that are 0.
220  `addFakeSources`
221  Add the fake sources to the calexp.
222 
223  Notes
224  -----
225  The ``calexp`` with fake souces added to it is written out as the datatype ``calexp_fakes``.
226  """
227 
228  _DefaultName = "processCcdWithFakes"
229  ConfigClass = ProcessCcdWithFakesConfig
230 
231  def __init__(self, schema=None, butler=None, **kwargs):
232  """Initalize things! This should go above in the class docstring
233  """
234 
235  super().__init__(**kwargs)
236 
237  if schema is None:
238  schema = SourceTable.makeMinimalSchema()
239  self.schema = schema
240  self.makeSubtask("insertFakes")
241  self.makeSubtask("calibrate")
242 
243  def runDataRef(self, dataRef):
244  """Read in/write out the required data products and add fake sources to the calexp.
245 
246  Parameters
247  ----------
248  dataRef : `lsst.daf.persistence.butlerSubset.ButlerDataRef`
249  Data reference defining the ccd to have fakes added to it.
250  Used to access the following data products:
251  calexp
252  jointcal_wcs
253  jointcal_photoCalib
254 
255  Notes
256  -----
257  Uses the calibration and WCS information attached to the calexp for the posistioning and calibration
258  of the sources unless the config option config.externalPhotoCalibName or config.externalSkyWcsName
259  are set then it uses the specified outputs. The config defualts for the column names in the catalog
260  of fakes are taken from the University of Washington simulations database.
261  Operates on one ccd at a time.
262  """
263  exposureIdInfo = dataRef.get("expIdInfo")
264 
265  if self.config.insertFakes.fakeType == "snapshot":
266  fakeCat = dataRef.get("fakeSourceCat").toDataFrame()
267  elif self.config.insertFakes.fakeType == "static":
268  fakeCat = dataRef.get("deepCoadd_fakeSourceCat").toDataFrame()
269  else:
270  fakeCat = Table.read(self.config.insertFakes.fakeType).to_pandas()
271 
272  calexp = dataRef.get("calexp")
273  if self.config.doApplyExternalSkyWcs:
274  self.log.info("Using external wcs from %s", self.config.externalSkyWcsName)
275  wcs = dataRef.get(self.config.externalSkyWcsName + "_wcs")
276  else:
277  wcs = calexp.getWcs()
278 
279  if self.config.doApplyExternalPhotoCalib:
280  self.log.info("Using external photocalib from %s", self.config.externalPhotoCalibName)
281  photoCalib = dataRef.get(self.config.externalPhotoCalibName + "_photoCalib")
282  else:
283  photoCalib = calexp.getPhotoCalib()
284 
285  icSourceCat = dataRef.get("icSrc", immediate=True)
286  sfdSourceCat = dataRef.get("src", immediate=True)
287 
288  resultStruct = self.run(fakeCat, calexp, wcs=wcs, photoCalib=photoCalib,
289  exposureIdInfo=exposureIdInfo, icSourceCat=icSourceCat,
290  sfdSourceCat=sfdSourceCat)
291 
292  dataRef.put(resultStruct.outputExposure, "fakes_calexp")
293  dataRef.put(resultStruct.outputCat, "fakes_src")
294  return resultStruct
295 
296  def runQuantum(self, butlerQC, inputRefs, outputRefs):
297  inputs = butlerQC.get(inputRefs)
298  if 'exposureIdInfo' not in inputs.keys():
299  expId, expBits = butlerQC.quantum.dataId.pack("visit_detector", returnMaxBits=True)
300  inputs['exposureIdInfo'] = ExposureIdInfo(expId, expBits)
301 
302  if not self.config.doApplyExternalSkyWcs:
303  inputs["wcs"] = inputs["exposure"].getWcs()
304 
305  if not self.config.doApplyExternalPhotoCalib:
306  inputs["photoCalib"] = inputs["exposure"].getPhotoCalib()
307 
308  outputs = self.run(**inputs)
309  butlerQC.put(outputs, outputRefs)
310 
311  @classmethod
312  def _makeArgumentParser(cls):
313  parser = pipeBase.ArgumentParser(name=cls._DefaultName)
314  parser.add_id_argument("--id", "fakes_calexp", help="data ID with raw CCD keys [+ tract optionally], "
315  "e.g. --id visit=12345 ccd=1,2 [tract=0]",
316  ContainerClass=PerTractCcdDataIdContainer)
317  return parser
318 
319  def run(self, fakeCat, exposure, wcs=None, photoCalib=None, exposureIdInfo=None, icSourceCat=None,
320  sfdSourceCat=None):
321  """Add fake sources to a calexp and then run detection, deblending and measurement.
322 
323  Parameters
324  ----------
325  fakeCat : `pandas.core.frame.DataFrame`
326  The catalog of fake sources to add to the exposure
327  exposure : `lsst.afw.image.exposure.exposure.ExposureF`
328  The exposure to add the fake sources to
329  wcs : `lsst.afw.geom.SkyWcs`
330  WCS to use to add fake sources
331  photoCalib : `lsst.afw.image.photoCalib.PhotoCalib`
332  Photometric calibration to be used to calibrate the fake sources
333  exposureIdInfo : `lsst.obs.base.ExposureIdInfo`
334  icSourceCat : `lsst.afw.table.SourceCatalog`
335  Default : None
336  Catalog to take the information about which sources were used for calibration from.
337  sfdSourceCat : `lsst.afw.table.SourceCatalog`
338  Default : None
339  Catalog produced by singleFrameDriver, needed to copy some calibration flags from.
340 
341  Returns
342  -------
343  resultStruct : `lsst.pipe.base.struct.Struct`
344  contains : outputExposure : `lsst.afw.image.exposure.exposure.ExposureF`
345  outputCat : `lsst.afw.table.source.source.SourceCatalog`
346 
347  Notes
348  -----
349  Adds pixel coordinates for each source to the fakeCat and removes objects with bulge or disk half
350  light radius = 0 (if ``config.cleanCat = True``). These columns are called ``x`` and ``y`` and are in
351  pixels.
352 
353  Adds the ``Fake`` mask plane to the exposure which is then set by `addFakeSources` to mark where fake
354  sources have been added. Uses the information in the ``fakeCat`` to make fake galaxies (using galsim)
355  and fake stars, using the PSF models from the PSF information for the calexp. These are then added to
356  the calexp and the calexp with fakes included returned.
357 
358  The galsim galaxies are made using a double sersic profile, one for the bulge and one for the disk,
359  this is then convolved with the PSF at that point.
360 
361  If exposureIdInfo is not provided then the SourceCatalog IDs will not be globally unique.
362  """
363 
364  if wcs is None:
365  wcs = exposure.getWcs()
366 
367  if photoCalib is None:
368  photoCalib = exposure.getPhotoCalib()
369 
370  self.insertFakes.run(fakeCat, exposure, wcs, photoCalib)
371 
372  # detect, deblend and measure sources
373  if exposureIdInfo is None:
374  exposureIdInfo = ExposureIdInfo()
375  returnedStruct = self.calibrate.run(exposure, exposureIdInfo=exposureIdInfo)
376  sourceCat = returnedStruct.sourceCat
377 
378  sourceCat = self.copyCalibrationFields(sfdSourceCat, sourceCat, self.config.srcFieldsToCopy)
379 
380  resultStruct = pipeBase.Struct(outputExposure=exposure, outputCat=sourceCat)
381  return resultStruct
382 
383  def copyCalibrationFields(self, calibCat, sourceCat, fieldsToCopy):
384  """Match sources in calibCat and sourceCat and copy the specified fields
385 
386  Parameters
387  ----------
388  calibCat : `lsst.afw.table.SourceCatalog`
389  Catalog from which to copy fields.
390  sourceCat : `lsst.afw.table.SourceCatalog`
391  Catalog to which to copy fields.
392  fieldsToCopy : `lsst.pex.config.listField.List`
393  Fields to copy from calibCat to SoourceCat.
394 
395  Returns
396  -------
397  newCat : `lsst.afw.table.SourceCatalog`
398  Catalog which includes the copied fields.
399 
400  The fields copied are those specified by `fieldsToCopy` that actually exist
401  in the schema of `calibCat`.
402 
403  This version was based on and adapted from the one in calibrateTask.
404  """
405 
406  # Make a new SourceCatalog with the data from sourceCat so that we can add the new columns to it
407  sourceSchemaMapper = afwTable.SchemaMapper(sourceCat.schema)
408  sourceSchemaMapper.addMinimalSchema(sourceCat.schema, True)
409 
410  calibSchemaMapper = afwTable.SchemaMapper(calibCat.schema, sourceCat.schema)
411 
412  # Add the desired columns from the option fieldsToCopy
413  missingFieldNames = []
414  for fieldName in fieldsToCopy:
415  if fieldName in calibCat.schema:
416  schemaItem = calibCat.schema.find(fieldName)
417  calibSchemaMapper.editOutputSchema().addField(schemaItem.getField())
418  schema = calibSchemaMapper.editOutputSchema()
419  calibSchemaMapper.addMapping(schemaItem.getKey(), schema.find(fieldName).getField())
420  else:
421  missingFieldNames.append(fieldName)
422  if missingFieldNames:
423  raise RuntimeError(f"calibCat is missing fields {missingFieldNames} specified in "
424  "fieldsToCopy")
425 
426  if "calib_detected" not in calibSchemaMapper.getOutputSchema():
427  self.calibSourceKey = calibSchemaMapper.addOutputField(afwTable.Field["Flag"]("calib_detected",
428  "Source was detected as an icSource"))
429  else:
430  self.calibSourceKey = None
431 
432  schema = calibSchemaMapper.getOutputSchema()
433  newCat = afwTable.SourceCatalog(schema)
434  newCat.reserve(len(sourceCat))
435  newCat.extend(sourceCat, sourceSchemaMapper)
436 
437  # Set the aliases so it doesn't complain.
438  for k, v in sourceCat.schema.getAliasMap().items():
439  newCat.schema.getAliasMap().set(k, v)
440 
441  select = newCat["deblend_nChild"] == 0
442  matches = afwTable.matchXy(newCat[select], calibCat, self.config.matchRadiusPix)
443  # Check that no sourceCat sources are listed twice (we already know
444  # that each match has a unique calibCat source ID, due to using
445  # that ID as the key in bestMatches)
446  numMatches = len(matches)
447  numUniqueSources = len(set(m[1].getId() for m in matches))
448  if numUniqueSources != numMatches:
449  self.log.warning("%d calibCat sources matched only %d sourceCat sources", numMatches,
450  numUniqueSources)
451 
452  self.log.info("Copying flags from calibCat to sourceCat for %s sources", numMatches)
453 
454  # For each match: set the calibSourceKey flag and copy the desired
455  # fields
456  for src, calibSrc, d in matches:
457  if self.calibSourceKey:
458  src.setFlag(self.calibSourceKey, True)
459  # src.assign copies the footprint from calibSrc, which we don't want
460  # (DM-407)
461  # so set calibSrc's footprint to src's footprint before src.assign,
462  # then restore it
463  calibSrcFootprint = calibSrc.getFootprint()
464  try:
465  calibSrc.setFootprint(src.getFootprint())
466  src.assign(calibSrc, calibSchemaMapper)
467  finally:
468  calibSrc.setFootprint(calibSrcFootprint)
469 
470  return newCat
471 
472 
473 class ProcessCcdWithVariableFakesConnections(ProcessCcdWithFakesConnections):
474  ccdVisitFakeMagnitudes = cT.Output(
475  doc="Catalog of fakes with magnitudes scattered for this ccdVisit.",
476  name="{fakesType}ccdVisitFakeMagnitudes",
477  storageClass="DataFrame",
478  dimensions=("instrument", "visit", "detector"),
479  )
480 
481 
482 class ProcessCcdWithVariableFakesConfig(ProcessCcdWithFakesConfig,
483  pipelineConnections=ProcessCcdWithVariableFakesConnections):
484  scatterSize = pexConfig.RangeField(
485  dtype=float,
486  default=0.4,
487  min=0,
488  max=100,
489  doc="Amount of scatter to add to the visit magnitude for variable "
490  "sources."
491  )
492 
493 
494 class ProcessCcdWithVariableFakesTask(ProcessCcdWithFakesTask):
495  """As ProcessCcdWithFakes except add variablity to the fakes catalog
496  magnitude in the observed band for this ccdVisit.
497 
498  Additionally, write out the modified magnitudes to the Butler.
499  """
500 
501  _DefaultName = "processCcdWithVariableFakes"
502  ConfigClass = ProcessCcdWithVariableFakesConfig
503 
504  def run(self, fakeCat, exposure, wcs=None, photoCalib=None, exposureIdInfo=None, icSourceCat=None,
505  sfdSourceCat=None):
506  """Add fake sources to a calexp and then run detection, deblending and measurement.
507 
508  Parameters
509  ----------
510  fakeCat : `pandas.core.frame.DataFrame`
511  The catalog of fake sources to add to the exposure
512  exposure : `lsst.afw.image.exposure.exposure.ExposureF`
513  The exposure to add the fake sources to
514  wcs : `lsst.afw.geom.SkyWcs`
515  WCS to use to add fake sources
516  photoCalib : `lsst.afw.image.photoCalib.PhotoCalib`
517  Photometric calibration to be used to calibrate the fake sources
518  exposureIdInfo : `lsst.obs.base.ExposureIdInfo`
519  icSourceCat : `lsst.afw.table.SourceCatalog`
520  Default : None
521  Catalog to take the information about which sources were used for calibration from.
522  sfdSourceCat : `lsst.afw.table.SourceCatalog`
523  Default : None
524  Catalog produced by singleFrameDriver, needed to copy some calibration flags from.
525 
526  Returns
527  -------
528  resultStruct : `lsst.pipe.base.struct.Struct`
529  Results Strcut containing:
530 
531  - outputExposure : Exposure with added fakes
532  (`lsst.afw.image.exposure.exposure.ExposureF`)
533  - outputCat : Catalog with detected fakes
534  (`lsst.afw.table.source.source.SourceCatalog`)
535  - ccdVisitFakeMagnitudes : Magnitudes that these fakes were
536  inserted with after being scattered (`pandas.DataFrame`)
537 
538  Notes
539  -----
540  Adds pixel coordinates for each source to the fakeCat and removes objects with bulge or disk half
541  light radius = 0 (if ``config.cleanCat = True``). These columns are called ``x`` and ``y`` and are in
542  pixels.
543 
544  Adds the ``Fake`` mask plane to the exposure which is then set by `addFakeSources` to mark where fake
545  sources have been added. Uses the information in the ``fakeCat`` to make fake galaxies (using galsim)
546  and fake stars, using the PSF models from the PSF information for the calexp. These are then added to
547  the calexp and the calexp with fakes included returned.
548 
549  The galsim galaxies are made using a double sersic profile, one for the bulge and one for the disk,
550  this is then convolved with the PSF at that point.
551 
552  If exposureIdInfo is not provided then the SourceCatalog IDs will not be globally unique.
553  """
554  if wcs is None:
555  wcs = exposure.getWcs()
556 
557  if photoCalib is None:
558  photoCalib = exposure.getPhotoCalib()
559 
560  if exposureIdInfo is None:
561  exposureIdInfo = ExposureIdInfo()
562 
563  band = exposure.getFilterLabel().bandLabel
564  ccdVisitMagnitudes = self.addVariablity(fakeCat, band, exposure, photoCalib, exposureIdInfo)
565 
566  self.insertFakes.run(fakeCat, exposure, wcs, photoCalib)
567 
568  # detect, deblend and measure sources
569  returnedStruct = self.calibrate.run(exposure, exposureIdInfo=exposureIdInfo)
570  sourceCat = returnedStruct.sourceCat
571 
572  sourceCat = self.copyCalibrationFields(sfdSourceCat, sourceCat, self.config.srcFieldsToCopy)
573 
574  resultStruct = pipeBase.Struct(outputExposure=exposure,
575  outputCat=sourceCat,
576  ccdVisitFakeMagnitudes=ccdVisitMagnitudes)
577  return resultStruct
578 
579  def addVariablity(self, fakeCat, band, exposure, photoCalib, exposureIdInfo):
580  """Add scatter to the fake catalog visit magnitudes.
581 
582  Currently just adds a simple Gaussian scatter around the static fake
583  magnitude. This function could be modified to return any number of
584  fake variability.
585 
586  Parameters
587  ----------
588  fakeCat : `pandas.DataFrame`
589  Catalog of fakes to modify magnitudes of.
590  band : `str`
591  Current observing band to modify.
592  exposure : `lsst.afw.image.ExposureF`
593  Exposure fakes will be added to.
594  photoCalib : `lsst.afw.image.PhotoCalib`
595  Photometric calibration object of ``exposure``.
596  exposureIdInfo : `lsst.obs.base.ExposureIdInfo`
597  Exposure id information and metadata.
598 
599  Returns
600  -------
601  dataFrame : `pandas.DataFrame`
602  DataFrame containing the values of the magnitudes to that will
603  be inserted into this ccdVisit.
604  """
605  expId = exposureIdInfo.expId
606  rng = np.random.default_rng(expId)
607  magScatter = rng.normal(loc=0,
608  scale=self.config.scatterSize,
609  size=len(fakeCat))
610  visitMagnitudes = fakeCat[self.insertFakes.config.mag_col % band] + magScatter
611  fakeCat.loc[:, self.insertFakes.config.mag_col % band] = visitMagnitudes
612  return pd.DataFrame(data={"variableMag": visitMagnitudes})
std::vector< SchemaItem< Flag > > * items
A mapping between the keys of two Schemas, used to copy data between them.
Definition: SchemaMapper.h:21
daf::base::PropertySet * set
Definition: fits.cc:912
SourceMatchVector matchXy(SourceCatalog const &cat1, SourceCatalog const &cat2, double radius, MatchControl const &mc=MatchControl())
Compute all tuples (s1,s2,d) where s1 belings to cat1, s2 belongs to cat2 and d, the distance between...
Definition: Match.cc:305
def run(self, coaddExposures, bbox, wcs)
Definition: getTemplate.py:603
A description of a field in a table.
Definition: Field.h:24