23Insert fake sources into calexps
25from astropy.table
import Table
32from .insertFakes
import InsertFakesTask
34from lsst.obs.base
import ExposureIdInfo
35from lsst.pipe.base import PipelineTask, PipelineTaskConfig, CmdLineTask, PipelineTaskConnections
36import lsst.pipe.base.connectionTypes
as cT
41__all__ = [
"ProcessCcdWithFakesConfig",
"ProcessCcdWithFakesTask",
42 "ProcessCcdWithVariableFakesConfig",
"ProcessCcdWithVariableFakesTask"]
46 dimensions=(
"instrument",
"visit",
"detector"),
47 defaultTemplates={
"coaddName":
"deep",
48 "wcsName":
"jointcal",
49 "photoCalibName":
"jointcal",
50 "fakesType":
"fakes_"}):
52 doc=
"Input definition of geometry/bbox and projection/wcs for "
53 "template exposures. Needed to test which tract to generate ",
54 name=BaseSkyMap.SKYMAP_DATASET_TYPE_NAME,
55 dimensions=(
"skymap",),
56 storageClass=
"SkyMap",
60 doc=
"Exposure into which fakes are to be added.",
62 storageClass=
"ExposureF",
63 dimensions=(
"instrument",
"visit",
"detector")
67 doc=
"Set of catalogs of fake sources to draw inputs from. We "
68 "concatenate the tract catalogs for detectorVisits that cover "
70 name=
"{fakesType}fakeSourceCat",
71 storageClass=
"DataFrame",
72 dimensions=(
"tract",
"skymap"),
77 externalSkyWcsTractCatalog = cT.Input(
78 doc=(
"Per-tract, per-visit wcs calibrations. These catalogs use the detector "
79 "id for the catalog id, sorted on id for fast lookup."),
80 name=
"{wcsName}SkyWcsCatalog",
81 storageClass=
"ExposureCatalog",
82 dimensions=(
"instrument",
"visit",
"tract",
"skymap"),
87 externalSkyWcsGlobalCatalog = cT.Input(
88 doc=(
"Per-visit wcs calibrations computed globally (with no tract information). "
89 "These catalogs use the detector id for the catalog id, sorted on id for "
91 name=
"{wcsName}SkyWcsCatalog",
92 storageClass=
"ExposureCatalog",
93 dimensions=(
"instrument",
"visit"),
96 externalPhotoCalibTractCatalog = cT.Input(
97 doc=(
"Per-tract, per-visit photometric calibrations. These catalogs use the "
98 "detector id for the catalog id, sorted on id for fast lookup."),
99 name=
"{photoCalibName}PhotoCalibCatalog",
100 storageClass=
"ExposureCatalog",
101 dimensions=(
"instrument",
"visit",
"tract"),
106 externalPhotoCalibGlobalCatalog = cT.Input(
107 doc=(
"Per-visit photometric calibrations. These catalogs use the "
108 "detector id for the catalog id, sorted on id for fast lookup."),
109 name=
"{photoCalibName}PhotoCalibCatalog",
110 storageClass=
"ExposureCatalog",
111 dimensions=(
"instrument",
"visit"),
114 icSourceCat = cT.Input(
115 doc=
"Catalog of calibration sources",
117 storageClass=
"SourceCatalog",
118 dimensions=(
"instrument",
"visit",
"detector")
121 sfdSourceCat = cT.Input(
122 doc=
"Catalog of calibration sources",
124 storageClass=
"SourceCatalog",
125 dimensions=(
"instrument",
"visit",
"detector")
128 outputExposure = cT.Output(
129 doc=
"Exposure with fake sources added.",
130 name=
"{fakesType}calexp",
131 storageClass=
"ExposureF",
132 dimensions=(
"instrument",
"visit",
"detector")
135 outputCat = cT.Output(
136 doc=
"Source catalog produced in calibrate task with fakes also measured.",
137 name=
"{fakesType}src",
138 storageClass=
"SourceCatalog",
139 dimensions=(
"instrument",
"visit",
"detector"),
142 def __init__(self, *, config=None):
143 super().__init__(config=config)
145 if not config.doApplyExternalGlobalPhotoCalib:
146 self.inputs.remove(
"externalPhotoCalibGlobalCatalog")
147 if not config.doApplyExternalTractPhotoCalib:
148 self.inputs.remove(
"externalPhotoCalibTractCatalog")
150 if not config.doApplyExternalGlobalSkyWcs:
151 self.inputs.remove(
"externalSkyWcsGlobalCatalog")
152 if not config.doApplyExternalTractSkyWcs:
153 self.inputs.remove(
"externalSkyWcsTractCatalog")
156class ProcessCcdWithFakesConfig(PipelineTaskConfig,
157 pipelineConnections=ProcessCcdWithFakesConnections):
158 """Config for inserting fake sources
162 The default column names are those from the UW sims database.
165 doApplyExternalGlobalPhotoCalib = pexConfig.Field(
168 doc=
"Whether to apply an external photometric calibration via an "
169 "`lsst.afw.image.PhotoCalib` object. Uses the "
170 "`externalPhotoCalibName` config option to determine which "
171 "calibration to use. Uses a global calibration."
174 doApplyExternalTractPhotoCalib = pexConfig.Field(
177 doc=
"Whether to apply an external photometric calibration via an "
178 "`lsst.afw.image.PhotoCalib` object. Uses the "
179 "`externalPhotoCalibName` config option to determine which "
180 "calibration to use. Uses a per tract calibration."
183 externalPhotoCalibName = pexConfig.ChoiceField(
184 doc=
"What type of external photo calib to use.",
187 allowed={
"jointcal":
"Use jointcal_photoCalib",
188 "fgcm":
"Use fgcm_photoCalib",
189 "fgcm_tract":
"Use fgcm_tract_photoCalib"}
192 doApplyExternalGlobalSkyWcs = pexConfig.Field(
195 doc=
"Whether to apply an external astrometric calibration via an "
196 "`lsst.afw.geom.SkyWcs` object. Uses the "
197 "`externalSkyWcsName` config option to determine which "
198 "calibration to use. Uses a global calibration."
201 doApplyExternalTractSkyWcs = pexConfig.Field(
204 doc=
"Whether to apply an external astrometric calibration via an "
205 "`lsst.afw.geom.SkyWcs` object. Uses the "
206 "`externalSkyWcsName` config option to determine which "
207 "calibration to use. Uses a per tract calibration."
210 externalSkyWcsName = pexConfig.ChoiceField(
211 doc=
"What type of updated WCS calib to use.",
214 allowed={
"jointcal":
"Use jointcal_wcs"}
217 coaddName = pexConfig.Field(
218 doc=
"The name of the type of coadd used",
223 srcFieldsToCopy = pexConfig.ListField(
225 default=(
"calib_photometry_reserved",
"calib_photometry_used",
"calib_astrometry_used",
226 "calib_psf_candidate",
"calib_psf_used",
"calib_psf_reserved"),
227 doc=(
"Fields to copy from the `src` catalog to the output catalog "
228 "for matching sources Any missing fields will trigger a "
229 "RuntimeError exception.")
232 matchRadiusPix = pexConfig.Field(
235 doc=(
"Match radius for matching icSourceCat objects to sourceCat objects (pixels)"),
238 doMatchVisit = pexConfig.Field(
241 doc=
"Match visit to trim the fakeCat"
244 calibrate = pexConfig.ConfigurableField(target=CalibrateTask,
245 doc=
"The calibration task to use.")
247 insertFakes = pexConfig.ConfigurableField(target=InsertFakesTask,
248 doc=
"Configuration for the fake sources")
250 def setDefaults(self):
251 super().setDefaults()
252 self.calibrate.measurement.plugins[
"base_PixelFlags"].masksFpAnywhere.append(
"FAKE")
253 self.calibrate.measurement.plugins[
"base_PixelFlags"].masksFpCenter.append(
"FAKE")
254 self.calibrate.doAstrometry =
False
255 self.calibrate.doWriteMatches =
False
256 self.calibrate.doPhotoCal =
False
257 self.calibrate.detection.reEstimateBackground =
False
260class ProcessCcdWithFakesTask(PipelineTask, CmdLineTask):
261 """Insert fake objects into calexps.
263 Add fake stars and galaxies to the given calexp, specified
in the dataRef. Galaxy parameters are read
in
264 from the specified file
and then modelled using galsim. Re-runs characterize image
and calibrate image to
265 give a new background estimation
and measurement of the calexp.
267 `ProcessFakeSourcesTask` inherits six functions
from insertFakesTask that make images of the fake
268 sources
and then add them to the calexp.
271 Use the WCS information to add the pixel coordinates of each source
272 Adds an ``x``
and ``y`` column to the catalog of fake sources.
274 Trim the fake cat to about the size of the input image.
275 `mkFakeGalsimGalaxies`
276 Use Galsim to make fake double sersic galaxies
for each set of galaxy parameters
in the input file.
278 Use the PSF information
from the calexp to make a fake star using the magnitude information
from the
281 Remove rows of the input fake catalog which have half light radius, of either the bulge
or the disk,
284 Add the fake sources to the calexp.
288 The ``calexp``
with fake souces added to it
is written out
as the datatype ``calexp_fakes``.
291 _DefaultName = "processCcdWithFakes"
292 ConfigClass = ProcessCcdWithFakesConfig
294 def __init__(self, schema=None, butler=None, **kwargs):
295 """Initalize things! This should go above in the class docstring
298 super().__init__(**kwargs)
301 schema = SourceTable.makeMinimalSchema()
303 self.makeSubtask(
"insertFakes")
304 self.makeSubtask(
"calibrate")
306 def runDataRef(self, dataRef):
307 """Read in/write out the required data products and add fake sources to the calexp.
312 Data reference defining the ccd to have fakes added to it.
313 Used to access the following data products:
320 Uses the calibration and WCS information attached to the calexp
for the posistioning
and calibration
321 of the sources unless the config option config.externalPhotoCalibName
or config.externalSkyWcsName
322 are set then it uses the specified outputs. The config defualts
for the column names
in the catalog
323 of fakes are taken
from the University of Washington simulations database.
324 Operates on one ccd at a time.
326 exposureIdInfo = dataRef.get("expIdInfo")
328 if self.config.insertFakes.fakeType ==
"snapshot":
329 fakeCat = dataRef.get(
"fakeSourceCat").toDataFrame()
330 elif self.config.insertFakes.fakeType ==
"static":
331 fakeCat = dataRef.get(
"deepCoadd_fakeSourceCat").toDataFrame()
333 fakeCat = Table.read(self.config.insertFakes.fakeType).to_pandas()
335 calexp = dataRef.get(
"calexp")
336 if self.config.doApplyExternalGlobalSkyWcs
or self.config.doApplyExternalTractSkyWcs:
337 self.log.info(
"Using external wcs from %s", self.config.externalSkyWcsName)
338 wcs = dataRef.get(self.config.externalSkyWcsName +
"_wcs")
340 wcs = calexp.getWcs()
342 if self.config.doApplyExternalGlobalPhotoCalib
or self.config.doApplyExternalTractPhotoCalib:
343 self.log.info(
"Using external photocalib from %s", self.config.externalPhotoCalibName)
344 photoCalib = dataRef.get(self.config.externalPhotoCalibName +
"_photoCalib")
346 photoCalib = calexp.getPhotoCalib()
348 icSourceCat = dataRef.get(
"icSrc", immediate=
True)
349 sfdSourceCat = dataRef.get(
"src", immediate=
True)
351 resultStruct = self.run(fakeCat, calexp, wcs=wcs, photoCalib=photoCalib,
352 exposureIdInfo=exposureIdInfo, icSourceCat=icSourceCat,
353 sfdSourceCat=sfdSourceCat)
355 dataRef.put(resultStruct.outputExposure,
"fakes_calexp")
356 dataRef.put(resultStruct.outputCat,
"fakes_src")
359 def runQuantum(self, butlerQC, inputRefs, outputRefs):
360 inputs = butlerQC.get(inputRefs)
361 detectorId = inputs[
"exposure"].getInfo().getDetector().getId()
363 if 'exposureIdInfo' not in inputs.keys():
364 expId, expBits = butlerQC.quantum.dataId.pack(
"visit_detector", returnMaxBits=
True)
365 inputs[
'exposureIdInfo'] = ExposureIdInfo(expId, expBits)
367 expWcs = inputs[
"exposure"].getWcs()
368 tractId = inputs[
"skyMap"].findTract(
369 expWcs.pixelToSky(inputs[
"exposure"].getBBox().getCenter())).tract_id
370 if not self.config.doApplyExternalGlobalSkyWcs
and not self.config.doApplyExternalTractSkyWcs:
371 inputs[
"wcs"] = expWcs
372 elif self.config.doApplyExternalGlobalSkyWcs:
373 externalSkyWcsCatalog = inputs[
"externalSkyWcsGlobalCatalog"]
374 row = externalSkyWcsCatalog.find(detectorId)
375 inputs[
"wcs"] = row.getWcs()
376 elif self.config.doApplyExternalTractSkyWcs:
377 externalSkyWcsCatalogList = inputs[
"externalSkyWcsTractCatalog"]
378 externalSkyWcsCatalog =
None
379 for externalSkyWcsCatalogRef
in externalSkyWcsCatalogList:
380 if externalSkyWcsCatalogRef.dataId[
"tract"] == tractId:
381 externalSkyWcsCatalog = externalSkyWcsCatalogRef.get(
382 datasetType=self.config.connections.externalSkyWcsTractCatalog)
384 if externalSkyWcsCatalog
is None:
385 usedTract = externalSkyWcsCatalogList[-1].dataId[
"tract"]
387 f
"Warning, external SkyWcs for tract {tractId} not found. Using tract {usedTract} "
389 externalSkyWcsCatalog = externalSkyWcsCatalogList[-1].get(
390 datasetType=self.config.connections.externalSkyWcsTractCatalog)
391 row = externalSkyWcsCatalog.find(detectorId)
392 inputs[
"wcs"] = row.getWcs()
394 if not self.config.doApplyExternalGlobalPhotoCalib
and not self.config.doApplyExternalTractPhotoCalib:
395 inputs[
"photoCalib"] = inputs[
"exposure"].getPhotoCalib()
396 elif self.config.doApplyExternalGlobalPhotoCalib:
397 externalPhotoCalibCatalog = inputs[
"externalPhotoCalibGlobalCatalog"]
398 row = externalPhotoCalibCatalog.find(detectorId)
399 inputs[
"photoCalib"] = row.getPhotoCalib()
400 elif self.config.doApplyExternalTractPhotoCalib:
401 externalPhotoCalibCatalogList = inputs[
"externalPhotoCalibTractCatalog"]
402 externalPhotoCalibCatalog =
None
403 for externalPhotoCalibCatalogRef
in externalPhotoCalibCatalogList:
404 if externalPhotoCalibCatalogRef.dataId[
"tract"] == tractId:
405 externalPhotoCalibCatalog = externalPhotoCalibCatalogRef.get(
406 datasetType=self.config.connections.externalPhotoCalibTractCatalog)
408 if externalPhotoCalibCatalog
is None:
409 usedTract = externalPhotoCalibCatalogList[-1].dataId[
"tract"]
411 f
"Warning, external PhotoCalib for tract {tractId} not found. Using tract {usedTract} "
413 externalPhotoCalibCatalog = externalPhotoCalibCatalogList[-1].get(
414 datasetType=self.config.connections.externalPhotoCalibTractCatalog)
415 row = externalPhotoCalibCatalog.find(detectorId)
416 inputs[
"photoCalib"] = row.getPhotoCalib()
418 outputs = self.run(**inputs)
419 butlerQC.put(outputs, outputRefs)
421 def run(self, fakeCats, exposure, skyMap, wcs=None, photoCalib=None, exposureIdInfo=None,
422 icSourceCat=None, sfdSourceCat=None, externalSkyWcsGlobalCatalog=None,
423 externalSkyWcsTractCatalog=None, externalPhotoCalibGlobalCatalog=None,
424 externalPhotoCalibTractCatalog=None):
425 """Add fake sources to a calexp and then run detection, deblending and measurement.
429 fakeCats : `list` of `lsst.daf.butler.DeferredDatasetHandle`
430 Set of tract level fake catalogs that potentially cover
432 exposure : `lsst.afw.image.exposure.exposure.ExposureF`
433 The exposure to add the fake sources to
434 skyMap : `lsst.skymap.SkyMap`
435 SkyMap defining the tracts and patches the fakes are stored over.
437 WCS to use to add fake sources
438 photoCalib : `lsst.afw.image.photoCalib.PhotoCalib`
439 Photometric calibration to be used to calibrate the fake sources
440 exposureIdInfo : `lsst.obs.base.ExposureIdInfo`
443 Catalog to take the information about which sources were used
for calibration
from.
446 Catalog produced by singleFrameDriver, needed to copy some calibration flags
from.
450 resultStruct : `lsst.pipe.base.struct.Struct`
451 contains : outputExposure : `lsst.afw.image.exposure.exposure.ExposureF`
452 outputCat : `lsst.afw.table.source.source.SourceCatalog`
456 Adds pixel coordinates
for each source to the fakeCat
and removes objects
with bulge
or disk half
457 light radius = 0 (
if ``config.cleanCat =
True``). These columns are called ``x``
and ``y``
and are
in
460 Adds the ``Fake`` mask plane to the exposure which
is then set by `addFakeSources` to mark where fake
461 sources have been added. Uses the information
in the ``fakeCat`` to make fake galaxies (using galsim)
462 and fake stars, using the PSF models
from the PSF information
for the calexp. These are then added to
463 the calexp
and the calexp
with fakes included returned.
465 The galsim galaxies are made using a double sersic profile, one
for the bulge
and one
for the disk,
466 this
is then convolved
with the PSF at that point.
468 If exposureIdInfo
is not provided then the SourceCatalog IDs will
not be globally unique.
470 fakeCat = self.composeFakeCat(fakeCats, skyMap)
473 wcs = exposure.getWcs()
475 if photoCalib
is None:
476 photoCalib = exposure.getPhotoCalib()
478 if self.config.doMatchVisit:
479 fakeCat = self.getVisitMatchedFakeCat(fakeCat, exposure)
481 self.insertFakes.run(fakeCat, exposure, wcs, photoCalib)
484 if exposureIdInfo
is None:
485 exposureIdInfo = ExposureIdInfo()
486 returnedStruct = self.calibrate.run(exposure, exposureIdInfo=exposureIdInfo)
487 sourceCat = returnedStruct.sourceCat
489 sourceCat = self.copyCalibrationFields(sfdSourceCat, sourceCat, self.config.srcFieldsToCopy)
491 resultStruct = pipeBase.Struct(outputExposure=exposure, outputCat=sourceCat)
494 def composeFakeCat(self, fakeCats, skyMap):
495 """Concatenate the fakeCats from tracts that may cover the exposure.
499 fakeCats : `list` of `lst.daf.butler.DeferredDatasetHandle`
500 Set of fake cats to concatenate.
501 skyMap : `lsst.skymap.SkyMap`
502 SkyMap defining the geometry of the tracts and patches.
506 combinedFakeCat : `pandas.DataFrame`
507 All fakes that cover the inner polygon of the tracts
in this
510 if len(fakeCats) == 1:
511 return fakeCats[0].get(
512 datasetType=self.config.connections.fakeCats)
514 for fakeCatRef
in fakeCats:
515 cat = fakeCatRef.get(
516 datasetType=self.config.connections.fakeCats)
517 tractId = fakeCatRef.dataId[
"tract"]
519 outputCat.append(cat[
520 skyMap.findTractIdArray(cat[self.config.insertFakes.ra_col],
521 cat[self.config.insertFakes.dec_col],
525 return pd.concat(outputCat)
527 def getVisitMatchedFakeCat(self, fakeCat, exposure):
528 """Trim the fakeCat to select particular visit
532 fakeCat : `pandas.core.frame.DataFrame`
533 The catalog of fake sources to add to the exposure
534 exposure : `lsst.afw.image.exposure.exposure.ExposureF`
535 The exposure to add the fake sources to
539 movingFakeCat : `pandas.DataFrame`
540 All fakes that belong to the visit
542 selected = exposure.getInfo().getVisitInfo().getId() == fakeCat["visit"]
544 return fakeCat[selected]
546 def copyCalibrationFields(self, calibCat, sourceCat, fieldsToCopy):
547 """Match sources in calibCat and sourceCat and copy the specified fields
552 Catalog from which to copy fields.
554 Catalog to which to copy fields.
556 Fields to copy
from calibCat to SoourceCat.
561 Catalog which includes the copied fields.
563 The fields copied are those specified by `fieldsToCopy` that actually exist
564 in the schema of `calibCat`.
566 This version was based on
and adapted
from the one
in calibrateTask.
570 sourceSchemaMapper = afwTable.SchemaMapper(sourceCat.schema)
571 sourceSchemaMapper.addMinimalSchema(sourceCat.schema,
True)
573 calibSchemaMapper = afwTable.SchemaMapper(calibCat.schema, sourceCat.schema)
576 missingFieldNames = []
577 for fieldName
in fieldsToCopy:
578 if fieldName
in calibCat.schema:
579 schemaItem = calibCat.schema.find(fieldName)
580 calibSchemaMapper.editOutputSchema().addField(schemaItem.getField())
581 schema = calibSchemaMapper.editOutputSchema()
582 calibSchemaMapper.addMapping(schemaItem.getKey(), schema.find(fieldName).getField())
584 missingFieldNames.append(fieldName)
585 if missingFieldNames:
586 raise RuntimeError(f
"calibCat is missing fields {missingFieldNames} specified in "
589 if "calib_detected" not in calibSchemaMapper.getOutputSchema():
590 self.calibSourceKey = calibSchemaMapper.addOutputField(afwTable.Field[
"Flag"](
"calib_detected",
591 "Source was detected as an icSource"))
593 self.calibSourceKey =
None
595 schema = calibSchemaMapper.getOutputSchema()
596 newCat = afwTable.SourceCatalog(schema)
597 newCat.reserve(len(sourceCat))
598 newCat.extend(sourceCat, sourceSchemaMapper)
601 for k, v
in sourceCat.schema.getAliasMap().items():
602 newCat.schema.getAliasMap().set(k, v)
604 select = newCat[
"deblend_nChild"] == 0
605 matches = afwTable.matchXy(newCat[select], calibCat, self.config.matchRadiusPix)
609 numMatches = len(matches)
610 numUniqueSources = len(set(m[1].getId()
for m
in matches))
611 if numUniqueSources != numMatches:
612 self.log.warning(
"%d calibCat sources matched only %d sourceCat sources", numMatches,
615 self.log.info(
"Copying flags from calibCat to sourceCat for %s sources", numMatches)
619 for src, calibSrc, d
in matches:
620 if self.calibSourceKey:
621 src.setFlag(self.calibSourceKey,
True)
626 calibSrcFootprint = calibSrc.getFootprint()
628 calibSrc.setFootprint(src.getFootprint())
629 src.assign(calibSrc, calibSchemaMapper)
631 calibSrc.setFootprint(calibSrcFootprint)
637 ccdVisitFakeMagnitudes = cT.Output(
638 doc=
"Catalog of fakes with magnitudes scattered for this ccdVisit.",
639 name=
"{fakesType}ccdVisitFakeMagnitudes",
640 storageClass=
"DataFrame",
641 dimensions=(
"instrument",
"visit",
"detector"),
645class ProcessCcdWithVariableFakesConfig(ProcessCcdWithFakesConfig,
646 pipelineConnections=ProcessCcdWithVariableFakesConnections):
647 scatterSize = pexConfig.RangeField(
652 doc=
"Amount of scatter to add to the visit magnitude for variable "
657class ProcessCcdWithVariableFakesTask(ProcessCcdWithFakesTask):
658 """As ProcessCcdWithFakes except add variablity to the fakes catalog
659 magnitude in the observed band
for this ccdVisit.
661 Additionally, write out the modified magnitudes to the Butler.
664 _DefaultName = "processCcdWithVariableFakes"
665 ConfigClass = ProcessCcdWithVariableFakesConfig
667 def run(self, fakeCats, exposure, skyMap, wcs=None, photoCalib=None, exposureIdInfo=None,
668 icSourceCat=None, sfdSourceCat=None):
669 """Add fake sources to a calexp and then run detection, deblending and measurement.
673 fakeCat : `pandas.core.frame.DataFrame`
674 The catalog of fake sources to add to the exposure
675 exposure : `lsst.afw.image.exposure.exposure.ExposureF`
676 The exposure to add the fake sources to
677 skyMap : `lsst.skymap.SkyMap`
678 SkyMap defining the tracts and patches the fakes are stored over.
680 WCS to use to add fake sources
681 photoCalib : `lsst.afw.image.photoCalib.PhotoCalib`
682 Photometric calibration to be used to calibrate the fake sources
683 exposureIdInfo : `lsst.obs.base.ExposureIdInfo`
686 Catalog to take the information about which sources were used
for calibration
from.
689 Catalog produced by singleFrameDriver, needed to copy some calibration flags
from.
693 resultStruct : `lsst.pipe.base.struct.Struct`
694 Results Strcut containing:
696 - outputExposure : Exposure
with added fakes
697 (`lsst.afw.image.exposure.exposure.ExposureF`)
698 - outputCat : Catalog
with detected fakes
699 (`lsst.afw.table.source.source.SourceCatalog`)
700 - ccdVisitFakeMagnitudes : Magnitudes that these fakes were
701 inserted
with after being scattered (`pandas.DataFrame`)
705 Adds pixel coordinates
for each source to the fakeCat
and removes objects
with bulge
or disk half
706 light radius = 0 (
if ``config.cleanCat =
True``). These columns are called ``x``
and ``y``
and are
in
709 Adds the ``Fake`` mask plane to the exposure which
is then set by `addFakeSources` to mark where fake
710 sources have been added. Uses the information
in the ``fakeCat`` to make fake galaxies (using galsim)
711 and fake stars, using the PSF models
from the PSF information
for the calexp. These are then added to
712 the calexp
and the calexp
with fakes included returned.
714 The galsim galaxies are made using a double sersic profile, one
for the bulge
and one
for the disk,
715 this
is then convolved
with the PSF at that point.
717 If exposureIdInfo
is not provided then the SourceCatalog IDs will
not be globally unique.
719 fakeCat = self.composeFakeCat(fakeCats, skyMap)
722 wcs = exposure.getWcs()
724 if photoCalib
is None:
725 photoCalib = exposure.getPhotoCalib()
727 if exposureIdInfo
is None:
728 exposureIdInfo = ExposureIdInfo()
730 band = exposure.getFilter().bandLabel
731 ccdVisitMagnitudes = self.addVariablity(fakeCat, band, exposure, photoCalib, exposureIdInfo)
733 self.insertFakes.run(fakeCat, exposure, wcs, photoCalib)
736 returnedStruct = self.calibrate.run(exposure, exposureIdInfo=exposureIdInfo)
737 sourceCat = returnedStruct.sourceCat
739 sourceCat = self.copyCalibrationFields(sfdSourceCat, sourceCat, self.config.srcFieldsToCopy)
741 resultStruct = pipeBase.Struct(outputExposure=exposure,
743 ccdVisitFakeMagnitudes=ccdVisitMagnitudes)
746 def addVariablity(self, fakeCat, band, exposure, photoCalib, exposureIdInfo):
747 """Add scatter to the fake catalog visit magnitudes.
749 Currently just adds a simple Gaussian scatter around the static fake
750 magnitude. This function could be modified to return any number of
755 fakeCat : `pandas.DataFrame`
756 Catalog of fakes to modify magnitudes of.
758 Current observing band to modify.
759 exposure : `lsst.afw.image.ExposureF`
760 Exposure fakes will be added to.
762 Photometric calibration object of ``exposure``.
763 exposureIdInfo : `lsst.obs.base.ExposureIdInfo`
764 Exposure id information
and metadata.
768 dataFrame : `pandas.DataFrame`
769 DataFrame containing the values of the magnitudes to that will
770 be inserted into this ccdVisit.
772 expId = exposureIdInfo.expId
773 rng = np.random.default_rng(expId)
774 magScatter = rng.normal(loc=0,
775 scale=self.config.scatterSize,
777 visitMagnitudes = fakeCat[self.insertFakes.config.mag_col % band] + magScatter
778 fakeCat.loc[:, self.insertFakes.config.mag_col % band] = visitMagnitudes
779 return pd.DataFrame(data={
"variableMag": visitMagnitudes})