Skip to content

Commit

Permalink
add function to convert matches to denormalized catalog
Browse files Browse the repository at this point in the history
This produces persisted catalogs that are easier to read,
even though they take more space.
  • Loading branch information
PaulPrice committed Mar 21, 2017
1 parent e3a4b3c commit 73531ca
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 0 deletions.
1 change: 1 addition & 0 deletions python/lsst/meas/astrom/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,5 @@
from .catalogStarSelector import *
from .directMatch import *
from .fitSipDistortion import *
from .denormalizedMatches import *
from .version import *
58 changes: 58 additions & 0 deletions python/lsst/meas/astrom/denormalizeMatches.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import lsst.afw.table

__all__ = ["denormalizeMatches"]

def denormalizeMatches(matches, matchMeta=None):
"""Generate a denormalized Catalog of matches
This is intended for writing matches in a convenient way.
Normally we write matches in a 'normalized' form: recording only the join
table (reference ID, source ID) to minimise space (the reference and source
catalogs should both be available separately, so the only extra information
we need is how to join them). However, using that can be a pain, since it
requires reading each catalog and doing the join.
This function generates a Catalog containing all the information in the
matches. The reference catalog entries are in columns with "ref_"
prepended, while the source catalog entries are in columns with "src_"
prepended. The distance between the matches is in a column named
"distance".
Parameters
----------
matches : `list` of `lsst.afw.table.ReferenceMatch`
List of matches between reference catalog and source catalog.
matchMeta : `lsst.daf.base.PropertyList`
Matching metadata to write in catalog.
Returns
-------
catalog : `lsst.afw.table.BaseCatalog`
Catalog containing matchlist entries.
See also
--------
`lsst.afw.table.packMatches`
"""
if len(matches) == 0:
raise RuntimeError("No matches provided.")

refSchema = matches[0].first.getSchema()
srcSchema = matches[0].second.getSchema()

refMapper, srcMapper = lsst.afw.table.SchemaMapper.join([refSchema, srcSchema], ["ref_", "src_"])
schema = refMapper.editOutputSchema()
distKey = schema.addField("distance", type=float, doc="Distance between ref and src")

catalog = lsst.afw.table.BaseCatalog(schema)
catalog.reserve(len(matches))
for mm in matches:
row = catalog.addNew()
row.assign(mm.first, refMapper)
row.assign(mm.second, srcMapper)
row.set(distKey, mm.distance)

if matchMeta is not None:
catalog.getTable().setMetadata(matchMeta)

return catalog
65 changes: 65 additions & 0 deletions tests/testDenormalizeMatches.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import sys
import unittest

import lsst.afw.geom
import lsst.afw.table

from lsst.meas.astrom import denormalizeMatches

class DenormalizeMatchesTestCase(unittest.TestCase):
"""Test the behaviour of the denormalizedMatches function"""

def checkDenormalizeMatches(self, refType, srcType, MatchClass, num=10):
"""Check that denormalizeMatches works
We create reference and source catalogs, generate matches,
run denormalizeMatches and verify that the results are as expected.
Parameters
----------
refType : `str`
Type of reference catalog/table; "Simple" or "Source".
srcType : `str`
Type of source catalog/table; "Simple" or "Source".
MatchClass : `type`
Class for match; should be suitable for the refType and srcType.
"""
refSchema = getattr(lsst.afw.table, refType + "Table").makeMinimalSchema()
refCat = getattr(lsst.afw.table, refType + "Catalog")(refSchema)
for ii in range(num):
ref = refCat.addNew()
ref.set("id", ii)

srcSchema = getattr(lsst.afw.table, srcType + "Table").makeMinimalSchema()
srcCat = getattr(lsst.afw.table, srcType + "Catalog")(srcSchema)
for ii in range(2*num, num, -1):
src = srcCat.addNew()
src.set("id", ii)

matches = [MatchClass(ref, src, ref.get("id")) for ref, src in zip(refCat, srcCat)]
catalog = denormalizeMatches(matches)
for row, ref, src in zip(catalog, refCat, srcCat):
self.assertEqual(row.get("ref_id"), ref.get("id"))
self.assertEqual(row.get("src_id"), src.get("id"))
self.assertEqual(row.get("distance"), ref.get("id"))

def testDenormalizeMatches(self):
"""Test denormalizeMatches for various types"""
for args in (("Simple", "Simple", lsst.afw.table.SimpleMatch),
("Simple", "Source", lsst.afw.table.ReferenceMatch),
("Source", "Source", lsst.afw.table.SourceMatch),
):
self.checkDenormalizeMatches(*args)


class MemoryTester(lsst.utils.tests.MemoryTestCase):
pass


def setup_module(module):
lsst.utils.tests.init()


if __name__ == "__main__":
setup_module(sys.modules[__name__])
unittest.main()

0 comments on commit 73531ca

Please sign in to comment.