lsst.pipe.tasks g15e86a050b+c4ce65ff94
Loading...
Searching...
No Matches
lsst.pipe.tasks.matchDiffimSourceInjected Namespace Reference

Classes

class  MatchInjectedToDiaSourceConnections
 

Variables

 injectionCat : `astropy.table.Table`
 
 diffIm : `lsst.afw.image.Exposure`
 
 diaSources : `afw.table.SourceCatalog`
 
 result : `lsst.pipe.base.Struct`
 
 injectedCat : `astropy.table.Table`
 
 ras : `numpy.ndarray`, (N,)
 
 decs : `numpy.ndarray`, (N,)
 
 vectors : `numpy.ndarray`, (N, 3)
 
 fakeCat : `astropy.table.table.Table`
 
 image : `lsst.afw.image.exposure.exposure.ExposureF`
 
 initialFakeCat : `astropy.table.table.Table`
 
 variableDoublesFakeCat : `astropy.table.table.Table`
 
 matchedFakes : `astropy.table.table.Table`
 
 fullMatchedFakes : `astropy.table.table.Table`
 
 matchDiaSources : `astropy.table.Table`
 
 assocDiaSources : `astropy.table.Table`
 

Variable Documentation

◆ assocDiaSources

lsst.pipe.tasks.matchDiffimSourceInjected.assocDiaSources : `astropy.table.Table`

Definition at line 493 of file matchDiffimSourceInjected.py.

◆ decs

lsst.pipe.tasks.matchDiffimSourceInjected.decs : `numpy.ndarray`, (N,)

Definition at line 292 of file matchDiffimSourceInjected.py.

◆ diaSources

lsst.pipe.tasks.matchDiffimSourceInjected.diaSources : `afw.table.SourceCatalog`

Definition at line 123 of file matchDiffimSourceInjected.py.

◆ diffIm

lsst.pipe.tasks.matchDiffimSourceInjected.diffIm : `lsst.afw.image.Exposure`

Definition at line 121 of file matchDiffimSourceInjected.py.

◆ fakeCat

lsst.pipe.tasks.matchDiffimSourceInjected.fakeCat : `astropy.table.table.Table`
vectors = np.empty((len(ras), 3))

vectors[:, 2] = np.sin(decs)
vectors[:, 0] = np.cos(decs) * np.cos(ras)
vectors[:, 1] = np.cos(decs) * np.sin(ras)

return vectors

def _addPixCoords(self, fakeCat, image):
wcs = image.getWcs()

# Get x/y pixel coordinates for injected sources.
xs, ys = wcs.skyToPixelArray(
    fakeCat["ra"],
    fakeCat["dec"],
    degrees=True
)
fakeCat["x"] = xs
fakeCat["y"] = ys

return fakeCat

def _trimFakeCat(self, fakeCat, image):
# fakeCat must be processed with _addPixCoords before trimming
fakeCat = self._addPixCoords(fakeCat, image)

# Prefilter in ra/dec to avoid cases where the wcs incorrectly maps
# input fakes which are really off the chip onto it.
ras = fakeCat["ra"] * u.deg
decs = fakeCat["dec"] * u.deg

isContainedRaDec = image.containsSkyCoords(ras, decs, padding=0)

# now use the exact pixel BBox to filter to only fakes that were inserted
xs = fakeCat["x"]
ys = fakeCat["y"]

bbox = lsstGeom.Box2D(image.getBBox())
isContainedXy = xs - self.config.trimBuffer >= bbox.minX
isContainedXy &= xs + self.config.trimBuffer <= bbox.maxX
isContainedXy &= ys - self.config.trimBuffer >= bbox.minY
isContainedXy &= ys + self.config.trimBuffer <= bbox.maxY

return fakeCat[isContainedRaDec & isContainedXy]

def _splitVariables(self, fakeCat):

Definition at line 313 of file matchDiffimSourceInjected.py.

◆ fullMatchedFakes

lsst.pipe.tasks.matchDiffimSourceInjected.fullMatchedFakes : `astropy.table.table.Table`

Definition at line 409 of file matchDiffimSourceInjected.py.

◆ image

