LSST Applications g04c3c9f7ca+2075667efa,g1e125bf412+5f448d5fcf,g2079a07aa2+3e9fd84d81,g2305ad1205+b635cf1488,g2bbee38e9b+6c6beb4891,g337abbeb29+6c6beb4891,g33d1c0ed96+6c6beb4891,g3a166c0a6a+6c6beb4891,g50ff169b8f+96c6868917,g52b1c1532d+585e252eca,g591dd9f2cf+42f171e1e6,g5c3423f6d4+d536b04327,g607f77f49a+d536b04327,g6f43f06aed+ca1339dc19,g858d7b2824+d536b04327,g8ee334c5b4+d7f9608c2f,g9963eaa53e+b3dc1655d3,g998f4353bf+d536b04327,g99cad8db69+8ef2408349,g9ddcbc5298+9a081db1e4,ga1e77700b3+2cbb763275,gadfd92a7e4+aec2f3b930,gae0086650b+585e252eca,gb0e22166c9+0e73c8378f,gb3b7280ab2+cb5fdb229e,gbb8dafda3b+a327199e22,gc120e1dc64+88074880ea,gc28159a63d+6c6beb4891,gcdd4ae20e8+bd241b2308,gcde1bda545+903e937d91,gcf0d15dbbd+bd241b2308,gdaeeff99f8+f9a426f77a,gddc38dedce+585e252eca,ge79ae78c31+6c6beb4891,gfbcc870c63+b310236976,w.2024.23
LSST Data Management Base Package
Loading...
Searching...
No Matches
Public Member Functions | Public Attributes | Static Public Attributes | List of all members
lsst.meas.base.forcedMeasurement.ForcedMeasurementTask Class Reference
Inheritance diagram for lsst.meas.base.forcedMeasurement.ForcedMeasurementTask:
lsst.meas.base.baseMeasurement.BaseMeasurementTask

Public Member Functions

 __init__ (self, refSchema, algMetadata=None, **kwds)
 
 run (self, measCat, exposure, refCat, refWcs, exposureId=None, beginOrder=None, endOrder=None)
 
 generateMeasCat (self, exposure, refCat, refWcs, idFactory=None)
 
 attachTransformedFootprints (self, sources, refCat, exposure, refWcs)
 
 attachPsfShapeFootprints (self, sources, exposure, scaling=3)
 

Public Attributes

 mapper
 
 schema
 
 algMetadata
 

Static Public Attributes

 ConfigClass = ForcedMeasurementConfig
 

Detailed Description

Measure sources on an image, constrained by a reference catalog.

A subtask for measuring the properties of sources on a single image,
using an existing "reference" catalog to constrain some aspects of the
measurement.

Parameters
----------
refSchema : `lsst.afw.table.Schema`
    Schema of the reference catalog.  Must match the catalog later passed
    to 'ForcedMeasurementTask.generateMeasCat` and/or
    `ForcedMeasurementTask.run`.
algMetadata : `lsst.daf.base.PropertyList` or `None`
    Will be updated in place to to record information about each
    algorithm. An empty `~lsst.daf.base.PropertyList` will be created if
    `None`.
**kwds
    Keyword arguments are passed to the supertask constructor.

Notes
-----
Note that while `SingleFrameMeasurementTask` is passed an initial
`~lsst.afw.table.Schema` that is appended to in order to create the output
`~lsst.afw.table.Schema`, `ForcedMeasurementTask` is initialized with the
`~lsst.afw.table.Schema` of the reference catalog, from which a new
`~lsst.afw.table.Schema` for the output catalog is created.  Fields to be
copied directly from the reference `~lsst.afw.table.Schema` are added
before ``Plugin`` fields are added.

Definition at line 215 of file forcedMeasurement.py.

Constructor & Destructor Documentation

◆ __init__()

lsst.meas.base.forcedMeasurement.ForcedMeasurementTask.__init__ ( self,
refSchema,
algMetadata = None,
** kwds )

