LSST Applications g00274db5b6+edbf708997,g00d0e8bbd7+edbf708997,g199a45376c+5137f08352,g1fd858c14a+1d4b6db739,g262e1987ae+f4d9505c4f,g29ae962dfc+7156fb1a53,g2cef7863aa+73c82f25e4,g35bb328faa+edbf708997,g3e17d7035e+5b3adc59f5,g3fd5ace14f+852fa6fbcb,g47891489e3+6dc8069a4c,g53246c7159+edbf708997,g64539dfbff+9f17e571f4,g67b6fd64d1+6dc8069a4c,g74acd417e5+ae494d68d9,g786e29fd12+af89c03590,g7ae74a0b1c+a25e60b391,g7aefaa3e3d+536efcc10a,g7cc15d900a+d121454f8d,g87389fa792+a4172ec7da,g89139ef638+6dc8069a4c,g8d7436a09f+28c28d8d6d,g8ea07a8fe4+db21c37724,g92c671f44c+9f17e571f4,g98df359435+b2e6376b13,g99af87f6a8+b0f4ad7b8d,gac66b60396+966efe6077,gb88ae4c679+7dec8f19df,gbaa8f7a6c5+38b34f4976,gbf99507273+edbf708997,gc24b5d6ed1+9f17e571f4,gca7fc764a6+6dc8069a4c,gcc769fe2a4+97d0256649,gd7ef33dd92+6dc8069a4c,gdab6d2f7ff+ae494d68d9,gdbb4c4dda9+9f17e571f4,ge410e46f29+6dc8069a4c,geaed405ab2+e194be0d2b,w.2025.47
LSST Data Management Base Package
Loading...
Searching...
No Matches
sfm.py
Go to the documentation of this file.
1# This file is part of meas_base.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://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 <https://www.gnu.org/licenses/>.
21
22r"""Base classes for single-frame measurement plugins and the associated task.
23
24In single-frame measurement, we assume that detection and probably deblending
25have already been run on the same frame, so a `~lsst.afw.table.SourceCatalog`
26has already been created with `lsst.afw.detection.Footprint`\ s (which may be
27"heavy" — that is, include pixel data). Measurements are generally recorded in
28the coordinate system of the image being measured (and all slot-eligible
29fields must be), but non-slot fields may be recorded in other coordinate
30systems if necessary to avoid information loss (this should, of course, be
31indicated in the field documentation).
32"""
33
34from lsst.utils.logging import PeriodicLogger
35from lsst.utils.timer import timeMethod
36
37from .pluginRegistry import PluginRegistry
38from .baseMeasurement import (BaseMeasurementPluginConfig, BaseMeasurementPlugin,
39 BaseMeasurementConfig, BaseMeasurementTask)
40
41__all__ = ("SingleFramePluginConfig", "SingleFramePlugin",
42 "SingleFrameMeasurementConfig", "SingleFrameMeasurementTask")
43
44
46 """Base class for single-frame plugin configuration classes.
47 """
48 pass
49
50
52 """Base class for single-frame measurement plugin.
53
54 Parameters
55 ----------
56 config : `SingleFramePlugin.ConfigClass`
57 Configuration for this plugin.
58 name : `str`
59 The string with which the plugin was registered.
60 schema : `lsst.afw.table.Schema`
61 The schema for the source table . New fields are added here to
62 hold measurements produced by this plugin.
63 metadata : `lsst.daf.base.PropertySet`
64 Plugin metadata that will be attached to the output catalog
65 logName : `str`, optional
66 Name to use when logging errors.
67
68 Notes
69 -----
70 New plugins can be created in Python by inheriting directly from this
71 class and implementing the `measure`, `fail` (from `BasePlugin`), and
72 optionally `__init__` and `measureN` methods. Plugins can also be defined
73 in C++ via the `WrappedSingleFramePlugin` class.
74 """
75
76 registry = PluginRegistry(SingleFramePluginConfig)
77 """Registry of subclasses of `SingleFramePlugin` (`PluginRegistry`).
78 """
79
80 ConfigClass = SingleFramePluginConfig
81
82 def __init__(self, config, name, schema, metadata, logName=None, **kwds):
83 BaseMeasurementPlugin.__init__(self, config, name, logName=logName)
84
85 def measure(self, measRecord, exposure):
86 """Measure the properties of a source on a single image.
87
88 The image may be from a single epoch, or it may be a coadd.
89
90 Parameters
91 ----------
92 measRecord : `lsst.afw.table.SourceRecord`
93 Record describing the object being measured. Previously-measured
94 quantities may be retrieved from here, and it will be updated
95 in-place tih the outputs of this plugin.
96 exposure : `lsst.afw.image.ExposureF`
97 The pixel data to be measured, together with the associated PSF,
98 WCS, etc. All other sources in the image should have been replaced
99 by noise according to deblender outputs.
100 """
101 raise NotImplementedError()
102
103
105 """Config class for single frame measurement driver task.
106 """
107
108 plugins = SingleFramePlugin.registry.makeField(
109 multi=True,
110 default=["base_PixelFlags",
111 "base_SdssCentroid",
112 "base_SdssShape",
113 "base_GaussianFlux",
114 "base_PsfFlux",
115 "base_CircularApertureFlux",
116 "base_SkyCoord",
117 "base_Variance",
118 "base_Blendedness",
119 "base_LocalBackground",
120 "base_CompensatedTophatFlux",
121 "base_ClassificationSizeExtendedness",
122 ],
123 doc="Plugins to be run and their configuration"
124 )
125 algorithms = property(lambda self: self.plugins, doc="backwards-compatibility alias for plugins")
126 undeblended = SingleFramePlugin.registry.makeField(
127 multi=True,
128 default=[],
129 doc="Plugins to run on undeblended image"
130 )
131
132
134 """A subtask for measuring the properties of sources on a single exposure.
135
136 Parameters
137 ----------
138 schema : `lsst.afw.table.Schema`
139 Schema of the output resultant catalog. Will be updated to provide
140 fields to accept the outputs of plugins which will be executed by this
141 task.
142 algMetadata : `lsst.daf.base.PropertyList`, optional
143 Used to record metadaa about algorithm execution. An empty
144 `lsst.daf.base.PropertyList` will be created if `None`.
145 **kwds
146 Keyword arguments forwarded to `BaseMeasurementTask`.
147 """
148
149 ConfigClass = SingleFrameMeasurementConfig
150
151 def __init__(self, schema, algMetadata=None, **kwds):
152 super(SingleFrameMeasurementTask, self).__init__(algMetadata=algMetadata, **kwds)
153 self.schema = schema
154 self.config.slots.setupSchema(self.schema)
155 self.initializePlugins(schema=self.schema)
156 self.addInvalidPsfFlag(self.schema)
157
158 # Check to see if blendedness is one of the plugins
159 if 'base_Blendedness' in self.plugins:
160 self.doBlendedness = True
161 self.blendPlugin = self.plugins['base_Blendedness']
162 else:
163 self.doBlendedness = False
164
165 @timeMethod
166 def run(
167 self,
168 measCat,
169 exposure,
170 noiseImage=None,
171 exposureId=None,
172 beginOrder=None,
173 endOrder=None,
174 footprints=None,
175 ):
176 r"""Run single frame measurement over an exposure and source catalog.
177
178 Parameters
179 ----------
180 measCat : `lsst.afw.table.SourceCatalog`
181 Catalog to be filled with the results of measurement. Must contain
182 all the `lsst.afw.table.SourceRecord`\ s to be measured (with
183 `lsst.afw.detection.Footprint`\ s attached), and have a schema
184 that is a superset of ``self.schema``.
185 exposure : `lsst.afw.image.ExposureF`
186 Image containing the pixel data to be measured together with
187 associated PSF, WCS, etc.
188 noiseImage : `lsst.afw.image.ImageF`, optional
189 Can be used to specify the a predictable noise replacement field
190 for testing purposes.
191 exposureId : `int`, optional
192 Unique exposure identifier used to calculate the random number
193 generator seed during noise replacement.
194 beginOrder : `float`, optional
195 Start execution order (inclusive): measurements with
196 ``executionOrder < beginOrder`` are not executed. `None` for no
197 limit.
198 endOrder : `float`, optional
199 Final execution order (exclusive): measurements with
200 ``executionOrder >= endOrder`` are not executed. `None` for no
201 limit.
202 footprints : `dict` {`int`: `lsst.afw.detection.Footprint`}, optional
203 List of footprints to use for noise replacement. If this is not
204 supplied then the footprints from the measCat are used.
205 """
206 assert measCat.getSchema().contains(self.schema)
207 if footprints is None:
208 footprints = self.getFootprintsFromCatalog(measCat)
209
210 # noiseReplacer is used to fill the footprints with noise and save
211 # heavy footprints of the source pixels so that they can be restored
212 # one at a time for measurement. After the NoiseReplacer is
213 # constructed, all pixels in the exposure.getMaskedImage() which
214 # belong to objects in measCat will be replaced with noise
215
216 # Initialize the noise replacer
217 noiseReplacer = self.initNoiseReplacer(exposure, measCat, footprints, exposureId, noiseImage)
218
219 self.runPlugins(noiseReplacer, measCat, exposure, beginOrder, endOrder)
220
222 self,
223 noiseReplacer,
224 measCat,
225 exposure,
226 beginOrder=None,
227 endOrder=None,
228 ):
229 r"""Call the configured measument plugins on an image.
230
231 Parameters
232 ----------
233 noiseReplacer : `NoiseReplacer`
234 Used to fill sources not being measured with noise.
235 measCat : `lsst.afw.table.SourceCatalog`
236 Catalog to be filled with the results of measurement. Must contain
237 all the `lsst.afw.table.SourceRecord`\ s to be measured (with
238 `lsst.afw.detection.Footprint`\ s attached), and have a schema
239 that is a superset of ``self.schema``.
240 exposure : `lsst.afw.image.ExposureF`
241 Image containing the pixel data to be measured together with
242 associated PSF, WCS, etc.
243 beginOrder : `float`, optional
244 Start execution order (inclusive): measurements with
245 ``executionOrder < beginOrder`` are not executed. `None` for no
246 limit.
247 endOrder : `float`, optional
248 Final execution order (exclusive): measurements with
249 ``executionOrder >= endOrder`` are not executed. `None` for no
250 limit.
251 """
252 nMeasCat = len(measCat)
253 self.log.info("Measuring %d source%s", nMeasCat, ("" if nMeasCat == 1 else "s"))
254
255 # Wrap the task logger into a period logger
256 periodicLog = PeriodicLogger(self.log)
257
258 for recordIndex, measRecord in enumerate(measCat):
259 noiseReplacer.insertSource(measRecord.getId())
260 self.callMeasure(measRecord, exposure, beginOrder=beginOrder, endOrder=endOrder)
261
262 if self.doBlendedness:
263 self.blendPlugin.cpp.measureChildPixels(exposure.getMaskedImage(), measRecord)
264
265 noiseReplacer.removeSource(measRecord.getId())
266 # Log a message if it has been a while since the last log.
267 periodicLog.log("Measurement complete for %d sources out of %d", recordIndex + 1, nMeasCat)
268
269 # When done, restore the exposure to its original state
270 noiseReplacer.end()
271
272 # Undeblended plugins only fire if we're running everything
273 if endOrder is None:
274 for sourceIndex, source in enumerate(measCat):
275 for plugin in self.undeblendedPlugins.iter():
276 self.doMeasurement(plugin, source, exposure)
277 # Log a message if it has been a while since the last log.
278 periodicLog.log("Undeblended measurement complete for %d sources out of %d",
279 sourceIndex + 1, nMeasCat)
280
281 # Now we loop over all of the sources one more time to compute the
282 # blendedness metrics
283 if self.doBlendedness:
284 for source in measCat:
285 self.blendPlugin.cpp.measureParentPixels(exposure.getMaskedImage(), source)
286
287 def measure(self, measCat, exposure):
288 """Backwards-compatibility alias for `run`.
289 """
290 self.run(measCat, exposure)
initNoiseReplacer(self, exposure, measCat, footprints, exposureId=None, noiseImage=None)
doMeasurement(self, plugin, measRecord, *args, **kwds)
__init__(self, schema, algMetadata=None, **kwds)
Definition sfm.py:151
runPlugins(self, noiseReplacer, measCat, exposure, beginOrder=None, endOrder=None)
Definition sfm.py:228
run(self, measCat, exposure, noiseImage=None, exposureId=None, beginOrder=None, endOrder=None, footprints=None)
Definition sfm.py:175
measure(self, measRecord, exposure)
Definition sfm.py:85
__init__(self, config, name, schema, metadata, logName=None, **kwds)
Definition sfm.py:82