23Insert fake sources into calexps
25from astropy.table
import Table
32from .insertFakes
import InsertFakesTask
35from lsst.obs.base
import ExposureIdInfo
36from lsst.pipe.base import PipelineTask, PipelineTaskConfig, CmdLineTask, PipelineTaskConnections
37import lsst.pipe.base.connectionTypes
as cT
42__all__ = [
"ProcessCcdWithFakesConfig",
"ProcessCcdWithFakesTask",
43 "ProcessCcdWithVariableFakesConfig",
"ProcessCcdWithVariableFakesTask"]
47 dimensions=(
"instrument",
"visit",
"detector"),
48 defaultTemplates={
"coaddName":
"deep",
49 "wcsName":
"jointcal",
50 "photoCalibName":
"jointcal",
51 "fakesType":
"fakes_"}):
53 doc=
"Input definition of geometry/bbox and projection/wcs for "
54 "template exposures. Needed to test which tract to generate ",
55 name=BaseSkyMap.SKYMAP_DATASET_TYPE_NAME,
56 dimensions=(
"skymap",),
57 storageClass=
"SkyMap",
61 doc=
"Exposure into which fakes are to be added.",
63 storageClass=
"ExposureF",
64 dimensions=(
"instrument",
"visit",
"detector")
68 doc=
"Set of catalogs of fake sources to draw inputs from. We "
69 "concatenate the tract catalogs for detectorVisits that cover "
71 name=
"{fakesType}fakeSourceCat",
72 storageClass=
"DataFrame",
73 dimensions=(
"tract",
"skymap"),
78 externalSkyWcsTractCatalog = cT.Input(
79 doc=(
"Per-tract, per-visit wcs calibrations. These catalogs use the detector "
80 "id for the catalog id, sorted on id for fast lookup."),
81 name=
"{wcsName}SkyWcsCatalog",
82 storageClass=
"ExposureCatalog",
83 dimensions=(
"instrument",
"visit",
"tract",
"skymap"),
88 externalSkyWcsGlobalCatalog = cT.Input(
89 doc=(
"Per-visit wcs calibrations computed globally (with no tract information). "
90 "These catalogs use the detector id for the catalog id, sorted on id for "
92 name=
"finalVisitSummary",
93 storageClass=
"ExposureCatalog",
94 dimensions=(
"instrument",
"visit"),
97 externalPhotoCalibTractCatalog = cT.Input(
98 doc=(
"Per-tract, per-visit photometric calibrations. These catalogs use the "
99 "detector id for the catalog id, sorted on id for fast lookup."),
100 name=
"{photoCalibName}PhotoCalibCatalog",
101 storageClass=
"ExposureCatalog",
102 dimensions=(
"instrument",
"visit",
"tract"),
107 externalPhotoCalibGlobalCatalog = cT.Input(
108 doc=(
"Per-visit photometric calibrations. These catalogs use the "
109 "detector id for the catalog id, sorted on id for fast lookup."),
110 name=
"finalVisitSummary",
111 storageClass=
"ExposureCatalog",
112 dimensions=(
"instrument",
"visit"),
115 icSourceCat = cT.Input(
116 doc=
"Catalog of calibration sources",
118 storageClass=
"SourceCatalog",
119 dimensions=(
"instrument",
"visit",
"detector")
122 sfdSourceCat = cT.Input(
123 doc=
"Catalog of calibration sources",
125 storageClass=
"SourceCatalog",
126 dimensions=(
"instrument",
"visit",
"detector")
129 outputExposure = cT.Output(
130 doc=
"Exposure with fake sources added.",
131 name=
"{fakesType}calexp",
132 storageClass=
"ExposureF",
133 dimensions=(
"instrument",
"visit",
"detector")
136 outputCat = cT.Output(
137 doc=
"Source catalog produced in calibrate task with fakes also measured.",
138 name=
"{fakesType}src",
139 storageClass=
"SourceCatalog",
140 dimensions=(
"instrument",
"visit",
"detector"),
143 def __init__(self, *, config=None):
144 super().__init__(config=config)
146 if not config.doApplyExternalGlobalPhotoCalib:
147 self.inputs.remove(
"externalPhotoCalibGlobalCatalog")
148 if not config.doApplyExternalTractPhotoCalib:
149 self.inputs.remove(
"externalPhotoCalibTractCatalog")
151 if not config.doApplyExternalGlobalSkyWcs:
152 self.inputs.remove(
"externalSkyWcsGlobalCatalog")
153 if not config.doApplyExternalTractSkyWcs:
154 self.inputs.remove(
"externalSkyWcsTractCatalog")
157class ProcessCcdWithFakesConfig(PipelineTaskConfig,
158 pipelineConnections=ProcessCcdWithFakesConnections):
159 """Config for inserting fake sources
163 The default column names are those from the UW sims database.
166 doApplyExternalGlobalPhotoCalib = pexConfig.Field(
169 doc=
"Whether to apply an external photometric calibration via an "
170 "`lsst.afw.image.PhotoCalib` object. Uses the "
171 "`externalPhotoCalibName` config option to determine which "
172 "calibration to use. Uses a global calibration."
175 doApplyExternalTractPhotoCalib = pexConfig.Field(
178 doc=
"Whether to apply an external photometric calibration via an "
179 "`lsst.afw.image.PhotoCalib` object. Uses the "
180 "`externalPhotoCalibName` config option to determine which "
181 "calibration to use. Uses a per tract calibration."
184 externalPhotoCalibName = pexConfig.ChoiceField(
185 doc=
"What type of external photo calib to use.",
188 allowed={
"jointcal":
"Use jointcal_photoCalib",
189 "fgcm":
"Use fgcm_photoCalib",
190 "fgcm_tract":
"Use fgcm_tract_photoCalib"}
193 doApplyExternalGlobalSkyWcs = pexConfig.Field(
196 doc=
"Whether to apply an external astrometric calibration via an "
197 "`lsst.afw.geom.SkyWcs` object. Uses the "
198 "`externalSkyWcsName` config option to determine which "
199 "calibration to use. Uses a global calibration."
202 doApplyExternalTractSkyWcs = pexConfig.Field(
205 doc=
"Whether to apply an external astrometric calibration via an "
206 "`lsst.afw.geom.SkyWcs` object. Uses the "
207 "`externalSkyWcsName` config option to determine which "
208 "calibration to use. Uses a per tract calibration."
211 externalSkyWcsName = pexConfig.ChoiceField(
212 doc=
"What type of updated WCS calib to use.",
215 allowed={
"jointcal":
"Use jointcal_wcs"}
218 coaddName = pexConfig.Field(
219 doc=
"The name of the type of coadd used",
224 srcFieldsToCopy = pexConfig.ListField(
226 default=(
"calib_photometry_reserved",
"calib_photometry_used",
"calib_astrometry_used",
227 "calib_psf_candidate",
"calib_psf_used",
"calib_psf_reserved"),
228 doc=(
"Fields to copy from the `src` catalog to the output catalog "
229 "for matching sources Any missing fields will trigger a "
230 "RuntimeError exception.")
233 matchRadiusPix = pexConfig.Field(
236 doc=(
"Match radius for matching icSourceCat objects to sourceCat objects (pixels)"),
239 doMatchVisit = pexConfig.Field(
242 doc=
"Match visit to trim the fakeCat"
245 calibrate = pexConfig.ConfigurableField(target=CalibrateTask,
246 doc=
"The calibration task to use.")
248 insertFakes = pexConfig.ConfigurableField(target=InsertFakesTask,
249 doc=
"Configuration for the fake sources")
251 def setDefaults(self):
252 super().setDefaults()
253 self.calibrate.measurement.plugins[
"base_PixelFlags"].masksFpAnywhere.append(
"FAKE")
254 self.calibrate.measurement.plugins[
"base_PixelFlags"].masksFpCenter.append(
"FAKE")
255 self.calibrate.doAstrometry =
False
256 self.calibrate.doWriteMatches =
False
257 self.calibrate.doPhotoCal =
False
258 self.calibrate.doComputeSummaryStats =
False
259 self.calibrate.detection.reEstimateBackground =
False
262class ProcessCcdWithFakesTask(PipelineTask, CmdLineTask):
263 """Insert fake objects into calexps.
265 Add fake stars and galaxies to the given calexp, specified
in the dataRef. Galaxy parameters are read
in
266 from the specified file
and then modelled using galsim. Re-runs characterize image
and calibrate image to
267 give a new background estimation
and measurement of the calexp.
269 `ProcessFakeSourcesTask` inherits six functions
from insertFakesTask that make images of the fake
270 sources
and then add them to the calexp.
273 Use the WCS information to add the pixel coordinates of each source
274 Adds an ``x``
and ``y`` column to the catalog of fake sources.
276 Trim the fake cat to about the size of the input image.
277 `mkFakeGalsimGalaxies`
278 Use Galsim to make fake double sersic galaxies
for each set of galaxy parameters
in the input file.
280 Use the PSF information
from the calexp to make a fake star using the magnitude information
from the
283 Remove rows of the input fake catalog which have half light radius, of either the bulge
or the disk,
286 Add the fake sources to the calexp.
290 The ``calexp``
with fake souces added to it
is written out
as the datatype ``calexp_fakes``.
293 _DefaultName = "processCcdWithFakes"
294 ConfigClass = ProcessCcdWithFakesConfig
296 def __init__(self, schema=None, butler=None, **kwargs):
297 """Initalize things! This should go above in the class docstring
300 super().__init__(**kwargs)
303 schema = SourceTable.makeMinimalSchema()
305 self.makeSubtask(
"insertFakes")
306 self.makeSubtask(
"calibrate")
308 def runDataRef(self, dataRef):
309 """Read in/write out the required data products and add fake sources to the calexp.
314 Data reference defining the ccd to have fakes added to it.
315 Used to access the following data products:
322 Uses the calibration and WCS information attached to the calexp
for the posistioning
and calibration
323 of the sources unless the config option config.externalPhotoCalibName
or config.externalSkyWcsName
324 are set then it uses the specified outputs. The config defualts
for the column names
in the catalog
325 of fakes are taken
from the University of Washington simulations database.
326 Operates on one ccd at a time.
328 exposureIdInfo = dataRef.get("expIdInfo")
330 if self.config.insertFakes.fakeType ==
"snapshot":
331 fakeCat = dataRef.get(
"fakeSourceCat").toDataFrame()
332 elif self.config.insertFakes.fakeType ==
"static":
333 fakeCat = dataRef.get(
"deepCoadd_fakeSourceCat").toDataFrame()
335 fakeCat = Table.read(self.config.insertFakes.fakeType).to_pandas()
337 calexp = dataRef.get(
"calexp")
338 if self.config.doApplyExternalGlobalSkyWcs
or self.config.doApplyExternalTractSkyWcs:
339 self.log.info(
"Using external wcs from %s", self.config.externalSkyWcsName)
340 wcs = dataRef.get(self.config.externalSkyWcsName +
"_wcs")
342 wcs = calexp.getWcs()
344 if self.config.doApplyExternalGlobalPhotoCalib
or self.config.doApplyExternalTractPhotoCalib:
345 self.log.info(
"Using external photocalib from %s", self.config.externalPhotoCalibName)
346 photoCalib = dataRef.get(self.config.externalPhotoCalibName +
"_photoCalib")
348 photoCalib = calexp.getPhotoCalib()
350 icSourceCat = dataRef.get(
"icSrc", immediate=
True)
351 sfdSourceCat = dataRef.get(
"src", immediate=
True)
353 resultStruct = self.run(fakeCat, calexp, wcs=wcs, photoCalib=photoCalib,
354 exposureIdInfo=exposureIdInfo, icSourceCat=icSourceCat,
355 sfdSourceCat=sfdSourceCat)
357 dataRef.put(resultStruct.outputExposure,
"fakes_calexp")
358 dataRef.put(resultStruct.outputCat,
"fakes_src")
361 def runQuantum(self, butlerQC, inputRefs, outputRefs):
362 inputs = butlerQC.get(inputRefs)
363 detectorId = inputs[
"exposure"].getInfo().getDetector().getId()
365 if 'exposureIdInfo' not in inputs.keys():
366 expId, expBits = butlerQC.quantum.dataId.pack(
"visit_detector", returnMaxBits=
True)
367 inputs[
'exposureIdInfo'] = ExposureIdInfo(expId, expBits)
369 expWcs = inputs[
"exposure"].getWcs()
370 tractId = inputs[
"skyMap"].findTract(
371 expWcs.pixelToSky(inputs[
"exposure"].getBBox().getCenter())).tract_id
372 if not self.config.doApplyExternalGlobalSkyWcs
and not self.config.doApplyExternalTractSkyWcs:
373 inputs[
"wcs"] = expWcs
374 elif self.config.doApplyExternalGlobalSkyWcs:
375 externalSkyWcsCatalog = inputs[
"externalSkyWcsGlobalCatalog"]
376 row = externalSkyWcsCatalog.find(detectorId)
377 inputs[
"wcs"] = row.getWcs()
378 elif self.config.doApplyExternalTractSkyWcs:
379 externalSkyWcsCatalogList = inputs[
"externalSkyWcsTractCatalog"]
380 externalSkyWcsCatalog =
None
381 for externalSkyWcsCatalogRef
in externalSkyWcsCatalogList:
382 if externalSkyWcsCatalogRef.dataId[
"tract"] == tractId:
383 externalSkyWcsCatalog = externalSkyWcsCatalogRef.get(
384 datasetType=self.config.connections.externalSkyWcsTractCatalog)
386 if externalSkyWcsCatalog
is None:
387 usedTract = externalSkyWcsCatalogList[-1].dataId[
"tract"]
389 f
"Warning, external SkyWcs for tract {tractId} not found. Using tract {usedTract} "
391 externalSkyWcsCatalog = externalSkyWcsCatalogList[-1].get(
392 datasetType=self.config.connections.externalSkyWcsTractCatalog)
393 row = externalSkyWcsCatalog.find(detectorId)
394 inputs[
"wcs"] = row.getWcs()
396 if not self.config.doApplyExternalGlobalPhotoCalib
and not self.config.doApplyExternalTractPhotoCalib:
397 inputs[
"photoCalib"] = inputs[
"exposure"].getPhotoCalib()
398 elif self.config.doApplyExternalGlobalPhotoCalib:
399 externalPhotoCalibCatalog = inputs[
"externalPhotoCalibGlobalCatalog"]
400 row = externalPhotoCalibCatalog.find(detectorId)
401 inputs[
"photoCalib"] = row.getPhotoCalib()
402 elif self.config.doApplyExternalTractPhotoCalib:
403 externalPhotoCalibCatalogList = inputs[
"externalPhotoCalibTractCatalog"]
404 externalPhotoCalibCatalog =
None
405 for externalPhotoCalibCatalogRef
in externalPhotoCalibCatalogList:
406 if externalPhotoCalibCatalogRef.dataId[
"tract"] == tractId:
407 externalPhotoCalibCatalog = externalPhotoCalibCatalogRef.get(
408 datasetType=self.config.connections.externalPhotoCalibTractCatalog)
410 if externalPhotoCalibCatalog
is None:
411 usedTract = externalPhotoCalibCatalogList[-1].dataId[
"tract"]
413 f
"Warning, external PhotoCalib for tract {tractId} not found. Using tract {usedTract} "
415 externalPhotoCalibCatalog = externalPhotoCalibCatalogList[-1].get(
416 datasetType=self.config.connections.externalPhotoCalibTractCatalog)
417 row = externalPhotoCalibCatalog.find(detectorId)
418 inputs[
"photoCalib"] = row.getPhotoCalib()
420 outputs = self.run(**inputs)
421 butlerQC.put(outputs, outputRefs)
424 def _makeArgumentParser(cls):
425 parser = pipeBase.ArgumentParser(name=cls._DefaultName)
426 parser.add_id_argument(
"--id",
"fakes_calexp", help=
"data ID with raw CCD keys [+ tract optionally], "
427 "e.g. --id visit=12345 ccd=1,2 [tract=0]",
428 ContainerClass=PerTractCcdDataIdContainer)
431 def run(self, fakeCats, exposure, skyMap, wcs=None, photoCalib=None, exposureIdInfo=None,
432 icSourceCat=None, sfdSourceCat=None, externalSkyWcsGlobalCatalog=None,
433 externalSkyWcsTractCatalog=None, externalPhotoCalibGlobalCatalog=None,
434 externalPhotoCalibTractCatalog=None):
435 """Add fake sources to a calexp and then run detection, deblending and measurement.
439 fakeCats : `list` of `lsst.daf.butler.DeferredDatasetHandle`
440 Set of tract level fake catalogs that potentially cover
442 exposure : `lsst.afw.image.exposure.exposure.ExposureF`
443 The exposure to add the fake sources to
444 skyMap : `lsst.skymap.SkyMap`
445 SkyMap defining the tracts and patches the fakes are stored over.
447 WCS to use to add fake sources
448 photoCalib : `lsst.afw.image.photoCalib.PhotoCalib`
449 Photometric calibration to be used to calibrate the fake sources
450 exposureIdInfo : `lsst.obs.base.ExposureIdInfo`
453 Catalog to take the information about which sources were used
for calibration
from.
456 Catalog produced by singleFrameDriver, needed to copy some calibration flags
from.
460 resultStruct : `lsst.pipe.base.struct.Struct`
461 contains : outputExposure : `lsst.afw.image.exposure.exposure.ExposureF`
462 outputCat : `lsst.afw.table.source.source.SourceCatalog`
466 Adds pixel coordinates
for each source to the fakeCat
and removes objects
with bulge
or disk half
467 light radius = 0 (
if ``config.cleanCat =
True``). These columns are called ``x``
and ``y``
and are
in
470 Adds the ``Fake`` mask plane to the exposure which
is then set by `addFakeSources` to mark where fake
471 sources have been added. Uses the information
in the ``fakeCat`` to make fake galaxies (using galsim)
472 and fake stars, using the PSF models
from the PSF information
for the calexp. These are then added to
473 the calexp
and the calexp
with fakes included returned.
475 The galsim galaxies are made using a double sersic profile, one
for the bulge
and one
for the disk,
476 this
is then convolved
with the PSF at that point.
478 If exposureIdInfo
is not provided then the SourceCatalog IDs will
not be globally unique.
480 fakeCat = self.composeFakeCat(fakeCats, skyMap)
483 wcs = exposure.getWcs()
485 if photoCalib
is None:
486 photoCalib = exposure.getPhotoCalib()
488 if self.config.doMatchVisit:
489 fakeCat = self.getVisitMatchedFakeCat(fakeCat, exposure)
491 self.insertFakes.run(fakeCat, exposure, wcs, photoCalib)
494 if exposureIdInfo
is None:
495 exposureIdInfo = ExposureIdInfo()
496 returnedStruct = self.calibrate.run(exposure, exposureIdInfo=exposureIdInfo)
497 sourceCat = returnedStruct.sourceCat
499 sourceCat = self.copyCalibrationFields(sfdSourceCat, sourceCat, self.config.srcFieldsToCopy)
501 resultStruct = pipeBase.Struct(outputExposure=exposure, outputCat=sourceCat)
504 def composeFakeCat(self, fakeCats, skyMap):
505 """Concatenate the fakeCats from tracts that may cover the exposure.
509 fakeCats : `list` of `lst.daf.butler.DeferredDatasetHandle`
510 Set of fake cats to concatenate.
511 skyMap : `lsst.skymap.SkyMap`
512 SkyMap defining the geometry of the tracts and patches.
516 combinedFakeCat : `pandas.DataFrame`
517 All fakes that cover the inner polygon of the tracts
in this
520 if len(fakeCats) == 1:
521 return fakeCats[0].get(
522 datasetType=self.config.connections.fakeCats)
524 for fakeCatRef
in fakeCats:
525 cat = fakeCatRef.get(
526 datasetType=self.config.connections.fakeCats)
527 tractId = fakeCatRef.dataId[
"tract"]
529 outputCat.append(cat[
530 skyMap.findTractIdArray(cat[self.config.insertFakes.ra_col],
531 cat[self.config.insertFakes.dec_col],
535 return pd.concat(outputCat)
537 def getVisitMatchedFakeCat(self, fakeCat, exposure):
538 """Trim the fakeCat to select particular visit
542 fakeCat : `pandas.core.frame.DataFrame`
543 The catalog of fake sources to add to the exposure
544 exposure : `lsst.afw.image.exposure.exposure.ExposureF`
545 The exposure to add the fake sources to
549 movingFakeCat : `pandas.DataFrame`
550 All fakes that belong to the visit
552 selected = exposure.getInfo().getVisitInfo().getId() == fakeCat["visit"]
554 return fakeCat[selected]
556 def copyCalibrationFields(self, calibCat, sourceCat, fieldsToCopy):
557 """Match sources in calibCat and sourceCat and copy the specified fields
562 Catalog from which to copy fields.
564 Catalog to which to copy fields.
566 Fields to copy
from calibCat to SoourceCat.
571 Catalog which includes the copied fields.
573 The fields copied are those specified by `fieldsToCopy` that actually exist
574 in the schema of `calibCat`.
576 This version was based on
and adapted
from the one
in calibrateTask.
580 sourceSchemaMapper = afwTable.SchemaMapper(sourceCat.schema)
581 sourceSchemaMapper.addMinimalSchema(sourceCat.schema,
True)
583 calibSchemaMapper = afwTable.SchemaMapper(calibCat.schema, sourceCat.schema)
586 missingFieldNames = []
587 for fieldName
in fieldsToCopy:
588 if fieldName
in calibCat.schema:
589 schemaItem = calibCat.schema.find(fieldName)
590 calibSchemaMapper.editOutputSchema().addField(schemaItem.getField())
591 schema = calibSchemaMapper.editOutputSchema()
592 calibSchemaMapper.addMapping(schemaItem.getKey(), schema.find(fieldName).getField())
594 missingFieldNames.append(fieldName)
595 if missingFieldNames:
596 raise RuntimeError(f
"calibCat is missing fields {missingFieldNames} specified in "
599 if "calib_detected" not in calibSchemaMapper.getOutputSchema():
600 self.calibSourceKey = calibSchemaMapper.addOutputField(afwTable.Field[
"Flag"](
"calib_detected",
601 "Source was detected as an icSource"))
603 self.calibSourceKey =
None
605 schema = calibSchemaMapper.getOutputSchema()
606 newCat = afwTable.SourceCatalog(schema)
607 newCat.reserve(len(sourceCat))
608 newCat.extend(sourceCat, sourceSchemaMapper)
611 for k, v
in sourceCat.schema.getAliasMap().items():
612 newCat.schema.getAliasMap().set(k, v)
614 select = newCat[
"deblend_nChild"] == 0
615 matches = afwTable.matchXy(newCat[select], calibCat, self.config.matchRadiusPix)
619 numMatches = len(matches)
620 numUniqueSources = len(set(m[1].getId()
for m
in matches))
621 if numUniqueSources != numMatches:
622 self.log.warning(
"%d calibCat sources matched only %d sourceCat sources", numMatches,
625 self.log.info(
"Copying flags from calibCat to sourceCat for %s sources", numMatches)
629 for src, calibSrc, d
in matches:
630 if self.calibSourceKey:
631 src.setFlag(self.calibSourceKey,
True)
636 calibSrcFootprint = calibSrc.getFootprint()
638 calibSrc.setFootprint(src.getFootprint())
639 src.assign(calibSrc, calibSchemaMapper)
641 calibSrc.setFootprint(calibSrcFootprint)
647 ccdVisitFakeMagnitudes = cT.Output(
648 doc=
"Catalog of fakes with magnitudes scattered for this ccdVisit.",
649 name=
"{fakesType}ccdVisitFakeMagnitudes",
650 storageClass=
"DataFrame",
651 dimensions=(
"instrument",
"visit",
"detector"),
655class ProcessCcdWithVariableFakesConfig(ProcessCcdWithFakesConfig,
656 pipelineConnections=ProcessCcdWithVariableFakesConnections):
657 scatterSize = pexConfig.RangeField(
662 doc=
"Amount of scatter to add to the visit magnitude for variable "
667class ProcessCcdWithVariableFakesTask(ProcessCcdWithFakesTask):
668 """As ProcessCcdWithFakes except add variablity to the fakes catalog
669 magnitude in the observed band
for this ccdVisit.
671 Additionally, write out the modified magnitudes to the Butler.
674 _DefaultName = "processCcdWithVariableFakes"
675 ConfigClass = ProcessCcdWithVariableFakesConfig
677 def run(self, fakeCats, exposure, skyMap, wcs=None, photoCalib=None, exposureIdInfo=None,
678 icSourceCat=None, sfdSourceCat=None):
679 """Add fake sources to a calexp and then run detection, deblending and measurement.
683 fakeCat : `pandas.core.frame.DataFrame`
684 The catalog of fake sources to add to the exposure
685 exposure : `lsst.afw.image.exposure.exposure.ExposureF`
686 The exposure to add the fake sources to
687 skyMap : `lsst.skymap.SkyMap`
688 SkyMap defining the tracts and patches the fakes are stored over.
690 WCS to use to add fake sources
691 photoCalib : `lsst.afw.image.photoCalib.PhotoCalib`
692 Photometric calibration to be used to calibrate the fake sources
693 exposureIdInfo : `lsst.obs.base.ExposureIdInfo`
696 Catalog to take the information about which sources were used
for calibration
from.
699 Catalog produced by singleFrameDriver, needed to copy some calibration flags
from.
703 resultStruct : `lsst.pipe.base.struct.Struct`
704 Results Strcut containing:
706 - outputExposure : Exposure
with added fakes
707 (`lsst.afw.image.exposure.exposure.ExposureF`)
708 - outputCat : Catalog
with detected fakes
709 (`lsst.afw.table.source.source.SourceCatalog`)
710 - ccdVisitFakeMagnitudes : Magnitudes that these fakes were
711 inserted
with after being scattered (`pandas.DataFrame`)
715 Adds pixel coordinates
for each source to the fakeCat
and removes objects
with bulge
or disk half
716 light radius = 0 (
if ``config.cleanCat =
True``). These columns are called ``x``
and ``y``
and are
in
719 Adds the ``Fake`` mask plane to the exposure which
is then set by `addFakeSources` to mark where fake
720 sources have been added. Uses the information
in the ``fakeCat`` to make fake galaxies (using galsim)
721 and fake stars, using the PSF models
from the PSF information
for the calexp. These are then added to
722 the calexp
and the calexp
with fakes included returned.
724 The galsim galaxies are made using a double sersic profile, one
for the bulge
and one
for the disk,
725 this
is then convolved
with the PSF at that point.
727 If exposureIdInfo
is not provided then the SourceCatalog IDs will
not be globally unique.
729 fakeCat = self.composeFakeCat(fakeCats, skyMap)
732 wcs = exposure.getWcs()
734 if photoCalib
is None:
735 photoCalib = exposure.getPhotoCalib()
737 if exposureIdInfo
is None:
738 exposureIdInfo = ExposureIdInfo()
740 band = exposure.getFilter().bandLabel
741 ccdVisitMagnitudes = self.addVariablity(fakeCat, band, exposure, photoCalib, exposureIdInfo)
743 self.insertFakes.run(fakeCat, exposure, wcs, photoCalib)
746 returnedStruct = self.calibrate.run(exposure, exposureIdInfo=exposureIdInfo)
747 sourceCat = returnedStruct.sourceCat
749 sourceCat = self.copyCalibrationFields(sfdSourceCat, sourceCat, self.config.srcFieldsToCopy)
751 resultStruct = pipeBase.Struct(outputExposure=exposure,
753 ccdVisitFakeMagnitudes=ccdVisitMagnitudes)
756 def addVariablity(self, fakeCat, band, exposure, photoCalib, exposureIdInfo):
757 """Add scatter to the fake catalog visit magnitudes.
759 Currently just adds a simple Gaussian scatter around the static fake
760 magnitude. This function could be modified to return any number of
765 fakeCat : `pandas.DataFrame`
766 Catalog of fakes to modify magnitudes of.
768 Current observing band to modify.
769 exposure : `lsst.afw.image.ExposureF`
770 Exposure fakes will be added to.
772 Photometric calibration object of ``exposure``.
773 exposureIdInfo : `lsst.obs.base.ExposureIdInfo`
774 Exposure id information
and metadata.
778 dataFrame : `pandas.DataFrame`
779 DataFrame containing the values of the magnitudes to that will
780 be inserted into this ccdVisit.
782 expId = exposureIdInfo.expId
783 rng = np.random.default_rng(expId)
784 magScatter = rng.normal(loc=0,
785 scale=self.config.scatterSize,
787 visitMagnitudes = fakeCat[self.insertFakes.config.mag_col % band] + magScatter
788 fakeCat.loc[:, self.insertFakes.config.mag_col % band] = visitMagnitudes
789 return pd.DataFrame(data={
"variableMag": visitMagnitudes})