23Insert fake sources into calexps
26__all__ = [
"ProcessCcdWithFakesConfig",
"ProcessCcdWithFakesTask",
27 "ProcessCcdWithVariableFakesConfig",
"ProcessCcdWithVariableFakesTask"]
35from .insertFakes
import InsertFakesTask
37from lsst.obs.base
import ExposureIdInfo
38from lsst.pipe.base import PipelineTask, PipelineTaskConfig, PipelineTaskConnections
39import lsst.pipe.base.connectionTypes
as cT
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):
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 runQuantum(self, butlerQC, inputRefs, outputRefs):
307 inputs = butlerQC.get(inputRefs)
308 detectorId = inputs[
"exposure"].getInfo().getDetector().getId()
310 if 'exposureIdInfo' not in inputs.keys():
311 expId, expBits = butlerQC.quantum.dataId.pack(
"visit_detector", returnMaxBits=
True)
312 inputs[
'exposureIdInfo'] = ExposureIdInfo(expId, expBits)
314 expWcs = inputs[
"exposure"].getWcs()
315 tractId = inputs[
"skyMap"].findTract(
316 expWcs.pixelToSky(inputs[
"exposure"].getBBox().getCenter())).tract_id
317 if not self.config.doApplyExternalGlobalSkyWcs
and not self.config.doApplyExternalTractSkyWcs:
318 inputs[
"wcs"] = expWcs
319 elif self.config.doApplyExternalGlobalSkyWcs:
320 externalSkyWcsCatalog = inputs[
"externalSkyWcsGlobalCatalog"]
321 row = externalSkyWcsCatalog.find(detectorId)
322 inputs[
"wcs"] = row.getWcs()
323 elif self.config.doApplyExternalTractSkyWcs:
324 externalSkyWcsCatalogList = inputs[
"externalSkyWcsTractCatalog"]
325 externalSkyWcsCatalog =
None
326 for externalSkyWcsCatalogRef
in externalSkyWcsCatalogList:
327 if externalSkyWcsCatalogRef.dataId[
"tract"] == tractId:
328 externalSkyWcsCatalog = externalSkyWcsCatalogRef.get(
329 datasetType=self.config.connections.externalSkyWcsTractCatalog)
331 if externalSkyWcsCatalog
is None:
332 usedTract = externalSkyWcsCatalogList[-1].dataId[
"tract"]
334 f
"Warning, external SkyWcs for tract {tractId} not found. Using tract {usedTract} "
336 externalSkyWcsCatalog = externalSkyWcsCatalogList[-1].get(
337 datasetType=self.config.connections.externalSkyWcsTractCatalog)
338 row = externalSkyWcsCatalog.find(detectorId)
339 inputs[
"wcs"] = row.getWcs()
341 if not self.config.doApplyExternalGlobalPhotoCalib
and not self.config.doApplyExternalTractPhotoCalib:
342 inputs[
"photoCalib"] = inputs[
"exposure"].getPhotoCalib()
343 elif self.config.doApplyExternalGlobalPhotoCalib:
344 externalPhotoCalibCatalog = inputs[
"externalPhotoCalibGlobalCatalog"]
345 row = externalPhotoCalibCatalog.find(detectorId)
346 inputs[
"photoCalib"] = row.getPhotoCalib()
347 elif self.config.doApplyExternalTractPhotoCalib:
348 externalPhotoCalibCatalogList = inputs[
"externalPhotoCalibTractCatalog"]
349 externalPhotoCalibCatalog =
None
350 for externalPhotoCalibCatalogRef
in externalPhotoCalibCatalogList:
351 if externalPhotoCalibCatalogRef.dataId[
"tract"] == tractId:
352 externalPhotoCalibCatalog = externalPhotoCalibCatalogRef.get(
353 datasetType=self.config.connections.externalPhotoCalibTractCatalog)
355 if externalPhotoCalibCatalog
is None:
356 usedTract = externalPhotoCalibCatalogList[-1].dataId[
"tract"]
358 f
"Warning, external PhotoCalib for tract {tractId} not found. Using tract {usedTract} "
360 externalPhotoCalibCatalog = externalPhotoCalibCatalogList[-1].get(
361 datasetType=self.config.connections.externalPhotoCalibTractCatalog)
362 row = externalPhotoCalibCatalog.find(detectorId)
363 inputs[
"photoCalib"] = row.getPhotoCalib()
365 outputs = self.run(**inputs)
366 butlerQC.put(outputs, outputRefs)
368 def run(self, fakeCats, exposure, skyMap, wcs=None, photoCalib=None, exposureIdInfo=None,
369 icSourceCat=None, sfdSourceCat=None, externalSkyWcsGlobalCatalog=None,
370 externalSkyWcsTractCatalog=None, externalPhotoCalibGlobalCatalog=None,
371 externalPhotoCalibTractCatalog=None):
372 """Add fake sources to a calexp and then run detection, deblending and measurement.
376 fakeCats : `list` of `lsst.daf.butler.DeferredDatasetHandle`
377 Set of tract level fake catalogs that potentially cover
379 exposure : `lsst.afw.image.exposure.exposure.ExposureF`
380 The exposure to add the fake sources to
381 skyMap : `lsst.skymap.SkyMap`
382 SkyMap defining the tracts and patches the fakes are stored over.
384 WCS to use to add fake sources
385 photoCalib : `lsst.afw.image.photoCalib.PhotoCalib`
386 Photometric calibration to be used to calibrate the fake sources
387 exposureIdInfo : `lsst.obs.base.ExposureIdInfo`
390 Catalog to take the information about which sources were used
for calibration
from.
393 Catalog produced by singleFrameDriver, needed to copy some calibration flags
from.
397 resultStruct : `lsst.pipe.base.struct.Struct`
398 contains : outputExposure : `lsst.afw.image.exposure.exposure.ExposureF`
399 outputCat : `lsst.afw.table.source.source.SourceCatalog`
403 Adds pixel coordinates
for each source to the fakeCat
and removes objects
with bulge
or disk half
404 light radius = 0 (
if ``config.cleanCat =
True``). These columns are called ``x``
and ``y``
and are
in
407 Adds the ``Fake`` mask plane to the exposure which
is then set by `addFakeSources` to mark where fake
408 sources have been added. Uses the information
in the ``fakeCat`` to make fake galaxies (using galsim)
409 and fake stars, using the PSF models
from the PSF information
for the calexp. These are then added to
410 the calexp
and the calexp
with fakes included returned.
412 The galsim galaxies are made using a double sersic profile, one
for the bulge
and one
for the disk,
413 this
is then convolved
with the PSF at that point.
415 If exposureIdInfo
is not provided then the SourceCatalog IDs will
not be globally unique.
417 fakeCat = self.composeFakeCat(fakeCats, skyMap)
420 wcs = exposure.getWcs()
422 if photoCalib
is None:
423 photoCalib = exposure.getPhotoCalib()
425 if self.config.doMatchVisit:
426 fakeCat = self.getVisitMatchedFakeCat(fakeCat, exposure)
428 self.insertFakes.run(fakeCat, exposure, wcs, photoCalib)
431 if exposureIdInfo
is None:
432 exposureIdInfo = ExposureIdInfo()
433 returnedStruct = self.calibrate.run(exposure, exposureIdInfo=exposureIdInfo)
434 sourceCat = returnedStruct.sourceCat
436 sourceCat = self.copyCalibrationFields(sfdSourceCat, sourceCat, self.config.srcFieldsToCopy)
438 resultStruct = pipeBase.Struct(outputExposure=exposure, outputCat=sourceCat)
441 def composeFakeCat(self, fakeCats, skyMap):
442 """Concatenate the fakeCats from tracts that may cover the exposure.
446 fakeCats : `list` of `lst.daf.butler.DeferredDatasetHandle`
447 Set of fake cats to concatenate.
448 skyMap : `lsst.skymap.SkyMap`
449 SkyMap defining the geometry of the tracts and patches.
453 combinedFakeCat : `pandas.DataFrame`
454 All fakes that cover the inner polygon of the tracts
in this
457 if len(fakeCats) == 1:
458 return fakeCats[0].get(
459 datasetType=self.config.connections.fakeCats)
461 for fakeCatRef
in fakeCats:
462 cat = fakeCatRef.get(
463 datasetType=self.config.connections.fakeCats)
464 tractId = fakeCatRef.dataId[
"tract"]
466 outputCat.append(cat[
467 skyMap.findTractIdArray(cat[self.config.insertFakes.ra_col],
468 cat[self.config.insertFakes.dec_col],
472 return pd.concat(outputCat)
474 def getVisitMatchedFakeCat(self, fakeCat, exposure):
475 """Trim the fakeCat to select particular visit
479 fakeCat : `pandas.core.frame.DataFrame`
480 The catalog of fake sources to add to the exposure
481 exposure : `lsst.afw.image.exposure.exposure.ExposureF`
482 The exposure to add the fake sources to
486 movingFakeCat : `pandas.DataFrame`
487 All fakes that belong to the visit
489 selected = exposure.getInfo().getVisitInfo().getId() == fakeCat["visit"]
491 return fakeCat[selected]
493 def copyCalibrationFields(self, calibCat, sourceCat, fieldsToCopy):
494 """Match sources in calibCat and sourceCat and copy the specified fields
499 Catalog from which to copy fields.
501 Catalog to which to copy fields.
503 Fields to copy
from calibCat to SoourceCat.
508 Catalog which includes the copied fields.
510 The fields copied are those specified by `fieldsToCopy` that actually exist
511 in the schema of `calibCat`.
513 This version was based on
and adapted
from the one
in calibrateTask.
517 sourceSchemaMapper = afwTable.SchemaMapper(sourceCat.schema)
518 sourceSchemaMapper.addMinimalSchema(sourceCat.schema,
True)
520 calibSchemaMapper = afwTable.SchemaMapper(calibCat.schema, sourceCat.schema)
523 missingFieldNames = []
524 for fieldName
in fieldsToCopy:
525 if fieldName
in calibCat.schema:
526 schemaItem = calibCat.schema.find(fieldName)
527 calibSchemaMapper.editOutputSchema().addField(schemaItem.getField())
528 schema = calibSchemaMapper.editOutputSchema()
529 calibSchemaMapper.addMapping(schemaItem.getKey(), schema.find(fieldName).getField())
531 missingFieldNames.append(fieldName)
532 if missingFieldNames:
533 raise RuntimeError(f
"calibCat is missing fields {missingFieldNames} specified in "
536 if "calib_detected" not in calibSchemaMapper.getOutputSchema():
537 self.calibSourceKey = calibSchemaMapper.addOutputField(afwTable.Field[
"Flag"](
"calib_detected",
538 "Source was detected as an icSource"))
540 self.calibSourceKey =
None
542 schema = calibSchemaMapper.getOutputSchema()
543 newCat = afwTable.SourceCatalog(schema)
544 newCat.reserve(len(sourceCat))
545 newCat.extend(sourceCat, sourceSchemaMapper)
548 for k, v
in sourceCat.schema.getAliasMap().items():
549 newCat.schema.getAliasMap().set(k, v)
551 select = newCat[
"deblend_nChild"] == 0
552 matches = afwTable.matchXy(newCat[select], calibCat, self.config.matchRadiusPix)
556 numMatches = len(matches)
557 numUniqueSources = len(set(m[1].getId()
for m
in matches))
558 if numUniqueSources != numMatches:
559 self.log.warning(
"%d calibCat sources matched only %d sourceCat sources", numMatches,
562 self.log.info(
"Copying flags from calibCat to sourceCat for %s sources", numMatches)
566 for src, calibSrc, d
in matches:
567 if self.calibSourceKey:
568 src.setFlag(self.calibSourceKey,
True)
573 calibSrcFootprint = calibSrc.getFootprint()
575 calibSrc.setFootprint(src.getFootprint())
576 src.assign(calibSrc, calibSchemaMapper)
578 calibSrc.setFootprint(calibSrcFootprint)
584 ccdVisitFakeMagnitudes = cT.Output(
585 doc=
"Catalog of fakes with magnitudes scattered for this ccdVisit.",
586 name=
"{fakesType}ccdVisitFakeMagnitudes",
587 storageClass=
"DataFrame",
588 dimensions=(
"instrument",
"visit",
"detector"),
592class ProcessCcdWithVariableFakesConfig(ProcessCcdWithFakesConfig,
593 pipelineConnections=ProcessCcdWithVariableFakesConnections):
594 scatterSize = pexConfig.RangeField(
599 doc=
"Amount of scatter to add to the visit magnitude for variable "
604class ProcessCcdWithVariableFakesTask(ProcessCcdWithFakesTask):
605 """As ProcessCcdWithFakes except add variablity to the fakes catalog
606 magnitude in the observed band
for this ccdVisit.
608 Additionally, write out the modified magnitudes to the Butler.
611 _DefaultName = "processCcdWithVariableFakes"
612 ConfigClass = ProcessCcdWithVariableFakesConfig
614 def run(self, fakeCats, exposure, skyMap, wcs=None, photoCalib=None, exposureIdInfo=None,
615 icSourceCat=None, sfdSourceCat=None):
616 """Add fake sources to a calexp and then run detection, deblending and measurement.
620 fakeCat : `pandas.core.frame.DataFrame`
621 The catalog of fake sources to add to the exposure
622 exposure : `lsst.afw.image.exposure.exposure.ExposureF`
623 The exposure to add the fake sources to
624 skyMap : `lsst.skymap.SkyMap`
625 SkyMap defining the tracts and patches the fakes are stored over.
627 WCS to use to add fake sources
628 photoCalib : `lsst.afw.image.photoCalib.PhotoCalib`
629 Photometric calibration to be used to calibrate the fake sources
630 exposureIdInfo : `lsst.obs.base.ExposureIdInfo`
633 Catalog to take the information about which sources were used
for calibration
from.
636 Catalog produced by singleFrameDriver, needed to copy some calibration flags
from.
640 resultStruct : `lsst.pipe.base.struct.Struct`
641 Results Strcut containing:
643 - outputExposure : Exposure
with added fakes
644 (`lsst.afw.image.exposure.exposure.ExposureF`)
645 - outputCat : Catalog
with detected fakes
646 (`lsst.afw.table.source.source.SourceCatalog`)
647 - ccdVisitFakeMagnitudes : Magnitudes that these fakes were
648 inserted
with after being scattered (`pandas.DataFrame`)
652 Adds pixel coordinates
for each source to the fakeCat
and removes objects
with bulge
or disk half
653 light radius = 0 (
if ``config.cleanCat =
True``). These columns are called ``x``
and ``y``
and are
in
656 Adds the ``Fake`` mask plane to the exposure which
is then set by `addFakeSources` to mark where fake
657 sources have been added. Uses the information
in the ``fakeCat`` to make fake galaxies (using galsim)
658 and fake stars, using the PSF models
from the PSF information
for the calexp. These are then added to
659 the calexp
and the calexp
with fakes included returned.
661 The galsim galaxies are made using a double sersic profile, one
for the bulge
and one
for the disk,
662 this
is then convolved
with the PSF at that point.
664 If exposureIdInfo
is not provided then the SourceCatalog IDs will
not be globally unique.
666 fakeCat = self.composeFakeCat(fakeCats, skyMap)
669 wcs = exposure.getWcs()
671 if photoCalib
is None:
672 photoCalib = exposure.getPhotoCalib()
674 if exposureIdInfo
is None:
675 exposureIdInfo = ExposureIdInfo()
677 band = exposure.getFilter().bandLabel
678 ccdVisitMagnitudes = self.addVariablity(fakeCat, band, exposure, photoCalib, exposureIdInfo)
680 self.insertFakes.run(fakeCat, exposure, wcs, photoCalib)
683 returnedStruct = self.calibrate.run(exposure, exposureIdInfo=exposureIdInfo)
684 sourceCat = returnedStruct.sourceCat
686 sourceCat = self.copyCalibrationFields(sfdSourceCat, sourceCat, self.config.srcFieldsToCopy)
688 resultStruct = pipeBase.Struct(outputExposure=exposure,
690 ccdVisitFakeMagnitudes=ccdVisitMagnitudes)
693 def addVariablity(self, fakeCat, band, exposure, photoCalib, exposureIdInfo):
694 """Add scatter to the fake catalog visit magnitudes.
696 Currently just adds a simple Gaussian scatter around the static fake
697 magnitude. This function could be modified to return any number of
702 fakeCat : `pandas.DataFrame`
703 Catalog of fakes to modify magnitudes of.
705 Current observing band to modify.
706 exposure : `lsst.afw.image.ExposureF`
707 Exposure fakes will be added to.
709 Photometric calibration object of ``exposure``.
710 exposureIdInfo : `lsst.obs.base.ExposureIdInfo`
711 Exposure id information
and metadata.
715 dataFrame : `pandas.DataFrame`
716 DataFrame containing the values of the magnitudes to that will
717 be inserted into this ccdVisit.
719 expId = exposureIdInfo.expId
720 rng = np.random.default_rng(expId)
721 magScatter = rng.normal(loc=0,
722 scale=self.config.scatterSize,
724 visitMagnitudes = fakeCat[self.insertFakes.config.mag_col % band] + magScatter
725 fakeCat.loc[:, self.insertFakes.config.mag_col % band] = visitMagnitudes
726 return pd.DataFrame(data={
"variableMag": visitMagnitudes})