Skip to content

Commit

Permalink
Improve matching by culling non-good sources
Browse files Browse the repository at this point in the history
MatchOptimisticBTask was not culling non-good sources from the match list
before returning. That was a bug I accidentally introduced while making
other changes.
I also changed the definition of good sources as those that are have no
interpolated pixels in their center, as recommended by Paul Price;
this catches cosmic rays and bad pixels, as well as saturation.
The result of re-introducing the culling is that the CFHT demo
not reaches 18.6 mas scatter of bright stars in only 3 iterations
of the outer loop in AstrometryTask, so I reduced the default accordingly
(still not quite the 2 Paul Price requested, but close).
  • Loading branch information
r-owen committed May 21, 2015
1 parent 3533563 commit 6575307
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 11 deletions.
2 changes: 1 addition & 1 deletion python/lsst/meas/astrom/astrometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class AstrometryConfig(pexConfig.Config):
doc = "maximum number of iterations of match sources and fit WCS; " +
"ignored if forceKnownWcs True",
dtype = int,
default = 6,
default = 3,
min = 1,
)
matchDistanceSigma = pexConfig.RangeField(
Expand Down
31 changes: 21 additions & 10 deletions python/lsst/meas/astrom/matchOptimisticB.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ class SourceInfo(object):
- centroidFlagKey key for flag that is True if centroid is valid
- edgeKey key for field that is True if source is near an edge
- saturatedKey key for field that is True if source has any saturated pixels
- interpolatedCenterKey key for field that is True if center pixels have interpolated values;
interpolation is triggered by saturation, cosmic rays and bad pixels, and possibly other reasons
- fluxField name of flux field
@throw RuntimeError if schema version unsupported or a needed field is not found
Expand All @@ -103,9 +105,9 @@ def __init__(self, schema, fluxType="Ap"):
self.edgeKey = schema["base_PixelFlags_flag_edge"].asKey()
self.saturatedKey = schema["base_PixelFlags_flag_saturated"].asKey()
self.fluxField = "slot_%sFlux_flux" % (fluxType,)
self.interpolatedCenterKey = schema["base_PixelFlags_flag_interpolatedCenter"].asKey()
# extra keys that might be useful
self.parentKey = schema["parent"].asKey()
self.interpolatedCenterKey = schema["base_PixelFlags_flag_interpolatedCenter"].asKey()
else:
raise RuntimeError("Version %r of sourceCat schema not supported" % (version,))

Expand Down Expand Up @@ -133,15 +135,15 @@ def isUsable(self, source):
- have a valid centroid
- be not too near the edge
"""
return (
self.hasCentroid(source)
and not source.get(self.edgeKey)
)
return self.hasCentroid(source) and not source.get(self.edgeKey)

def isGood(self, source):
"""Return True if source is usable for matching (as per isUsable) and is not saturated
"""Return True if source is usable for matching (as per isUsable) and likely has a good centroid
For a source to have a good centroid it should not be interpolated in the center;
this includes saturated sources so we don't have to test separately for that.
"""
return self.isUsable(source) and not source.get(self.saturatedKey)
return self.isUsable(source) and not source.get(self.interpolatedCenterKey)


# The following block adds links to this task from the Task Documentation page.
Expand Down Expand Up @@ -245,7 +247,7 @@ def matchObjectsToSources(self, refCat, sourceCat, wcs, refFluxField, maxMatchDi
if specified then min(config.maxMatchDistArcSec, maxMatchDistArcSec) is used
if None then config.maxMatchDistArcSec is used
@return an lsst.pipe.base.Struct with fields:
- matches a list of matches, an instance of lsst.afw.table.ReferenceMatch
- matches a list of matches, each instance of lsst.afw.table.ReferenceMatch
- usableSourcCat a catalog of sources potentially usable for matching.
For this fitter usable sources include unresolved sources not too near the edge.
It includes saturated sources, even those these are removed from the final match list,
Expand Down Expand Up @@ -283,7 +285,7 @@ def matchObjectsToSources(self, refCat, sourceCat, wcs, refFluxField, maxMatchDi
int(self.config.minFracMatchedPairs * min([len(refCat), len(usableSourceCat)])))

# match usable (possibly saturated) sources and then purge saturated sources from the match list
matches = self._doMatch(
usableMatches = self._doMatch(
refCat = refCat,
sourceCat = usableSourceCat,
wcs = wcs,
Expand All @@ -295,10 +297,19 @@ def matchObjectsToSources(self, refCat, sourceCat, wcs, refFluxField, maxMatchDi
verbose = debug.verbose,
)

# cull non-good sources
matches = []
for match in usableMatches:
if sourceInfo.isGood(match.second):
matches.append(match)

self.log.logdebug("Found %d usable matches, of which %d had good sources" %
(len(usableMatches), len(matches)))

if len(matches) == 0:
raise RuntimeError("Unable to match sources")

if self.log: self.log.info("Matched %d sources" % len(matches))
self.log.info("Matched %d sources" % len(matches))
if len(matches) < minMatchedPairs:
self.log.warn("Number of matches is smaller than request")

Expand Down

0 comments on commit 6575307

Please sign in to comment.