Reimplemented from lsst.meas.base.baseMeasurement.BaseMeasurementTask.

Definition at line 248 of file forcedMeasurement.py.

248 def __init__(self, refSchema, algMetadata=None, **kwds):
249 super(ForcedMeasurementTask, self).__init__(algMetadata=algMetadata, **kwds)
250 self.mapper = lsst.afw.table.SchemaMapper(refSchema)
251 self.mapper.addMinimalSchema(lsst.afw.table.SourceTable.makeMinimalSchema(), False)
252 self.config.slots.setupSchema(self.mapper.editOutputSchema())
253 for refName, targetName in self.config.copyColumns.items():
254 refItem = refSchema.find(refName)
255 self.mapper.addMapping(refItem.key, targetName)
256 self.config.slots.setupSchema(self.mapper.editOutputSchema())
257 self.initializePlugins(schemaMapper=self.mapper)
258 self.schema = self.mapper.getOutputSchema()
259 self.schema.checkUnits(parse_strict=self.config.checkUnitsParseStrict)
260
A mapping between the keys of two Schemas, used to copy data between them.
static Schema makeMinimalSchema()
Return a minimal schema for Source tables and records.
Definition Source.h:258

Member Function Documentation

◆ attachPsfShapeFootprints()

lsst.meas.base.forcedMeasurement.ForcedMeasurementTask.attachPsfShapeFootprints ( self,
sources,
exposure,
scaling = 3 )
Attach Footprints to blank sources prior to measurement, by
creating elliptical Footprints from the PSF moments.

Parameters
----------
sources : `lsst.afw.table.SourceCatalog`
    Blank catalog (with all rows and columns, but values other than
    ``coord_ra``, ``coord_dec`` unpopulated).
    to which footprints should be attached.
exposure : `lsst.afw.image.Exposure`
    Image object from which peak values and the PSF are obtained.
scaling : `int`, optional
    Scaling factor to apply to the PSF second-moments ellipse in order
    to determine the footprint boundary.

Notes
-----
This is a utility function for use by parent tasks; see
`attachTransformedFootprints` for more information.

Definition at line 457 of file forcedMeasurement.py.

457 def attachPsfShapeFootprints(self, sources, exposure, scaling=3):
458 """Attach Footprints to blank sources prior to measurement, by
459 creating elliptical Footprints from the PSF moments.
460
461 Parameters
462 ----------
463 sources : `lsst.afw.table.SourceCatalog`
464 Blank catalog (with all rows and columns, but values other than
465 ``coord_ra``, ``coord_dec`` unpopulated).
466 to which footprints should be attached.
467 exposure : `lsst.afw.image.Exposure`
468 Image object from which peak values and the PSF are obtained.
469 scaling : `int`, optional
470 Scaling factor to apply to the PSF second-moments ellipse in order
471 to determine the footprint boundary.
472
473 Notes
474 -----
475 This is a utility function for use by parent tasks; see
476 `attachTransformedFootprints` for more information.
477 """
478 psf = exposure.getPsf()
479 if psf is None:
480 raise RuntimeError("Cannot construct Footprints from PSF shape without a PSF.")
481 bbox = exposure.getBBox()
482 wcs = exposure.getWcs()
483 for record in sources:
484 localPoint = wcs.skyToPixel(record.getCoord())
485 localIntPoint = lsst.geom.Point2I(localPoint)
486 assert bbox.contains(localIntPoint), (
487 f"Center for record {record.getId()} is not in exposure; this should be guaranteed by "
488 "generateMeasCat."
489 )
490 ellipse = lsst.afw.geom.ellipses.Ellipse(psf.computeShape(localPoint), localPoint)
491 ellipse.getCore().scale(scaling)
492 spans = lsst.afw.geom.SpanSet.fromShape(ellipse)
493 footprint = lsst.afw.detection.Footprint(spans.clippedTo(bbox), bbox)
494 footprint.addPeak(localIntPoint.getX(), localIntPoint.getY(),
495 exposure.image._get(localIntPoint, lsst.afw.image.PARENT))
496 record.setFootprint(footprint)
Class to describe the properties of a detected object from an image.
Definition Footprint.h:63
static std::shared_ptr< geom::SpanSet > fromShape(int r, Stencil s=Stencil::CIRCLE, lsst::geom::Point2I offset=lsst::geom::Point2I())
Factory function for creating SpanSets from a Stencil.
Definition SpanSet.cc:688
An ellipse defined by an arbitrary BaseCore and a center point.
Definition Ellipse.h:51

