25 import astropy.units
as u
29 from lsst.pex.config
import Config, Field, ConfigDictField
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 getCorrectedMagnitudes(self, refCat, filterName): 64 """Return the colorterm corrected magnitudes
for a given filter.
69 The reference catalog to apply color corrections to.
71 The camera filter to correct the reference catalog into.
76 The corrected AB magnitudes.
77 RefMagErr : `np.ndarray`
78 The corrected AB magnitude errors.
83 Raised
if the reference catalog does
not have a flux uncertainty
88 WARNING: I do
not know that we can trust the propagation of magnitude
89 errors returned by this method. They need more thorough tests.
92 def getFluxes(fluxField): 93 """Get the flux
and fluxErr of this field
from refCat.
""" 94 fluxKey = refCat.schema.find(fluxField).key 95 refFlux = refCat[fluxKey] 97 fluxErrKey = refCat.schema.find(fluxField + "Err").key 98 refFluxErr = refCat[fluxErrKey] 100 raise KeyError("Reference catalog does not have flux uncertainties for %s" % fluxField) from e 102 return refFlux, refFluxErr 104 primaryFlux, primaryErr = getFluxes(self.primary + "_flux") 105 secondaryFlux, secondaryErr = getFluxes(self.secondary + "_flux") 107 primaryMag = u.Quantity(primaryFlux, u.nJy).to_value(u.ABmag) 108 secondaryMag = u.Quantity(secondaryFlux, u.nJy).to_value(u.ABmag) 110 refMag = self.transformMags(primaryMag, secondaryMag) 111 refFluxErrArr = self.propagateFluxErrors(primaryErr, secondaryErr) 113 # HACK convert to Jy until we have a replacement for this (DM-16903) 114 refMagErr = abMagErrFromFluxErr(refFluxErrArr*1e-9, primaryFlux*1e-9) 116 return refMag, refMagErr 118 def transformSource(self, source): 119 """!Transform the brightness of a source
121 @param[
in] source source whose brightness
is to be converted; must support get(filterName)
122 (e.g. source.get(
"r")) method, as do afw::table::Source and dicts. 123 @return the transformed source magnitude
125 return self.transformMags(source.get(self.primary), source.get(self.secondary)) 127 def transformMags(self, primary, secondary): 128 """!Transform brightness
130 @param[
in] primary brightness
in primary filter (magnitude)
131 @param[
in] secondary brightness
in secondary filter (magnitude)
132 @
return the transformed brightness (
as a magnitude)
134 color = primary - secondary 135 return primary + self.c0 + color*(self.c1 + color*self.c2) 137 def propagateFluxErrors(self, primaryFluxErr, secondaryFluxErr): 138 return np.hypot((1 + self.c1)*primaryFluxErr, self.c1*secondaryFluxErr) 141 class ColortermDict(Config): 142 """!A mapping of filterName to Colorterm
144 Different reference catalogs may need different ColortermDicts; see ColortermLibrary
146 To construct a ColortermDict use keyword arguments:
148 where dataDict
is a Python dict of filterName: Colorterm
151 'g':
Colorterm(primary=
"g", secondary=
"r", c0=-0.00816446, c1=-0.08366937, c2=-0.00726883), 152 'r': Colorterm(primary="r", secondary="i", c0= 0.00231810, c1= 0.01284177, c2=-0.03068248),
153 'i':
Colorterm(primary=
"i", secondary=
"z", c0= 0.00130204, c1=-0.16922042, c2=-0.01374245),
155 The constructor will likely be simplified at some point.
157 This
is subclass of Config. That
is a bit of a hack to make it easy to store the data
158 in an appropriate obs_* package
as a config override file. In the long term some other
159 means of persistence will be used, at which point the constructor can be made saner.
161 data = ConfigDictField( 162 doc="Mapping of filter name to Colorterm", 169 class ColortermLibrary(Config): 170 """!A mapping of photometric reference catalog name
or glob to ColortermDict
172 This allows photometric calibration using a variety of reference catalogs.
174 To construct a ColortermLibrary, use keyword arguments:
176 where dataDict
is a Python dict of catalog_name_or_glob: ColortermDict
181 'g':
Colorterm(primary=
"g", secondary=
"g"),
182 'r': Colorterm(primary="r", secondary="r"), 186 'g':
Colorterm(primary=
"g", secondary=
"r", c0=-0.00816446, c1=-0.08366937, c2=-0.00726883), 187 'r': Colorterm(primary="r", secondary="i", c0= 0.00231810, c1= 0.01284177, c2=-0.03068248),
192 This
is subclass of Config. That
is a bit of a hack to make it easy to store the data
193 in an appropriate obs_* package
as a config override file. In the long term some other
194 means of persistence will be used, at which point the constructor can be made saner.
196 data = ConfigDictField( 197 doc="Mapping of reference catalog name (or glob) to ColortermDict", 199 itemtype=ColortermDict, 203 def getColorterm(self, filterName, photoCatName, doRaise=True): 204 """!Get the appropriate Colorterm
from the library
206 Use dict of color terms
in the library that matches the photoCatName.
207 If the photoCatName exactly matches an entry
in the library, that
208 dict
is used; otherwise
if the photoCatName matches a single glob (shell syntax,
209 e.g.,
"sdss-*" will match
"sdss-dr8"), then that
is used. If there
is no
210 exact match
and no unique match to the globs,
raise an exception.
212 @param filterName name of filter
213 @param photoCatName name of photometric reference catalog
from which to retrieve the data.
214 This argument
is not glob-expanded (but the catalog names
in the library are,
215 if no exact match
is found).
216 @param[
in] doRaise
if True then
raise ColortermNotFoundError
if no suitable Colorterm found;
217 if False then
return a null Colorterm with filterName
as the primary
and secondary filter
218 @
return the appropriate Colorterm
220 @throw ColortermNotFoundError
if no suitable Colorterm found
and doRaise true;
221 other exceptions may be raised
for unexpected errors, regardless of the value of doRaise
224 trueRefCatName = None 225 ctDictConfig = self.data.get(photoCatName) 226 if ctDictConfig is None: 227 # try glob expression 228 matchList = [libRefNameGlob for libRefNameGlob in self.data 229 if fnmatch.fnmatch(photoCatName, libRefNameGlob)] 230 if len(matchList) == 1: 231 trueRefCatName = matchList[0] 232 ctDictConfig = self.data[trueRefCatName] 233 elif len(matchList) > 1: 234 raise ColortermNotFoundError( 235 "Multiple library globs match photoCatName %r: %s" % (photoCatName, matchList)) 237 raise ColortermNotFoundError( 238 "No colorterm dict found with photoCatName %r" % photoCatName) 239 ctDict = ctDictConfig.data 240 if filterName not in ctDict: 241 # Perhaps it's an alias 243 filterName = Filter(Filter(filterName).getId()).getName() 244 except pexExcept.NotFoundError: 245 pass # this will be handled shortly 246 if filterName not in ctDict: 247 errMsg = "No colorterm found for filter %r with photoCatName %r" % ( 248 filterName, photoCatName) 249 if trueRefCatName is not None: 250 errMsg += " = catalog %r" % (trueRefCatName,) 251 raise ColortermNotFoundError(errMsg) 252 return ctDict[filterName] 253 except ColortermNotFoundError: 257 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.