26import astropy.units
as u
31__all__ = [
"ColortermNotFoundError",
"Colorterm",
"ColortermDict",
"ColortermLibrary"]
35 """Exception class indicating we couldn't find a colorterm
41 """!Colorterm correction for one pair of filters
43 The transformed magnitude p' is given by
44 p' = primary + c0 + c1*(primary - secondary) + c2*(primary - secondary)**2
46 To construct a Colorterm, use keyword arguments:
47 Colorterm(primary=primaryFilterName, secondary=secondaryFilterName, c0=c0value, c1=c1Coeff, c2=c2Coeff)
48 where c0-c2 are optional. For example (omitting c2):
49 Colorterm(primary="g", secondary=
"r", c0=-0.00816446, c1=-0.08366937)
51 This
is subclass of Config. That
is a bit of a hack to make it easy to store the data
52 in an appropriate obs_* package
as a config override file. In the long term some other
53 means of persistence will be used, at which point the constructor can be simplified
54 to
not require keyword arguments. (Fixing DM-2831 will also allow making a custom constructor).
56 primary = Field(dtype=str, doc="name of primary filter")
57 secondary = Field(dtype=str, doc=
"name of secondary filter")
58 c0 = Field(dtype=float, default=0.0, doc=
"Constant parameter")
59 c1 = Field(dtype=float, default=0.0, doc=
"First-order parameter")
60 c2 = Field(dtype=float, default=0.0, doc=
"Second-order parameter")
63 """Return the colorterm corrected magnitudes for a given filter.
68 The reference catalog to apply color corrections to.
69 filterName : `str`, deprecated
70 The camera filter to correct the reference catalog into.
71 The ``filterName`` argument is unused
and will be removed
in v23.
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 if filterName !=
"deprecatedArgument":
93 msg =
"Colorterm.getCorrectedMagnitudes() `filterName` arg is unused and will be removed in v23."
94 warnings.warn(msg, category=FutureWarning)
96 def getFluxes(fluxField):
97 """Get the flux and fluxErr of this field from refCat."""
98 fluxKey = refCat.schema.find(fluxField).key
99 refFlux = refCat[fluxKey]
101 fluxErrKey = refCat.schema.find(fluxField +
"Err").key
102 refFluxErr = refCat[fluxErrKey]
103 except KeyError
as e:
104 raise KeyError(
"Reference catalog does not have flux uncertainties for %s" % fluxField)
from e
106 return refFlux, refFluxErr
108 primaryFlux, primaryErr = getFluxes(self.
primaryprimary +
"_flux")
109 secondaryFlux, secondaryErr = getFluxes(self.
secondarysecondary +
"_flux")
111 primaryMag = u.Quantity(primaryFlux, u.nJy).to_value(u.ABmag)
112 secondaryMag = u.Quantity(secondaryFlux, u.nJy).to_value(u.ABmag)
114 refMag = self.
transformMagstransformMags(primaryMag, secondaryMag)
118 refMagErr = abMagErrFromFluxErr(refFluxErrArr*1e-9, primaryFlux*1e-9)
120 return refMag, refMagErr
123 """!Transform the brightness of a source
125 @param[
in] source source whose brightness
is to be converted; must support get(filterName)
126 (e.g. source.get(
"r")) method,
as do afw::table::Source
and dicts.
127 @return the transformed source magnitude
132 """!Transform brightness
134 @param[
in] primary brightness
in primary filter (magnitude)
135 @param[
in] secondary brightness
in secondary filter (magnitude)
136 @return the transformed brightness (
as a magnitude)
138 color = primary - secondary
139 return primary + self.
c0c0 + color*(self.
c1c1 + color*self.
c2c2)
142 return np.hypot((1 + self.
c1c1)*primaryFluxErr, self.
c1c1*secondaryFluxErr)
146 """A mapping of physical filter label to Colorterm
148 Different reference catalogs may need different ColortermDicts; see ColortermLibrary
150 To construct a ColortermDict use keyword arguments:
152 where dataDict is a Python dict of filterName: Colorterm
155 'g':
Colorterm(primary=
"g", secondary=
"r", c0=-0.00816446, c1=-0.08366937, c2=-0.00726883),
156 'r':
Colorterm(primary=
"r", secondary=
"i", c0= 0.00231810, c1= 0.01284177, c2=-0.03068248),
157 'i':
Colorterm(primary=
"i", secondary=
"z", c0= 0.00130204, c1=-0.16922042, c2=-0.01374245),
159 The constructor will likely be simplified at some point.
161 This
is subclass of Config. That
is a bit of a hack to make it easy to store the data
162 in an appropriate obs_* package
as a config override file. In the long term some other
163 means of persistence will be used, at which point the constructor can be made saner.
165 data = ConfigDictField(
166 doc="Mapping of filter name to Colorterm",
174 """!A mapping of photometric reference catalog name or glob to ColortermDict
176 This allows photometric calibration using a variety of reference catalogs.
178 To construct a ColortermLibrary, use keyword arguments:
180 where dataDict is a Python dict of catalog_name_or_glob: ColortermDict
185 'g':
Colorterm(primary=
"g", secondary=
"g"),
186 'r':
Colorterm(primary=
"r", secondary=
"r"),
190 'g':
Colorterm(primary=
"g", secondary=
"r", c0=-0.00816446, c1=-0.08366937, c2=-0.00726883),
191 'r':
Colorterm(primary=
"r", secondary=
"i", c0= 0.00231810, c1= 0.01284177, c2=-0.03068248),
196 This
is subclass of Config. That
is a bit of a hack to make it easy to store the data
197 in an appropriate obs_* package
as a config override file. In the long term some other
198 means of persistence will be used, at which point the constructor can be made saner.
200 data = ConfigDictField(
201 doc="Mapping of reference catalog name (or glob) to ColortermDict",
203 itemtype=ColortermDict,
208 """!Get the appropriate Colorterm from the library
210 Use dict of color terms in the library that matches the photoCatName.
211 If the photoCatName exactly matches an entry
in the library, that
212 dict
is used; otherwise
if the photoCatName matches a single glob (shell syntax,
213 e.g.,
"sdss-*" will match
"sdss-dr8"), then that
is used. If there
is no
214 exact match
and no unique match to the globs,
raise an exception.
216 @param physicalFilter Label of physical filter to correct to.
217 @param photoCatName name of photometric reference catalog
from which to retrieve the data.
218 This argument
is not glob-expanded (but the catalog names
in the library are,
219 if no exact match
is found).
220 @param[
in] doRaise
if True then
raise ColortermNotFoundError
if no suitable Colorterm found;
221 if False then
return a null Colorterm
with physicalFilter
as the primary
and secondary filter
222 @return the appropriate Colorterm
224 @throw ColortermNotFoundError
if no suitable Colorterm found
and doRaise true;
225 other exceptions may be raised
for unexpected errors, regardless of the value of doRaise
228 trueRefCatName =
None
229 ctDictConfig = self.
datadata.get(photoCatName)
230 if ctDictConfig
is None:
232 matchList = [libRefNameGlob
for libRefNameGlob
in self.
datadata
233 if fnmatch.fnmatch(photoCatName, libRefNameGlob)]
234 if len(matchList) == 1:
235 trueRefCatName = matchList[0]
236 ctDictConfig = self.
datadata[trueRefCatName]
237 elif len(matchList) > 1:
239 "Multiple library globs match photoCatName %r: %s" % (photoCatName, matchList))
242 "No colorterm dict found with photoCatName %r" % photoCatName)
243 ctDict = ctDictConfig.data
244 if physicalFilter
not in ctDict:
245 errMsg =
"No colorterm found for filter %r with photoCatName %r" % (
246 physicalFilter, photoCatName)
247 if trueRefCatName
is not None:
248 errMsg +=
" = catalog %r" % (trueRefCatName,)
250 return ctDict[physicalFilter]
251 except ColortermNotFoundError:
255 return Colorterm(physicalFilter, physicalFilter)
Colorterm correction for one pair of filters.
def propagateFluxErrors(self, primaryFluxErr, secondaryFluxErr)
def transformMags(self, primary, secondary)
Transform brightness.
def getCorrectedMagnitudes(self, refCat, filterName="deprecatedArgument")
def transformSource(self, source)
Transform the brightness of a source.
A mapping of photometric reference catalog name or glob to ColortermDict.
def getColorterm(self, physicalFilter, photoCatName, doRaise=True)
Get the appropriate Colorterm from the library.