Skip to content

Commit

Permalink
Merge pull request #209 from lsst/tickets/DM-26007
Browse files Browse the repository at this point in the history
DM-26007: defaultFilter is not used if a filterName is given to loadSkyCircle
  • Loading branch information
parejkoj committed Aug 4, 2020
2 parents c448522 + 59203ed commit 01203ff
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 11 deletions.
57 changes: 46 additions & 11 deletions python/lsst/meas/algorithms/loadReferenceObjects.py
Original file line number Diff line number Diff line change
Expand Up @@ -691,20 +691,23 @@ def remapReferenceCatalogSchema(refCat, *, filterNameList=None, position=False,
def getRefFluxField(schema, filterName=None):
"""Get the name of a flux field from a schema.
if filterName is specified:
return *filterName*_camFlux if present
else return *filterName*_flux if present (camera filter name matches reference filter name)
return the alias of "anyFilterMapsToThis", if present
else if filterName is specified:
return "*filterName*_camFlux" if present
else return "*filterName*_flux" if present (camera filter name
matches reference filter name)
else throw RuntimeError
else:
return camFlux, if present,
return "camFlux", if present,
else throw RuntimeError
Parameters
----------
schema : `lsst.afw.table.Schema`
Reference catalog schema.
filterName : `str`
Name of camera filter.
filterName : `str`, optional
Name of camera filter. If not specified, ``defaultFilter`` needs to be
set in the refcat loader config.
Returns
-------
Expand All @@ -718,6 +721,11 @@ def getRefFluxField(schema, filterName=None):
"""
if not isinstance(schema, afwTable.Schema):
raise RuntimeError("schema=%s is not a schema" % (schema,))
try:
return schema.getAliasMap().get("anyFilterMapsToThis")
except LookupError:
pass # try the filterMap next

if filterName:
fluxFieldList = [filterName + "_camFlux", filterName + "_flux"]
else:
Expand Down Expand Up @@ -770,14 +778,25 @@ class LoadReferenceObjectsConfig(pexConfig.Config):
min=0,
)
defaultFilter = pexConfig.Field(
doc="Default reference catalog filter to use if filter not specified in exposure; "
"if blank then filter must be specified in exposure",
doc=("Default reference catalog filter to use if filter not specified in exposure;"
" if blank then filter must be specified in exposure."),
dtype=str,
default="",
)
anyFilterMapsToThis = pexConfig.Field(
doc=("Always use this reference catalog filter, no matter whether or what filter name is "
"supplied to the loader. Effectively a trivial filterMap: map all filter names to this filter."
" This can be set for purely-astrometric catalogs (e.g. Gaia DR2) where there is only one "
"reasonable choice for every camera filter->refcat mapping, but not for refcats used for "
"photometry, which need a filterMap and/or colorterms/transmission corrections."),
dtype=str,
default=None,
optional=True
)
filterMap = pexConfig.DictField(
doc="Mapping of camera filter name: reference catalog filter name; "
"each reference filter must exist",
doc=("Mapping of camera filter name: reference catalog filter name; "
"each reference filter must exist in the refcat."
" Note that this does not perform any bandpass corrections: it is just a lookup."),
keytype=str,
itemtype=str,
default={},
Expand All @@ -789,6 +808,14 @@ class LoadReferenceObjectsConfig(pexConfig.Config):
default=False,
)

def validate(self):
super().validate()
if self.filterMap != {} and self.anyFilterMapsToThis is not None:
msg = "`filterMap` and `anyFilterMapsToThis` are mutually exclusive"
raise pexConfig.FieldValidationError(LoadReferenceObjectsConfig.anyFilterMapsToThis,
self, msg)


# The following comment block adds a link to this task from the Task Documentation page.
## @addtogroup LSST_task_documentation
## @{
Expand Down Expand Up @@ -1046,13 +1073,21 @@ def _addFluxAliases(self, schema):
schema : `lsst.afw.table.Schema`
Schema for reference catalog.
Throws
Raises
------
RuntimeError
If any reference flux field is missing from the schema.
"""
aliasMap = schema.getAliasMap()

if self.config.anyFilterMapsToThis is not None:
refFluxName = self.config.anyFilterMapsToThis + "_flux"
if refFluxName not in schema:
msg = f"Unknown reference filter for anyFilterMapsToThis='{refFluxName}'"
raise RuntimeError(msg)
aliasMap.set("anyFilterMapsToThis", refFluxName)
return # this is mutually exclusive with filterMap

def addAliasesForOneFilter(filterName, refFilterName):
"""Add aliases for a single filter
Expand Down
35 changes: 35 additions & 0 deletions tests/test_loadReferenceObjects.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import lsst.log
from lsst.meas.algorithms import LoadReferenceObjectsTask, getRefFluxField, getRefFluxKeys
from lsst.meas.algorithms.loadReferenceObjects import hasNanojanskyFluxUnits, convertToNanojansky
import lsst.pex.config
import lsst.utils.tests


Expand All @@ -45,6 +46,27 @@ class TestLoadReferenceObjects(lsst.utils.tests.TestCase):
Only methods with concrete implementations are tested (hence not loadSkyCircle)
"""

def testFilterMapVsAnyFilterMapsToThis(self):
config = TrivialLoader.ConfigClass()
# check that a filterMap-only config passes validation
config.filterMap = {"b": "a"}
try:
config.validate()
except lsst.pex.config.FieldValidationError:
self.fail("`filterMap`-only LoadReferenceObjectsConfig should not fail validation.")

# anyFilterMapsToThis and filterMap are mutually exclusive
config.anyFilterMapsToThis = "c"
with self.assertRaises(lsst.pex.config.FieldValidationError):
config.validate()

# check that a anyFilterMapsToThis-only config passes validation
config.filterMap = {}
try:
config.validate()
except lsst.pex.config.FieldValidationError:
self.fail("`anyFilterMapsToThis`-only LoadReferenceObjectsConfig should not fail validation.")

def testMakeMinimalSchema(self):
"""Make a schema and check it."""
for filterNameList in (["r"], ["foo", "_bar"]):
Expand Down Expand Up @@ -153,6 +175,19 @@ def testFilterAliasMap(self):
with self.assertRaises(RuntimeError):
getRefFluxKeys(refSchema, "camr")

def testAnyFilterMapsToThisAlias(self):
# test anyFilterMapsToThis
config = TrivialLoader.ConfigClass()
config.anyFilterMapsToThis = "gg"
loader = TrivialLoader(config=config)
refSchema = TrivialLoader.makeMinimalSchema(filterNameList=["gg"])
loader._addFluxAliases(refSchema)
self.assertEqual(getRefFluxField(refSchema, "r"), "gg_flux")
# raise if "gg" is not in the refcat filter list
with self.assertRaises(RuntimeError):
refSchema = TrivialLoader.makeMinimalSchema(filterNameList=["rr"])
refSchema = loader._addFluxAliases(refSchema)

def testCheckFluxUnits(self):
"""Test that we can identify old style fluxes in a schema."""
schema = LoadReferenceObjectsTask.makeMinimalSchema(['r', 'z'])
Expand Down

0 comments on commit 01203ff

Please sign in to comment.