◆ attachTransformedFootprints()

lsst.meas.base.forcedMeasurement.ForcedMeasurementTask.attachTransformedFootprints ( self,
sources,
refCat,
exposure,
refWcs )
Attach Footprints to blank sources prior to measurement, by
transforming Footprints attached to the reference catalog.

Notes
-----
`~lsst.afw.detection.Footprint`\s for forced photometry must be in the
pixel coordinate system of the image being measured, while the actual
detections may start out in a different coordinate system. This
default implementation transforms the Footprints from the reference
catalog from the WCS to the exposure's WCS, which downgrades
``HeavyFootprint``\s into regular `~lsst.afw.detection.Footprint`\s,
destroying deblend information.

See the documentation for `run` for information about the
relationships between `run`, `generateMeasCat`, and
`attachTransformedFootprints`.

Definition at line 434 of file forcedMeasurement.py.

434 def attachTransformedFootprints(self, sources, refCat, exposure, refWcs):
435 r"""Attach Footprints to blank sources prior to measurement, by
436 transforming Footprints attached to the reference catalog.
437
438 Notes
439 -----
440 `~lsst.afw.detection.Footprint`\s for forced photometry must be in the
441 pixel coordinate system of the image being measured, while the actual
442 detections may start out in a different coordinate system. This
443 default implementation transforms the Footprints from the reference
444 catalog from the WCS to the exposure's WCS, which downgrades
445 ``HeavyFootprint``\s into regular `~lsst.afw.detection.Footprint`\s,
446 destroying deblend information.
447
448 See the documentation for `run` for information about the
449 relationships between `run`, `generateMeasCat`, and
450 `attachTransformedFootprints`.
451 """
452 exposureWcs = exposure.getWcs()
453 region = exposure.getBBox(lsst.afw.image.PARENT)
454 for srcRecord, refRecord in zip(sources, refCat):
455 srcRecord.setFootprint(refRecord.getFootprint().transform(refWcs, exposureWcs, region))
456

◆ generateMeasCat()

lsst.meas.base.forcedMeasurement.ForcedMeasurementTask.generateMeasCat ( self,
exposure,
refCat,
refWcs,
idFactory = None )
Initialize an output catalog from the reference catalog.

Parameters
----------
exposure : `lsst.afw.image.exposureF`
    Image to be measured.
refCat : iterable of `lsst.afw.table.SourceRecord`
    Catalog of reference sources.
refWcs : `lsst.afw.geom.SkyWcs`
    Defines the X,Y coordinate system of ``refCat``.
    This parameter is not currently used.
idFactory : `lsst.afw.table.IdFactory`, optional
    Factory for creating IDs for sources.

Returns
-------
meascat : `lsst.afw.table.SourceCatalog`
    Source catalog ready for measurement.

Notes
-----
This generates a new blank `~lsst.afw.table.SourceRecord` for each
record in ``refCat``. Note that this method does not attach any
`~lsst.afw.detection.Footprint`\ s.  Doing so is up to the caller (who
may call `attachedTransformedFootprints` or define their own method -
see `run` for more information).

Definition at line 394 of file forcedMeasurement.py.

