Measurement of Sources, specifically ones from difference images, for characterization as dipoles.
More...
Measurement of Sources, specifically ones from difference images, for characterization as dipoles.
Contents
#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Description
This class provides a default configuration for running Source measurement on image differences.
These default plugins include:
class DipoleMeasurementConfig(SingleFrameMeasurementConfig):
"""!Measurement of detected diaSources as dipoles"""
def setDefaults(self):
SingleFrameMeasurementConfig.setDefaults(self)
self.plugins = ["base_CircularApertureFlux",
"base_PixelFlags",
"base_SkyCoord",
"base_PsfFlux",
"ip_diffim_NaiveDipoleCentroid",
"ip_diffim_NaiveDipoleFlux",
"ip_diffim_PsfDipoleFlux",
"ip_diffim_ClassificationDipole",
]
self.slots.calibFlux = None
self.slots.modelFlux = None
self.slots.gaussianFlux = None
self.slots.shape = None
self.slots.centroid = "ip_diffim_NaiveDipoleCentroid"
self.doReplaceWithNoise = False
These plugins enabled by default allow the user to test the hypothesis that the Source is a dipole. This includes a set of measurements derived from intermediate base classes DipoleCentroidAlgorithm and DipoleFluxAlgorithm. Their respective algorithm control classes are defined in DipoleCentroidControl and DipoleFluxControl. Each centroid and flux measurement will have _neg (negative) and _pos (positive lobe) fields.
The first set of measurements uses a "naive" alrogithm for centroid and flux measurements, implemented in NaiveDipoleCentroidControl and NaiveDipoleFluxControl. The algorithm uses a naive 3x3 weighted moment around the nominal centroids of each peak in the Source Footprint. These algorithms fill the table fields ip_diffim_NaiveDipoleCentroid* and ip_diffim_NaiveDipoleFlux*
The second set of measurements undertakes a joint-Psf model on the negative and positive lobe simultaneously. This fit simultaneously solves for the negative and positive lobe centroids and fluxes using non-linear least squares minimization. The fields are stored in table elements ip_diffim_PsfDipoleFlux*.
Because this Task is just a config for SourceMeasurementTask, the same result may be acheived by manually editing the config and running SourceMeasurementTask. For example:
config = SingleFrameMeasurementConfig()
config.plugins.names = ["base_PsfFlux",
"ip_diffim_PsfDipoleFlux",
"ip_diffim_NaiveDipoleFlux",
"ip_diffim_NaiveDipoleCentroid",
"ip_diffim_ClassificationDipole",
"base_CircularApertureFlux",
"base_SkyCoord"]
config.slots.calibFlux = None
config.slots.modelFlux = None
config.slots.gaussianFlux = None
config.slots.shape = None
config.slots.centroid = "ip_diffim_NaiveDipoleCentroid"
config.doReplaceWithNoise = False
schema = afwTable.SourceTable.makeMinimalSchema()
task = SingleFrameMeasurementTask(schema, config=config)
task.run(sources, exposure)
#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Task initialization
#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Invoking the Task
#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Configuration parameters
See DipoleMeasurementConfig
#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Quantities set in Metadata
No specific values are set in the Task metadata. However, the Source schema are modified to store the results of the dipole-specific measurements.
#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Debug variables
The command line task interface supports a flag -d/–debug
to import debug.py from your PYTHONPATH
. The relevant contents of debug.py for this Task include:
import sys
import lsstDebug
def DebugInfo(name):
if name == "lsst.ip.diffim.dipoleMeasurement":
di.display = True
di.maskTransparency = 90
di.displayDiaSources = True
return di
lsstDebug.frame = 1
#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
A complete example of using DipoleMeasurementTask
This code is dipoleMeasTask.py in the examples directory, and can be run as e.g.
examples/dipoleMeasTask.py
examples/dipoleMeasTask.py --debug
examples/dipoleMeasTask.py --debug --image /path/to/image.fits
Start the processing by parsing the command line, where the user has the option of enabling debugging output and/or sending their own image for demonstration (in case they have not downloaded the afwdata package).
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(
description="Demonstrate the use of SourceDetectionTask and DipoleMeasurementTask")
parser.add_argument('--debug', '-d', action="store_true", help="Load debug.py?", default=False)
parser.add_argument("--image", "-i", help="User defined image", default=None)
args = parser.parse_args()
if args.debug:
try:
import debug
debug.lsstDebug.frame = 2
except ImportError as e:
print(e, file=sys.stderr)
run(args)
The processing occurs in the run function. We first extract an exposure from disk or afwdata, displaying it if requested:
def run(args):
exposure = loadData(args.image)
if args.debug:
ds9.mtv(exposure, frame=1)
Create a default source schema that we will append fields to as we add more algorithms:
schema = afwTable.SourceTable.makeMinimalSchema()
Create the detection and measurement Tasks, with some minor tweaking of their configs:
config = SourceDetectionTask.ConfigClass()
config.thresholdPolarity = "both"
config.background.isNanSafe = True
config.thresholdValue = 3
detectionTask = SourceDetectionTask(config=config, schema=schema)
config = DipoleMeasurementTask.ConfigClass()
config.plugins.names.remove('base_SkyCoord')
algMetadata = dafBase.PropertyList()
measureTask = DipoleMeasurementTask(schema, algMetadata, config=config)
Having fully initialied the schema, we create a Source table from it:
tab = afwTable.SourceTable.make(schema)
Run detection:
results = detectionTask.run(tab, exposure)
Because we are looking for dipoles, we need to merge the positive and negative detections:
fpSet = results.fpSets.positive
growFootprint = 2
fpSet.merge(results.fpSets.negative, growFootprint, growFootprint, False)
diaSources = afwTable.SourceCatalog(tab)
fpSet.makeSources(diaSources)
print("Merged %s Sources into %d diaSources (from %d +ve, %d -ve)" % (len(results.sources),
len(diaSources),
results.fpSets.numPos,
results.fpSets.numNeg))
Finally, perform measurement (both standard and dipole-specialized) on the merged sources:
measureTask.run(diaSources, exposure)
Optionally display debugging information:
if args.debug:
dpa = DipoleAnalysis()
dpa.displayDipoles(exposure, diaSources)
#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Definition at line 127 of file dipoleMeasurement.py.