lsst.pipe.tasks.matchDiffimSourceInjected.image : `lsst.afw.image.exposure.exposure.ExposureF`

Definition at line 315 of file matchDiffimSourceInjected.py.

◆ initialFakeCat

lsst.pipe.tasks.matchDiffimSourceInjected.initialFakeCat : `astropy.table.table.Table`

Definition at line 383 of file matchDiffimSourceInjected.py.

◆ injectedCat

lsst.pipe.tasks.matchDiffimSourceInjected.injectedCat : `astropy.table.Table`
# Create a schema for the forced measurement task
schema = afwTable.SourceTable.makeMinimalSchema()
schema.addField("x", "D", "x position in image.", units="pixel")
schema.addField("y", "D", "y position in image.", units="pixel")
schema.addField("deblend_nChild", "I", "Need for minimal forced phot schema")

pluginList = [
    "base_PixelFlags",
    "base_SdssCentroid",
    "base_CircularApertureFlux",
    "base_PsfFlux",
    "base_LocalBackground"
]
forcedMeasConfig = ForcedMeasurementConfig(plugins=pluginList)
forcedMeasConfig.slots.centroid = 'base_SdssCentroid'
forcedMeasConfig.slots.shape = None

# Create the forced measurement task
forcedMeas = ForcedMeasurementTask(schema, config=forcedMeasConfig)

# Specify the columns to copy from the input catalog to the output catalog
forcedMeas.copyColumns = {"coord_ra": "ra", "coord_dec": "dec"}

# Create an afw table from the input catalog
outputCatalog = afwTable.SourceCatalog(schema)
outputCatalog.reserve(len(injectionCat))
for row in injectionCat:
    outputRecord = outputCatalog.addNew()
    outputRecord.setId(row['injection_id'])
    outputRecord.setCoord(lsstGeom.SpherePoint(row["ra"], row["dec"], lsstGeom.degrees))
    outputRecord.set("x", row["x"])
    outputRecord.set("y", row["y"])

# Generate the forced measurement catalog
forcedSources = forcedMeas.generateMeasCat(diffIm, outputCatalog, diffIm.getWcs())
# Attach the PSF shape footprints to the forced measurement catalog
forcedMeas.attachPsfShapeFootprints(forcedSources, diffIm)

# Copy the x and y positions from the forced measurement catalog back
# to the input catalog
for src, tgt in zip(forcedSources, outputCatalog):
    src.set('base_SdssCentroid_x', tgt['x'])
    src.set('base_SdssCentroid_y', tgt['y'])

# Define the centroid for the forced measurement catalog
forcedSources.defineCentroid('base_SdssCentroid')
# Run the forced measurement task
forcedMeas.run(forcedSources, diffIm, outputCatalog, diffIm.getWcs())
# Convert the forced measurement catalog to an astropy table
forcedSources_table = forcedSources.asAstropy()

# Add the forced measurement columns to the input catalog
for column in forcedSources_table.columns:
    if "Flux" in column or "flag" in column:
        injectionCat["forced_"+column] = forcedSources_table[column]

# Add the SNR columns to the input catalog
for column in injectionCat.colnames:
    if column.endswith("instFlux"):
        flux = np.abs(injectionCat[column])
        fluxErr = injectionCat[column+"Err"].copy()
        fluxErr = np.where(
            (fluxErr <= 0) | (np.isnan(fluxErr)), np.nanmax(fluxErr), fluxErr)

        injectionCat[column+"_SNR"] = flux / fluxErr

def _processFakes(self, injectedCat, diaSources):

Definition at line 233 of file matchDiffimSourceInjected.py.

◆ injectionCat

lsst.pipe.tasks.matchDiffimSourceInjected.injectionCat : `astropy.table.Table`
matchDistanceArcseconds = pexConfig.RangeField(
    doc="Distance in arcseconds to match within.",
    dtype=float,
    default=0.5,
    min=0,
    max=10,
)
doMatchVisit = pexConfig.Field(
    dtype=bool,
    default=True,
    doc="Match visit to trim the fakeCat"
)
trimBuffer = pexConfig.Field(
    doc="Size of the pixel buffer surrounding the image."
        "Only those fake sources with a centroid"
        "falling within the image+buffer region will be considered matches.",
    dtype=int,
    default=50,
)
doForcedMeasurement = pexConfig.Field(
    dtype=bool,
    default=True,
    doc="Force measurement of the fakes at the injection locations."
)
forcedMeasurement = pexConfig.ConfigurableField(
    target=ForcedMeasurementTask,
    doc="Task to force photometer difference image at injection locations.",
)