394 def generateMeasCat(self, exposure, refCat, refWcs, idFactory=None):
395 r"""Initialize an output catalog from the reference catalog.
396
397 Parameters
398 ----------
399 exposure : `lsst.afw.image.exposureF`
400 Image to be measured.
401 refCat : iterable of `lsst.afw.table.SourceRecord`
402 Catalog of reference sources.
403 refWcs : `lsst.afw.geom.SkyWcs`
404 Defines the X,Y coordinate system of ``refCat``.
405 This parameter is not currently used.
406 idFactory : `lsst.afw.table.IdFactory`, optional
407 Factory for creating IDs for sources.
408
409 Returns
410 -------
411 meascat : `lsst.afw.table.SourceCatalog`
412 Source catalog ready for measurement.
413
414 Notes
415 -----
416 This generates a new blank `~lsst.afw.table.SourceRecord` for each
417 record in ``refCat``. Note that this method does not attach any
418 `~lsst.afw.detection.Footprint`\ s. Doing so is up to the caller (who
419 may call `attachedTransformedFootprints` or define their own method -
420 see `run` for more information).
421 """
422 if idFactory is None:
424 table = lsst.afw.table.SourceTable.make(self.schema, idFactory)
425 measCat = lsst.afw.table.SourceCatalog(table)
426 table = measCat.table
427 table.setMetadata(self.algMetadata)
428 table.preallocate(len(refCat))
429 for ref in refCat:
430 newSource = measCat.addNew()
431 newSource.assign(ref, self.mapper)
432 return measCat
433
static std::shared_ptr< IdFactory > makeSimple()
Return a simple IdFactory that simply counts from 1.
Definition IdFactory.cc:70
static std::shared_ptr< SourceTable > make(Schema const &schema, std::shared_ptr< IdFactory > const &idFactory)
Construct a new table.
Definition Source.cc:400

◆ run()

lsst.meas.base.forcedMeasurement.ForcedMeasurementTask.run ( self,
measCat,
exposure,
refCat,
refWcs,
exposureId = None,
beginOrder = None,
endOrder = None )
Perform forced measurement.

    Parameters
    ----------
    exposure : `lsst.afw.image.exposureF`
        Image to be measured. Must have at least a `lsst.afw.geom.SkyWcs`
        attached.
    measCat : `lsst.afw.table.SourceCatalog`
        Source catalog for measurement results; must be initialized with
        empty records already corresponding to those in ``refCat`` (via
        e.g. `generateMeasCat`).
    refCat : `lsst.afw.table.SourceCatalog`
        A sequence of `lsst.afw.table.SourceRecord` objects that provide
        reference information for the measurement.  These will be passed
        to each plugin in addition to the output
        `~lsst.afw.table.SourceRecord`.
    refWcs : `lsst.afw.geom.SkyWcs`
        Defines the X,Y coordinate system of ``refCat``.
    exposureId : `int`, optional
        Optional unique exposureId used to calculate random number
        generator seed in the NoiseReplacer.
    beginOrder : `int`, optional
        Beginning execution order (inclusive). Algorithms with
        ``executionOrder`` < ``beginOrder`` are not executed. `None` for no limit.
    endOrder : `int`, optional
        Ending execution order (exclusive). Algorithms with
        ``executionOrder`` >= ``endOrder`` are not executed. `None` for no limit.

    Notes
    -----
    Fills the initial empty `~lsst.afw.table.SourceCatalog` with forced
    measurement results.  Two steps must occur before `run` can be called:

    - `generateMeasCat` must be called to create the output ``measCat``
      argument.
    - `~lsst.afw.detection.Footprint`\ s appropriate for the forced sources
      must be attached to the ``measCat`` records. The
      `attachTransformedFootprints` method can be used to do this, but
      this degrades "heavy" (i.e., including pixel values)
      `~lsst.afw.detection.Footprint`\s to regular
      `~lsst.afw.detection.Footprint`\s, leading to non-deblended
      measurement, so most callers should provide
      `~lsst.afw.detection.Footprint`\s some other way. Typically, calling
      code will have access to information that will allow them to provide
      heavy footprints - for instance, `ForcedPhotCoaddTask` uses the
      heavy footprints from deblending run in the same band just before
      non-forced is run measurement in that band.

