Skip to content

Commit

Permalink
Make source selectors optional
Browse files Browse the repository at this point in the history
We don't want to do any source selection in the new calibrateImageTask,
as we are selecting sources directly in that task; astrometry and directMatch
source selectors are now optional.
  • Loading branch information
parejkoj committed Jul 14, 2023
1 parent 6637afe commit efacb34
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 25 deletions.
17 changes: 10 additions & 7 deletions python/lsst/meas/astrom/astrometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,11 +215,14 @@ def solve(self, exposure, sourceCat):

expMd = self._getExposureMetadata(exposure)

sourceSelection = self.sourceSelector.run(sourceCat)

self.log.info("Purged %d sources, leaving %d good sources",
len(sourceCat) - len(sourceSelection.sourceCat),
len(sourceSelection.sourceCat))
if self.config.doSourceSelection:
sourceSelection = self.sourceSelector.run(sourceCat)
self.log.info("Purged %d sources, leaving %d good sources",
len(sourceCat) - len(sourceSelection.sourceCat),
len(sourceSelection.sourceCat))
catalog = sourceSelection.sourceCat
else:
catalog = sourceCat

loadRes = self.refObjLoader.loadPixelBox(
bbox=expMd.bbox,
Expand All @@ -241,7 +244,7 @@ def solve(self, exposure, sourceCat):
frame = int(debug.frame)
displayAstrometry(
refCat=refSelection.sourceCat,
sourceCat=sourceSelection.sourceCat,
sourceCat=catalog,
exposure=exposure,
bbox=expMd.bbox,
frame=frame,
Expand All @@ -259,7 +262,7 @@ def solve(self, exposure, sourceCat):
tryRes = self._matchAndFitWcs(
refCat=refSelection.sourceCat,
sourceCat=sourceCat,
goodSourceCat=sourceSelection.sourceCat,
goodSourceCat=catalog,
refFluxField=loadRes.fluxField,
bbox=expMd.bbox,
wcs=wcs,
Expand Down
29 changes: 21 additions & 8 deletions python/lsst/meas/astrom/directMatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ class DirectMatchConfigWithoutLoader(Config):
``refObjLoader`` will be passed to this task.
"""
matchRadius = Field(dtype=float, default=0.25, doc="Matching radius, arcsec")
doSourceSelection = Field(
dtype=bool,
doc="Select sources to be matched with `sourceSelector`?"
" Set to False if you want to use exactly the sources that are passed in.",
default=True,
)
sourceSelection = ConfigurableField(target=ScienceSourceSelectorTask,
doc="Selection of science sources")
referenceSelection = ConfigurableField(target=ReferenceSourceSelectorTask,
Expand Down Expand Up @@ -55,7 +61,8 @@ def __init__(self, butler=None, refObjLoader=None, **kwargs):
warnings.warn("The 'butler' parameter is no longer used and can be safely removed.",
category=FutureWarning, stacklevel=2)
self.refObjLoader = refObjLoader
self.makeSubtask("sourceSelection")
if self.config.doSourceSelection:
self.makeSubtask("sourceSelection")
self.makeSubtask("referenceSelection")

def setRefObjLoader(self, refObjLoader):
Expand Down Expand Up @@ -96,21 +103,27 @@ def run(self, catalog, filterName=None, epoch=None):
raise RuntimeError("Running matcher task with no refObjLoader set in __ini__ or setRefObjLoader")
circle = self.calculateCircle(catalog)
matchMeta = self.refObjLoader.getMetadataCircle(circle.center, circle.radius, filterName, epoch=epoch)

emptyResult = Struct(matches=[], matchMeta=matchMeta)
sourceSelection = self.sourceSelection.run(catalog)
if len(sourceSelection.sourceCat) == 0:
self.log.warning("No objects selected from %d objects in source catalog", len(catalog))
return emptyResult
if self.config.doSourceSelection:
sourceSelection = self.sourceSelection.run(catalog)
if len(sourceSelection.sourceCat) == 0:
self.log.warning("No objects selected from %d objects in source catalog", len(catalog))
return emptyResult
sourceCat = sourceSelection.sourceCat
else:
sourceSelection = None
sourceCat = catalog

refData = self.refObjLoader.loadSkyCircle(circle.center, circle.radius, filterName, epoch=epoch)
refCat = refData.refCat
refSelection = self.referenceSelection.run(refCat)
if len(refSelection.sourceCat) == 0:
self.log.warning("No objects selected from %d objects in reference catalog", len(refCat))
return emptyResult
matches = afwTable.matchRaDec(refSelection.sourceCat, sourceSelection.sourceCat,
self.config.matchRadius*arcseconds)
matches = afwTable.matchRaDec(refSelection.sourceCat, sourceCat, self.config.matchRadius*arcseconds)
self.log.info("Matched %d from %d/%d input and %d/%d reference sources",
len(matches), len(sourceSelection.sourceCat), len(catalog),
len(matches), len(sourceCat), len(catalog),
len(refSelection.sourceCat), len(refCat))
return Struct(matches=matches, matchMeta=matchMeta, refCat=refCat, sourceSelection=sourceSelection,
refSelection=refSelection)
Expand Down
21 changes: 17 additions & 4 deletions python/lsst/meas/astrom/ref_match.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,16 @@ class RefMatchConfig(pexConfig.Config):
default=2,
min=0,
)
doSourceSelection = pexConfig.Field(
dtype=bool,
doc="Select sources to be matched with `sourceSelector`?"
" Set to False if you want to use exactly the sources that are passed in.",
default=True
)
sourceSelector = sourceSelectorRegistry.makeField(
doc="How to select sources for cross-matching.",
default="science",
optional=True
)
referenceSelector = pexConfig.ConfigurableField(
target=ReferenceSourceSelectorTask,
Expand Down Expand Up @@ -100,7 +107,8 @@ def __init__(self, refObjLoader, **kwargs):
"the configured sourceFluxType")

self.makeSubtask("matcher")
self.makeSubtask("sourceSelector")
if self.config.doSourceSelection:
self.makeSubtask("sourceSelector")
self.makeSubtask("referenceSelector")

def setRefObjLoader(self, refObjLoader):
Expand Down Expand Up @@ -148,7 +156,12 @@ def loadAndMatch(self, exposure, sourceCat):

expMd = self._getExposureMetadata(exposure)

sourceSelection = self.sourceSelector.run(sourceCat)
if self.config.doSourceSelection:
sourceSelection = self.sourceSelector.run(sourceCat)
catalog = sourceSelection.sourceCat
else:
sourceSelection = None
catalog = sourceCat

sourceFluxField = "slot_%sFlux_instFlux" % (self.config.sourceFluxType)

Expand All @@ -170,7 +183,7 @@ def loadAndMatch(self, exposure, sourceCat):

matchRes = self.matcher.matchObjectsToSources(
refCat=refSelection.sourceCat,
sourceCat=sourceSelection.sourceCat,
sourceCat=catalog,
wcs=expMd.wcs,
sourceFluxField=sourceFluxField,
refFluxField=loadRes.fluxField,
Expand All @@ -187,7 +200,7 @@ def loadAndMatch(self, exposure, sourceCat):
frame = int(debug.frame)
displayAstrometry(
refCat=refSelection.sourceCat,
sourceCat=sourceSelection.sourceCat,
sourceCat=catalog,
matches=matchRes.matches,
exposure=exposure,
bbox=expMd.bbox,
Expand Down
18 changes: 14 additions & 4 deletions tests/test_astrometryTask.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,15 @@ def testTrivial(self):
"""
self.doTest(afwGeom.makeIdentityTransform())

def testNoSourceSelector(self):
"""Test fit with no distortion, with no source selector.
"""
config = AstrometryTask.ConfigClass()
config.wcsFitter.order = 2
config.wcsFitter.numRejIter = 0
config.doSourceSelection = False
self.doTest(afwGeom.makeIdentityTransform(), config=config)

def testRadial(self):
"""Test fit with radial distortion
Expand Down Expand Up @@ -131,16 +140,17 @@ def testWcsFailure(self):
self.assertTrue(results.scatterOnSky is None)
self.assertTrue(results.matches is None)

def doTest(self, pixelsToTanPixels, order=3):
def doTest(self, pixelsToTanPixels, order=3, config=None):
"""Test using pixelsToTanPixels to distort the source positions
"""
distortedWcs = afwGeom.makeModifiedWcs(pixelTransform=pixelsToTanPixels, wcs=self.tanWcs,
modifyActualPixels=False)
self.exposure.setWcs(distortedWcs)
sourceCat = self.makeSourceCat(distortedWcs)
config = AstrometryTask.ConfigClass()
config.wcsFitter.order = order
config.wcsFitter.numRejIter = 0
if config is None:
config = AstrometryTask.ConfigClass()
config.wcsFitter.order = order
config.wcsFitter.numRejIter = 0
solver = AstrometryTask(config=config, refObjLoader=self.refObjLoader)
results = solver.run(
sourceCat=sourceCat,
Expand Down
11 changes: 9 additions & 2 deletions tests/test_directMatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,9 @@ def tearDown(self):
del self.refObjLoader
del self.references

def checkMatching(self, catalog):
config = lsst.meas.astrom.DirectMatchConfig()
def checkMatching(self, catalog, config=None):
if config is None:
config = lsst.meas.astrom.DirectMatchConfig()
task = lsst.meas.astrom.DirectMatchTask(config=config, refObjLoader=self.refObjLoader)
results = task.run(catalog, self.filter)

Expand Down Expand Up @@ -85,6 +86,12 @@ def testWithNoise(self):
dec += offset*np.random.uniform(-1.0, 1.0, num)
self.checkMatching(references)

def testNoSourceSelection(self):
"""Same results with source selector disabled."""
config = lsst.meas.astrom.DirectMatchConfig()
config.doSourceSelection = False
self.checkMatching(self.references, config=config)


class DirectMatchMemoryTestCase(lsst.utils.tests.MemoryTestCase):
pass
Expand Down

0 comments on commit efacb34

Please sign in to comment.