-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add updateRefCentroids and updateSourceCoords
Add two utility functions to lsst.afw.table: updateRefCentroids and updateSourceCoords. Add a unit test for these functions testTableUtils.py (since the functions are defined in new module lsst.afw.table.utils)
- Loading branch information
Showing
3 changed files
with
251 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,3 +2,4 @@ | |
from .tableEnumDicts import * | ||
from .multiMatch import * | ||
from .catalogMatches import * | ||
from .utils import * |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
# | ||
# LSST Data Management System | ||
# Copyright 2016 AURA/LSST. | ||
# | ||
# This product includes software developed by the | ||
# LSST Project (http://www.lsst.org/). | ||
# | ||
# This program is free software: you can redistribute it and/or modify | ||
# it under the terms of the GNU General Public License as published by | ||
# the Free Software Foundation, either version 3 of the License, or | ||
# (at your option) any later version. | ||
# | ||
# This program is distributed in the hope that it will be useful, | ||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
# GNU General Public License for more details. | ||
# | ||
# You should have received a copy of the LSST License Statement and | ||
# the GNU General Public License along with this program. If not, | ||
# see <https://www.lsstcorp.org/LegalNotices/>. | ||
# | ||
from __future__ import absolute_import, division, print_function | ||
|
||
from .tableLib import CoordKey, Point2DKey | ||
|
||
__all__ = ["updateRefCentroids", "updateSourceCoords"] | ||
|
||
|
||
def updateRefCentroids(wcs, refList): | ||
"""Update centroids in a collection of reference objects | ||
This code supports any kind of collection, instead of requiring a catalog, | ||
to make it easy to use with match lists. For example: | ||
updateRefCentroids(wcs, refList=[match.first for match in matches]) | ||
@param[in] wcs WCS to map from sky to pixels; an lsst.afw.image.Wcs | ||
@param[in,out] refList collection of reference objects (lsst.afw.table.SimpleRecords) with fields: | ||
- "coord", a field of lsst.afw.coord.Coord, is read | ||
- "centroid", a field of lsst.afw.geom.Point2D, is written | ||
""" | ||
if len(refList) < 1: | ||
return | ||
schema = refList[0].schema | ||
coordKey = CoordKey(schema["coord"]) | ||
centroidKey = Point2DKey(schema["centroid"]) | ||
for refObj in refList: | ||
refObj.set(centroidKey, wcs.skyToPixel(refObj.get(coordKey))) | ||
|
||
|
||
def updateSourceCoords(wcs, sourceList): | ||
"""Update coords in a collection of sources | ||
This code supports any kind of collection, instead of requiring a catalog, | ||
to make it easy to use with match lists. For example: | ||
updateSourceCoords(wcs, sourceList=[match.second for match in matches]) | ||
@param[in] wcs WCS to map from pixels to sky; an lsst.afw.image.Wcs | ||
@param[in,out] sourceList collection of sources (lsst.afw.table.SourceRecords) with fields: | ||
- "slot_Centroid" (as returned by getCentroid) is read | ||
- "coord", a field of lsst.afw.coord.Coord, is written | ||
""" | ||
if len(sourceList) < 1: | ||
return | ||
schema = sourceList[0].schema | ||
srcCoordKey = CoordKey(schema["coord"]) | ||
for src in sourceList: | ||
src.set(srcCoordKey, wcs.pixelToSky(src.getCentroid())) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
#!/usr/bin/env python | ||
|
||
# LSST Data Management System | ||
# Copyright 2016 LSST Corporation. | ||
# | ||
# This product includes software developed by the | ||
# LSST Project (http://www.lsst.org/). | ||
# | ||
# This program is free software: you can redistribute it and/or modify | ||
# it under the terms of the GNU General Public License as published by | ||
# the Free Software Foundation, either version 3 of the License, or | ||
# (at your option) any later version. | ||
# | ||
# This program is distributed in the hope that it will be useful, | ||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
# GNU General Public License for more details. | ||
# | ||
# You should have received a copy of the LSST License Statement and | ||
# the GNU General Public License along with this program. If not, | ||
# see <http://www.lsstcorp.org/LegalNotices/>. | ||
# | ||
# The classes in this test are a little non-standard to reduce code | ||
# duplication and support automated unittest discovery. | ||
# A base class includes all the code that implements the testing and | ||
# itself inherits from unittest.TestCase. unittest automated discovery | ||
# will scan all classes that inherit from unittest.TestCase and invoke | ||
# any test methods found. To prevent this base class from being executed | ||
# the test methods are placed in a different class that does not inherit | ||
# from unittest.TestCase. The actual test classes then inherit from | ||
# both the testing class and the implementation class allowing test | ||
# discovery to only run tests found in the subclasses. | ||
|
||
from __future__ import absolute_import, division, print_function | ||
import math | ||
import unittest | ||
from itertools import izip | ||
|
||
import numpy as np | ||
|
||
import lsst.utils.tests | ||
import lsst.afw.coord as afwCoord | ||
import lsst.afw.geom as afwGeom | ||
import lsst.afw.image as afwImage | ||
import lsst.afw.table as afwTable | ||
|
||
|
||
def setup_module(module): | ||
lsst.utils.tests.init() | ||
|
||
|
||
def setCentroids(cat, key, maxPix, numPoints): | ||
"""Add a square grid of points to an empty catalog | ||
The catalog must be empty to start with | ||
@param[in,out] cat a catalog, e.g. lsst.afw.table.SimpleCatalog | ||
@paramp[in] key key for field to be set | ||
@param[in] maxPix maximum pixel position; used for both x and y; | ||
the min is the negative of maxPix | ||
@param[in] numPoints number of points in x or y; total points = numPoints*numPoints | ||
""" | ||
if len(cat) != 0: | ||
raise RuntimeError("cat must be empty") | ||
for i in np.linspace(-maxPix, maxPix, numPoints): | ||
for j in np.linspace(-maxPix, maxPix, numPoints): | ||
rec = cat.addNew() | ||
rec.set(key, afwGeom.Point2D(i, j)) | ||
|
||
|
||
class UpdateTestCase(lsst.utils.tests.TestCase): | ||
"""A test case for the lsst.afw.table.updateRefCentroids and updateSourceCoords | ||
""" | ||
|
||
def setUp(self): | ||
self.crval = afwCoord.IcrsCoord(afwGeom.PointD(44., 45.)) | ||
self.crpix = afwGeom.Point2D(15000, 4000) | ||
|
||
arcsecPerPixel = 1/3600.0 | ||
CD11 = arcsecPerPixel | ||
CD12 = 0 | ||
CD21 = 0 | ||
CD22 = arcsecPerPixel | ||
|
||
self.wcs = afwImage.makeWcs(self.crval, self.crpix, CD11, CD12, CD21, CD22) | ||
|
||
refSchema = afwTable.SimpleTable.makeMinimalSchema() | ||
self.refCentroidKey = afwTable.Point2DKey.addFields(refSchema, "centroid", "centroid", "pixels") | ||
self.refCoordKey = afwTable.CoordKey(refSchema["coord"]) | ||
self.refCat = afwTable.SimpleCatalog(refSchema) | ||
|
||
# an alias is required to make src.getCentroid() work; | ||
# simply defining a field named "slot_Centroid" doesn't suffice | ||
srcSchema = afwTable.SourceTable.makeMinimalSchema() | ||
self.srcCentroidKey = afwTable.Point2DKey.addFields(srcSchema, "base_SdssCentroid", | ||
"centroid", "pixels") | ||
srcAliases = srcSchema.getAliasMap() | ||
srcAliases.set("slot_Centroid", "base_SdssCentroid") | ||
self.srcCoordKey = afwTable.CoordKey(srcSchema["coord"]) | ||
self.sourceCat = afwTable.SourceCatalog(srcSchema) | ||
|
||
def tearDown(self): | ||
del self.wcs | ||
del self.refCat | ||
del self.sourceCat | ||
|
||
def testNull(self): | ||
"""Check that an empty list causes no problems for either function""" | ||
afwTable.updateRefCentroids(self.wcs, []) | ||
afwTable.updateSourceCoords(self.wcs, []) | ||
|
||
def testRefCenter(self): | ||
"""Check that a ref obj at the center is handled as expected""" | ||
refObj = self.refCat.addNew() | ||
refObj.set(self.refCoordKey, self.crval) | ||
|
||
# initial centroid should be nan | ||
nanRefCentroid = self.refCat[0].get(self.refCentroidKey) | ||
for val in nanRefCentroid: | ||
self.assertTrue(math.isnan(val)) | ||
|
||
# computed centroid should be crpix | ||
afwTable.updateRefCentroids(self.wcs, self.refCat) | ||
refCentroid = self.refCat[0].get(self.refCentroidKey) | ||
self.assertPairsNearlyEqual(refCentroid, self.crpix) | ||
|
||
# coord should not be changed | ||
self.assertPairsNearlyEqual(self.refCat[0].get(self.refCoordKey), self.crval, maxDiff=0) | ||
|
||
def testSourceCenter(self): | ||
"""Check that a source at the center is handled as expected""" | ||
src = self.sourceCat.addNew() | ||
src.set(self.srcCentroidKey, self.crpix) | ||
|
||
# initial coord should be nan; as a sanity-check | ||
nanSourceCoord = self.sourceCat[0].get(self.srcCoordKey) | ||
for val in nanSourceCoord: | ||
self.assertTrue(math.isnan(val)) | ||
|
||
# compute coord should be crval | ||
afwTable.updateSourceCoords(self.wcs, self.sourceCat) | ||
srcCoord = self.sourceCat[0].get(self.srcCoordKey) | ||
self.assertPairsNearlyEqual(srcCoord, self.crval) | ||
|
||
# centroid should not be changed; also make sure that getCentroid words | ||
self.assertPairsNearlyEqual(self.sourceCat[0].getCentroid(), self.crpix, maxDiff=0) | ||
|
||
def testList(self): | ||
"""Check lists of reference objects and sources""" | ||
maxPix = 1000 | ||
numPoints = 10 | ||
setCentroids(cat=self.sourceCat, key=self.srcCentroidKey, maxPix=maxPix, numPoints=numPoints) | ||
for src in self.sourceCat: | ||
refObj = self.refCat.addNew() | ||
centroid = src.get(self.srcCentroidKey) | ||
coord = self.wcs.pixelToSky(centroid) | ||
refObj.setCoord(coord) | ||
self.assertEqual(len(self.sourceCat), len(self.refCat)) | ||
|
||
# update the catalogs, but this time use a list instead of an actual catalog | ||
# to make sure that feature works | ||
afwTable.updateSourceCoords(self.wcs, [s for s in self.sourceCat]) | ||
afwTable.updateRefCentroids(self.wcs, [r for r in self.refCat]) | ||
|
||
# check that centroids and coords match | ||
for src, refObj in izip(self.sourceCat, self.refCat): | ||
srcCentroid = src.get(self.srcCentroidKey) | ||
refCentroid = refObj.get(self.refCentroidKey) | ||
self.assertPairsNearlyEqual(srcCentroid, refCentroid) | ||
|
||
srcCoord = src.get(self.srcCoordKey) | ||
refCoord = refObj.get(self.refCoordKey) | ||
self.assertCoordsNearlyEqual(srcCoord, refCoord) | ||
|
||
|
||
class MyMemoryTestCase(lsst.utils.tests.MemoryTestCase): | ||
pass | ||
|
||
if __name__ == "__main__": | ||
lsst.utils.tests.init() | ||
unittest.main() |