Definition at line 261 of file forcedMeasurement.py.

261 def run(self, measCat, exposure, refCat, refWcs, exposureId=None, beginOrder=None, endOrder=None):
262 r"""Perform forced measurement.
263
264 Parameters
265 ----------
266 exposure : `lsst.afw.image.exposureF`
267 Image to be measured. Must have at least a `lsst.afw.geom.SkyWcs`
268 attached.
269 measCat : `lsst.afw.table.SourceCatalog`
270 Source catalog for measurement results; must be initialized with
271 empty records already corresponding to those in ``refCat`` (via
272 e.g. `generateMeasCat`).
273 refCat : `lsst.afw.table.SourceCatalog`
274 A sequence of `lsst.afw.table.SourceRecord` objects that provide
275 reference information for the measurement. These will be passed
276 to each plugin in addition to the output
277 `~lsst.afw.table.SourceRecord`.
278 refWcs : `lsst.afw.geom.SkyWcs`
279 Defines the X,Y coordinate system of ``refCat``.
280 exposureId : `int`, optional
281 Optional unique exposureId used to calculate random number
282 generator seed in the NoiseReplacer.
283 beginOrder : `int`, optional
284 Beginning execution order (inclusive). Algorithms with
285 ``executionOrder`` < ``beginOrder`` are not executed. `None` for no limit.
286 endOrder : `int`, optional
287 Ending execution order (exclusive). Algorithms with
288 ``executionOrder`` >= ``endOrder`` are not executed. `None` for no limit.
289
290 Notes
291 -----
292 Fills the initial empty `~lsst.afw.table.SourceCatalog` with forced
293 measurement results. Two steps must occur before `run` can be called:
294
295 - `generateMeasCat` must be called to create the output ``measCat``
296 argument.
297 - `~lsst.afw.detection.Footprint`\ s appropriate for the forced sources
298 must be attached to the ``measCat`` records. The
299 `attachTransformedFootprints` method can be used to do this, but
300 this degrades "heavy" (i.e., including pixel values)
301 `~lsst.afw.detection.Footprint`\s to regular
302 `~lsst.afw.detection.Footprint`\s, leading to non-deblended
303 measurement, so most callers should provide
304 `~lsst.afw.detection.Footprint`\s some other way. Typically, calling
305 code will have access to information that will allow them to provide
306 heavy footprints - for instance, `ForcedPhotCoaddTask` uses the
307 heavy footprints from deblending run in the same band just before
308 non-forced is run measurement in that band.
309 """
310 # First check that the reference catalog does not contain any children
311 # for which any member of their parent chain is not within the list.
312 # This can occur at boundaries when the parent is outside and one of
313 # the children is within. Currently, the parent chain is always only
314 # one deep, but just in case, this code checks for any case where when
315 # the parent chain to a child's topmost parent is broken and raises an
316 # exception if it occurs.
317 #
318 # I.e. this code checks that this precondition is satisfied by
319 # whatever reference catalog provider is being paired with it.
320 refCatIdDict = {ref.getId(): ref.getParent() for ref in refCat}
321 for ref in refCat:
322 refId = ref.getId()
323 topId = refId
324 while topId > 0:
325 if topId not in refCatIdDict:
326 raise RuntimeError("Reference catalog contains a child for which at least "
327 "one parent in its parent chain is not in the catalog.")
328 topId = refCatIdDict[topId]
329
330 # Construct a footprints dict which looks like
331 # {ref.getId(): (ref.getParent(), source.getFootprint())}
332 # (i.e. getting the footprint from the transformed source footprint)
333 footprints = {ref.getId(): (ref.getParent(), measRecord.getFootprint())
334 for (ref, measRecord) in zip(refCat, measCat)}
335
336 self.log.info("Performing forced measurement on %d source%s", len(refCat),
337 "" if len(refCat) == 1 else "s")
338
339 # Wrap the task logger into a periodic logger.
340 periodicLog = PeriodicLogger(self.log)
341
342 if self.config.doReplaceWithNoise:
343 noiseReplacer = NoiseReplacer(self.config.noiseReplacer, exposure,
344 footprints, log=self.log, exposureId=exposureId)
345 algMetadata = measCat.getTable().getMetadata()
346 if algMetadata is not None:
347 algMetadata.addInt("NOISE_SEED_MULTIPLIER", self.config.noiseReplacer.noiseSeedMultiplier)
348 algMetadata.addString("NOISE_SOURCE", self.config.noiseReplacer.noiseSource)
349 algMetadata.addDouble("NOISE_OFFSET", self.config.noiseReplacer.noiseOffset)
350 if exposureId is not None:
351 algMetadata.addLong("NOISE_EXPOSURE_ID", exposureId)
352 else:
353 noiseReplacer = DummyNoiseReplacer()
354
355 # Create parent cat which slices both the refCat and measCat (sources)
356 # first, get the reference and source records which have no parent
357 refParentCat, measParentCat = refCat.getChildren(0, measCat)
358 childrenIter = refCat.getChildren((refParentRecord.getId() for refParentRecord in refCat), measCat)
359 for parentIdx, records in enumerate(zip(refParentCat, measParentCat, childrenIter)):
360 # Unpack records
361 refParentRecord, measParentRecord, (refChildCat, measChildCat) = records
362 # First process the records which have the current parent as children
363 # TODO: skip this loop if there are no plugins configured for single-object mode
364 for refChildRecord, measChildRecord in zip(refChildCat, measChildCat):
365 noiseReplacer.insertSource(refChildRecord.getId())
366 self.callMeasure(measChildRecord, exposure, refChildRecord, refWcs,
367 beginOrder=beginOrder, endOrder=endOrder)
368 noiseReplacer.removeSource(refChildRecord.getId())
369
370 # Then process the parent record
371 noiseReplacer.insertSource(refParentRecord.getId())
372 self.callMeasure(measParentRecord, exposure, refParentRecord, refWcs,
373 beginOrder=beginOrder, endOrder=endOrder)
374 self.callMeasureN(measParentCat[parentIdx:parentIdx+1], exposure,
375 refParentCat[parentIdx:parentIdx+1],
376 beginOrder=beginOrder, endOrder=endOrder)
377 # Measure all the children simultaneously
378 self.callMeasureN(measChildCat, exposure, refChildCat,
379 beginOrder=beginOrder, endOrder=endOrder)
380 noiseReplacer.removeSource(refParentRecord.getId())
381 # Log a message if it has been a while since the last log.
382 periodicLog.log("Forced measurement complete for %d parents (and their children) out of %d",
383 parentIdx + 1, len(refParentCat))
384 noiseReplacer.end()
385
386 # Undeblended plugins only fire if we're running everything
387 if endOrder is None:
388 for recordIndex, (measRecord, refRecord) in enumerate(zip(measCat, refCat)):
389 for plugin in self.undeblendedPlugins.iter():
390 self.doMeasurement(plugin, measRecord, exposure, refRecord, refWcs)
391 periodicLog.log("Undeblended forced measurement complete for %d sources out of %d",
392 recordIndex + 1, len(refCat))
393

Member Data Documentation

◆ algMetadata

lsst.meas.base.forcedMeasurement.ForcedMeasurementTask.algMetadata

Definition at line 427 of file forcedMeasurement.py.

◆ ConfigClass

lsst.meas.base.forcedMeasurement.ForcedMeasurementTask.ConfigClass = ForcedMeasurementConfig
static

Definition at line 246 of file forcedMeasurement.py.

◆ mapper

lsst.meas.base.forcedMeasurement.ForcedMeasurementTask.mapper

Definition at line 250 of file forcedMeasurement.py.

◆ schema

lsst.meas.base.forcedMeasurement.ForcedMeasurementTask.schema

Definition at line 258 of file forcedMeasurement.py.


The documentation for this class was generated from the following file: