22__all__ = (
"SimpleForcedMeasurementConfig",
"SimpleForcedMeasurementTask")
33from lsst.utils.logging
import PeriodicLogger
35from .baseMeasurement
import SimpleBaseMeasurementConfig, SimpleBaseMeasurementTask
36from .forcedMeasurement
import ForcedPlugin
40 """Config class for SimpleForcedMeasurementTask."""
41 plugins = ForcedPlugin.registry.makeField(
43 default=[
"base_PixelFlags",
44 "base_TransformedCentroidFromCoord",
47 doc=
"Plugins to be run and their configuration"
49 psfFootprintScaling = lsst.pex.config.Field(
51 doc=
"Scaling factor to apply to the PSF shape when footprintSource='psf' (ignored otherwise).",
54 copyColumns = lsst.pex.config.DictField(
55 keytype=str, itemtype=str, doc=
"Mapping of reference columns to source columns",
56 default={
"id":
"objectId",
"parent":
"parentObjectId",
57 "coord_ra":
"coord_ra",
"coord_dec":
"coord_dec"}
59 checkUnitsParseStrict = lsst.pex.config.Field(
60 doc=
"Strictness of Astropy unit compatibility check, can be 'raise', 'warn' or 'silent'",
66 self.
slots.centroid =
"base_TransformedCentroidFromCoord"
67 self.
slots.shape =
None
68 self.
slots.apFlux =
None
69 self.
slots.modelFlux =
None
70 self.
slots.psfFlux =
"base_PsfFlux"
71 self.
slots.gaussianFlux =
None
72 self.
slots.calibFlux =
None
76 """Measure sources on an image using a simple forced measurement algorithm.
78 This differes from ForcedMeasurmentTask in that it uses a PSF-based
79 footprint for every source so it does not need to transform footprints.
83 algMetadata : `lsst.daf.base.PropertyList` or `None`
84 Will be updated in place to to record information about each
85 algorithm. An empty `~lsst.daf.base.PropertyList` will be created if
88 Keyword arguments are passed to the supertask constructor.
90 ConfigClass = SimpleForcedMeasurementConfig
93 super().
__init__(algMetadata=algMetadata, **kwds)
96 self.config.slots.setupSchema(self.
mapper.editOutputSchema())
97 for refName, targetName
in self.config.copyColumns.items():
98 refItem = refSchema.find(refName)
99 self.
mapper.addMapping(refItem.key, targetName)
100 self.config.slots.setupSchema(self.
mapper.editOutputSchema())
104 self.
schema.checkUnits(parse_strict=self.config.checkUnitsParseStrict)
112 beginOrder: int |
None =
None,
113 endOrder: int |
None =
None,
115 """Perform forced measurement.
119 refCat : `lsst.afw.table.SourceCatalog`
120 Catalog with locations and ids of sources to measure.
121 measCat : `lsst.afw.table.SourceCatalog`
122 Catalog that measurements are made on.
123 exposure : `lsst.afw.image.exposureF`
124 Image to be measured. Must have at least a `lsst.afw.geom.SkyWcs`
126 refWcs : `lsst.afw.geom.SkyWcs`
127 Defines the X,Y coordinate system of ``refCat``.
128 beginOrder : `int`, optional
129 Beginning execution order (inclusive). Algorithms with
130 ``executionOrder`` < ``beginOrder`` are not executed. `None` for no limit.
131 endOrder : `int`, optional
132 Ending execution order (exclusive). Algorithms with
133 ``executionOrder`` >= ``endOrder`` are not executed. `None` for no limit.
134 idFactory : `lsst.afw.table.IdFactory`, optional
135 Factory for creating IDs for sources.
138 self.log.info(
"Performing forced measurement on %d source%s", len(refCat),
139 "" if len(refCat) == 1
else "s")
141 periodicLog = PeriodicLogger(self.log)
143 for index
in range(len(refCat)):
144 measRecord = measCat[index]
145 refRecord = refCat[index]
146 if measRecord.getFootprint()
is None:
147 self.log.warning(
"Skipping object with ID %s that is off the image.", measRecord.getId())
148 self.
callMeasure(measRecord, exposure, refRecord, refWcs,
149 beginOrder=beginOrder, endOrder=endOrder)
151 periodicLog.log(
"Forced measurement complete for %d parents (and their children) out of %d",
152 index + 1, len(refCat))
155 """Attach Footprints to blank sources prior to measurement, by
156 creating elliptical Footprints from the PSF moments.
160 sources : `lsst.afw.table.SourceCatalog`
161 Blank catalog (with all rows and columns, but values other than
162 ``coord_ra``, ``coord_dec`` unpopulated).
163 to which footprints should be attached.
164 exposure : `lsst.afw.image.Exposure`
165 Image object from which peak values and the PSF are obtained.
166 scaling : `int`, optional
167 Scaling factor to apply to the PSF second-moments ellipse in order
168 to determine the footprint boundary.
170 psf = exposure.getPsf()
172 raise RuntimeError(
"Cannot construct Footprints from PSF shape without a PSF.")
173 bbox = exposure.getBBox()
174 wcs = exposure.getWcs()
177 x, y = wcs.skyToPixelArray(sources[
"coord_ra"], sources[
"coord_dec"], degrees=
False)
179 for idx, record
in enumerate(sources):
183 record.setFootprint(
None)
186 ellipse.getCore().scale(scaling)
189 footprint.addPeak(localIntPoint.getX(), localIntPoint.getY(),
190 exposure.image._get(localIntPoint, lsst.afw.image.PARENT))
191 record.setFootprint(footprint)
static std::shared_ptr< geom::SpanSet > fromShape(int r, Stencil s=Stencil::CIRCLE, lsst::geom::Point2I offset=lsst::geom::Point2I())
static Schema makeMinimalSchema()
addInvalidPsfFlag(self, schema)
initializePlugins(self, **kwds)
callMeasure(self, measRecord, *args, **kwds)
None run(self, lsst.afw.table.SourceCatalog refCat, lsst.afw.table.SourceCatalog measCat, lsst.afw.image.Exposure exposure, lsst.afw.geom.SkyWcs refWcs, int|None beginOrder=None, int|None endOrder=None)
_attachPsfShapeFootprints(self, sources, exposure, scaling=3)
__init__(self, refSchema, lsst.daf.base.PropertyList algMetadata=None, **kwds)