class MatchInjectedToDiaSourceTask(PipelineTask):

_DefaultName = "matchInjectedToDiaSource"
ConfigClass = MatchInjectedToDiaSourceConfig

def run(self, injectionCat, diffIm, diaSources):
if self.config.doMatchVisit:
    fakeCat = self._trimFakeCat(injectionCat, diffIm)
else:
    fakeCat = injectionCat
if self.config.doForcedMeasurement:
    self._estimateFakesSNR(fakeCat, diffIm)

# Split the fake catalog into the initial injections and the variable sources themselves,
# which are generated as duplicates of the initial injections with a twin_id column.
# We then match only the initial injections to the diaSources,
# and then add back in the variable sources by matching them to their twins
initialFakeCat, variableDoublesFakeCat = self._splitVariables(fakeCat)
matchedFakes = self._processFakes(initialFakeCat, diaSources)
fullMatchedFakes = self._add_variables_to_matched(matchedFakes, variableDoublesFakeCat)

return Struct(matchDiaSources=fullMatchedFakes)

def _estimateFakesSNR(self, injectionCat, diffIm):

Definition at line 119 of file matchDiffimSourceInjected.py.

◆ matchDiaSources

lsst.pipe.tasks.matchDiffimSourceInjected.matchDiaSources : `astropy.table.Table`
if variableDoublesFakeCat is None:
    return matchedFakes

# For the variable sources, we have a match to diaSources if their twins
# had a match, so we fill the diaSourceId with the diaSourceId of the matched
# twin if it exists and 0 otherwise, and we set the distance to -1 to
# indicate that these are variable sources that were not directly matched
# to diaSources.
variableDoublesFakeCat = variableDoublesFakeCat.copy()
variableDoublesFakeCat['diaSourceId'] = 0
variableDoublesFakeCat['dist_diaSrc'] = -1

# Match variable sources to their twin's matched diaSource
# Join on twin_id to injection_id
matched = join(variableDoublesFakeCat, matchedFakes,
               keys_left='twin_id', keys_right='injection_id',
               join_type='left', table_names=['variables', 'matched'],
               keep_order=True)

# Fill diaSourceId and dist_diaSrc from matched results
dia_id = np.ma.asarray(matched["diaSourceId_matched"])
dist = np.ma.asarray(matched["dist_diaSrc_matched"])

variableDoublesFakeCat["diaSourceId"] = np.ma.filled(dia_id, 0).astype(np.int64)
variableDoublesFakeCat["dist_diaSrc"] = np.ma.filled(dist, -1.0)

return vstack([matchedFakes, variableDoublesFakeCat], metadata_conflicts='silent')


class MatchInjectedToAssocDiaSourceConnections(
PipelineTaskConnections,
defaultTemplates={"coaddName": "deep"},
dimensions=("instrument",
        "visit",
        "detector")):

assocDiaSources = connTypes.Input(
doc="An assocDiaSource catalog to match against fakeCat from the"
    "diaPipe run. Assumed to be SDMified.",
name="{coaddName}Diff_assocDiaSrc",
storageClass="ArrowAstropy",
dimensions=("instrument", "visit", "detector"),
)
matchDiaSources = connTypes.Input(
doc="A catalog of those fakeCat sources that have a match in "
    "diaSrc. The schema is the union of the schemas for "
    "``fakeCat`` and ``diaSrc``.",
name="{coaddName}Diff_matchDiaSrc",
storageClass="ArrowAstropy",
dimensions=("instrument", "visit", "detector"),
)
matchAssocDiaSources = connTypes.Output(
doc="A catalog of those fakeCat sources that have a match in "
    "associatedDiaSources. The schema is the union of the schemas for "
    "``fakeCat`` and ``associatedDiaSources``.",
name="{coaddName}Diff_matchAssocDiaSrc",
storageClass="ArrowAstropy",
dimensions=("instrument", "visit", "detector"),
)


