23 from __future__
import absolute_import, division, print_function
28 import lsst.pex.exceptions
as pexExcept
29 from lsst.pex.config
import Config, Field, ConfigDictField
30 from lsst.afw.image
import Filter
32 __all__ = [
"ColortermNotFoundError",
"Colorterm",
"ColortermDict",
"ColortermLibrary"]
36 """Exception class indicating we couldn't find a colorterm 42 """!Colorterm correction for one pair of filters 44 The transformed magnitude p' is given by 45 p' = primary + c0 + c1*(primary - secondary) + c2*(primary - secondary)**2 47 To construct a Colorterm, use keyword arguments: 48 Colorterm(primary=primaryFilterName, secondary=secondaryFilterName, c0=c0value, c1=c1Coeff, c2=c2Coeff) 49 where c0-c2 are optional. For example (omitting c2): 50 Colorterm(primary="g", secondary="r", c0=-0.00816446, c1=-0.08366937) 52 This is subclass of Config. That
is a bit of a hack to make it easy to store the data
53 in an appropriate obs_* package
as a config override file. In the long term some other
54 means of persistence will be used, at which point the constructor can be simplified
55 to
not require keyword arguments. (Fixing DM-2831 will also allow making a custom constructor).
57 primary = Field(dtype=str, doc="name of primary filter") 58 secondary = Field(dtype=str, doc="name of secondary filter") 59 c0 = Field(dtype=float, default=0.0, doc="Constant parameter") 60 c1 = Field(dtype=float, default=0.0, doc="First-order parameter") 61 c2 = Field(dtype=float, default=0.0, doc="Second-order parameter") 63 def transformSource(self, source): 64 """!Transform the brightness of a source
66 @param[
in] source source whose brightness
is to be converted; must support get(filterName)
67 (e.g. source.get(
"r")) method, as do afw::table::Source and dicts. 68 @return the transformed source magnitude
70 return self.transformMags(source.get(self.primary), source.get(self.secondary)) 72 def transformMags(self, primary, secondary): 73 """!Transform brightness
75 @param[
in] primary brightness
in primary filter (magnitude)
76 @param[
in] secondary brightness
in secondary filter (magnitude)
77 @
return the transformed brightness (
as a magnitude)
79 color = primary - secondary 80 return primary + self.c0 + color*(self.c1 + color*self.c2) 82 def propagateFluxErrors(self, primaryFluxErr, secondaryFluxErr): 83 return np.hypot((1 + self.c1)*primaryFluxErr, self.c1*secondaryFluxErr) 86 class ColortermDict(Config): 87 """!A mapping of filterName to Colorterm
89 Different reference catalogs may need different ColortermDicts; see ColortermLibrary
91 To construct a ColortermDict use keyword arguments:
93 where dataDict
is a Python dict of filterName: Colorterm
96 'g':
Colorterm(primary=
"g", secondary=
"r", c0=-0.00816446, c1=-0.08366937, c2=-0.00726883), 97 'r': Colorterm(primary="r", secondary="i", c0= 0.00231810, c1= 0.01284177, c2=-0.03068248),
98 'i':
Colorterm(primary=
"i", secondary=
"z", c0= 0.00130204, c1=-0.16922042, c2=-0.01374245),
100 The constructor will likely be simplified at some point.
102 This
is subclass of Config. That
is a bit of a hack to make it easy to store the data
103 in an appropriate obs_* package
as a config override file. In the long term some other
104 means of persistence will be used, at which point the constructor can be made saner.
106 data = ConfigDictField( 107 doc="Mapping of filter name to Colorterm", 114 class ColortermLibrary(Config): 115 """!A mapping of photometric reference catalog name
or glob to ColortermDict
117 This allows photometric calibration using a variety of reference catalogs.
119 To construct a ColortermLibrary, use keyword arguments:
121 where dataDict
is a Python dict of catalog_name_or_glob: ColortermDict
126 'g':
Colorterm(primary=
"g", secondary=
"g"),
127 'r': Colorterm(primary="r", secondary="r"), 131 'g':
Colorterm(primary=
"g", secondary=
"r", c0=-0.00816446, c1=-0.08366937, c2=-0.00726883), 132 'r': Colorterm(primary="r", secondary="i", c0= 0.00231810, c1= 0.01284177, c2=-0.03068248),
137 This
is subclass of Config. That
is a bit of a hack to make it easy to store the data
138 in an appropriate obs_* package
as a config override file. In the long term some other
139 means of persistence will be used, at which point the constructor can be made saner.
141 data = ConfigDictField( 142 doc="Mapping of reference catalog name (or glob) to ColortermDict", 144 itemtype=ColortermDict, 148 def getColorterm(self, filterName, photoCatName, doRaise=True): 149 """!Get the appropriate Colorterm
from the library
151 Use dict of color terms
in the library that matches the photoCatName.
152 If the photoCatName exactly matches an entry
in the library, that
153 dict
is used; otherwise
if the photoCatName matches a single glob (shell syntax,
154 e.g.,
"sdss-*" will match
"sdss-dr8"), then that
is used. If there
is no
155 exact match
and no unique match to the globs,
raise an exception.
157 @param filterName name of filter
158 @param photoCatName name of photometric reference catalog
from which to retrieve the data.
159 This argument
is not glob-expanded (but the catalog names
in the library are,
160 if no exact match
is found).
161 @param[
in] doRaise
if True then
raise ColortermNotFoundError
if no suitable Colorterm found;
162 if False then
return a null Colorterm with filterName
as the primary
and secondary filter
163 @
return the appropriate Colorterm
165 @throw ColortermNotFoundError
if no suitable Colorterm found
and doRaise true;
166 other exceptions may be raised
for unexpected errors, regardless of the value of doRaise
169 trueRefCatName = None 170 ctDictConfig = self.data.get(photoCatName) 171 if ctDictConfig is None: 172 # try glob expression 173 matchList = [libRefNameGlob for libRefNameGlob in self.data 174 if fnmatch.fnmatch(photoCatName, libRefNameGlob)] 175 if len(matchList) == 1: 176 trueRefCatName = matchList[0] 177 ctDictConfig = self.data[trueRefCatName] 178 elif len(matchList) > 1: 179 raise ColortermNotFoundError( 180 "Multiple library globs match photoCatName %r: %s" % (photoCatName, matchList)) 182 raise ColortermNotFoundError( 183 "No colorterm dict found with photoCatName %r" % photoCatName) 184 ctDict = ctDictConfig.data 185 if filterName not in ctDict: 186 # Perhaps it's an alias 188 filterName = Filter(Filter(filterName).getId()).getName() 189 except pexExcept.NotFoundError: 190 pass # this will be handled shortly 191 if filterName not in ctDict: 192 errMsg = "No colorterm found for filter %r with photoCatName %r" % ( 193 filterName, photoCatName) 194 if trueRefCatName is not None: 195 errMsg += " = catalog %r" % (trueRefCatName,) 196 raise ColortermNotFoundError(errMsg) 197 return ctDict[filterName] 198 except ColortermNotFoundError: 202 return Colorterm(filterName, filterName) A mapping of filterName to Colorterm.
A mapping of photometric reference catalog name or glob to ColortermDict.
Colorterm correction for one pair of filters.