261 def run(self, measCat, exposure, refCat, refWcs, exposureId=None, beginOrder=None, endOrder=None):
262 r"""Perform forced measurement.
266 exposure : `lsst.afw.image.exposureF`
267 Image to be measured. Must have at least a `lsst.afw.geom.SkyWcs`
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.
292 Fills the initial empty `~lsst.afw.table.SourceCatalog` with forced
293 measurement results. Two steps must occur before `run` can be called:
295 - `generateMeasCat` must be called to create the output ``measCat``
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.
320 refCatIdDict = {ref.getId(): ref.getParent()
for ref
in refCat}
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]
333 footprints = {ref.getId(): (ref.getParent(), measRecord.getFootprint())
334 for (ref, measRecord)
in zip(refCat, measCat)}
336 self.log.info(
"Performing forced measurement on %d source%s", len(refCat),
337 "" if len(refCat) == 1
else "s")
340 periodicLog = PeriodicLogger(self.log)
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)
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)):
361 refParentRecord, measParentRecord, (refChildCat, measChildCat) = records
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())
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)
379 beginOrder=beginOrder, endOrder=endOrder)
380 noiseReplacer.removeSource(refParentRecord.getId())
382 periodicLog.log(
"Forced measurement complete for %d parents (and their children) out of %d",
383 parentIdx + 1, len(refParentCat))
388 for recordIndex, (measRecord, refRecord)
in enumerate(zip(measCat, refCat)):
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))
458 """Attach Footprints to blank sources prior to measurement, by
459 creating elliptical Footprints from the PSF moments.
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.
475 This is a utility function for use by parent tasks; see
476 `attachTransformedFootprints` for more information.
478 psf = exposure.getPsf()
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())
486 assert bbox.contains(localIntPoint), (
487 f
"Center for record {record.getId()} is not in exposure; this should be guaranteed by "
491 ellipse.getCore().scale(scaling)
494 footprint.addPeak(localIntPoint.getX(), localIntPoint.getY(),
495 exposure.image._get(localIntPoint, lsst.afw.image.PARENT))
496 record.setFootprint(footprint)