class MatchInjectedToAssocDiaSourceConfig(
PipelineTaskConfig,
pipelineConnections=MatchInjectedToAssocDiaSourceConnections):
class MatchInjectedToAssocDiaSourceTask(PipelineTask):

_DefaultName = "matchInjectedToAssocDiaSource"
ConfigClass = MatchInjectedToAssocDiaSourceConfig

def run(self, assocDiaSources, matchDiaSources):

Definition at line 491 of file matchDiffimSourceInjected.py.

◆ matchedFakes

lsst.pipe.tasks.matchDiffimSourceInjected.matchedFakes : `astropy.table.table.Table`
if "twin_id" not in fakeCat.colnames:
    self.log.warning("No twin_id column found in fake catalog.")
    return fakeCat, None

isVariable = fakeCat["twin_id"] > 0

return fakeCat[~isVariable], fakeCat[isVariable]

def _add_variables_to_matched(self, matchedFakes, variableDoublesFakeCat):

Definition at line 401 of file matchDiffimSourceInjected.py.

◆ ras

lsst.pipe.tasks.matchDiffimSourceInjected.ras : `numpy.ndarray`, (N,)
# First match the diaSrc to the injected fakes
nPossibleFakes = len(injectedCat)

fakeVects = self._getVectors(
    np.radians(injectedCat['ra']),
    np.radians(injectedCat['dec']))
diaSrcVects = self._getVectors(
    diaSources['coord_ra'],
    diaSources['coord_dec'])

diaSrcTree = cKDTree(diaSrcVects)
dist, idxs = diaSrcTree.query(
    fakeVects,
    distance_upper_bound=np.radians(self.config.matchDistanceArcseconds / 3600))
# handshake matching, that is symmetrize the match by matching the
# diaSrcs back to the fakes and only keeping those matches where the
# same pair is returned
diaSrcTreeBack = cKDTree(fakeVects)
distBack, idxsBack = diaSrcTreeBack.query(
    diaSrcVects,
    distance_upper_bound=np.radians(self.config.matchDistanceArcseconds / 3600))

idxsAux = np.where(np.array(idxs) < len(diaSources), idxs, -1)
valid = idxsAux >= 0
idxsBackMatched = np.full_like(idxsAux, -1)
idxsBackMatched[valid] = idxsBack[idxsAux[valid]]
idxsMatched = np.where(idxsBackMatched == np.arange(len(injectedCat)), idxs, -1)
distMatched = np.where(idxsBackMatched == np.arange(len(injectedCat)), dist, np.inf)
nFakesFound = np.isfinite(distMatched).sum()

self.log.info("Found %d out of %d possible in diaSources.", nFakesFound, nPossibleFakes)

# assign diaSourceId to the matched fakes
diaSrcIds = diaSources['id'][np.where(np.isfinite(distMatched), idxsMatched, 0)]
matchedFakes = injectedCat.copy()
matchedFakes['diaSourceId'] = np.where(np.isfinite(distMatched), diaSrcIds, 0)
matchedFakes['dist_diaSrc'] = np.where(np.isfinite(distMatched), 3600*np.rad2deg(distMatched), -1)
return matchedFakes

def _getVectors(self, ras, decs):

Definition at line 290 of file matchDiffimSourceInjected.py.

◆ result

lsst.pipe.tasks.matchDiffimSourceInjected.result : `lsst.pipe.base.Struct`

Definition at line 127 of file matchDiffimSourceInjected.py.

◆ variableDoublesFakeCat

lsst.pipe.tasks.matchDiffimSourceInjected.variableDoublesFakeCat : `astropy.table.table.Table`

Definition at line 385 of file matchDiffimSourceInjected.py.

◆ vectors

lsst.pipe.tasks.matchDiffimSourceInjected.vectors : `numpy.ndarray`, (N, 3)

Definition at line 297 of file matchDiffimSourceInjected.py.