25 import astropy.units
as u
30 __all__ = [
"ColortermNotFoundError",
"Colorterm",
"ColortermDict",
"ColortermLibrary"]
34 """Exception class indicating we couldn't find a colorterm
40 """!Colorterm correction for one pair of filters
42 The transformed magnitude p' is given by
43 p' = primary + c0 + c1*(primary - secondary) + c2*(primary - secondary)**2
45 To construct a Colorterm, use keyword arguments:
46 Colorterm(primary=primaryFilterName, secondary=secondaryFilterName, c0=c0value, c1=c1Coeff, c2=c2Coeff)
47 where c0-c2 are optional. For example (omitting c2):
48 Colorterm(primary="g", secondary="r", c0=-0.00816446, c1=-0.08366937)
50 This is subclass of Config. That is a bit of a hack to make it easy to store the data
51 in an appropriate obs_* package as a config override file. In the long term some other
52 means of persistence will be used, at which point the constructor can be simplified
53 to not require keyword arguments. (Fixing DM-2831 will also allow making a custom constructor).
55 primary = Field(dtype=str, doc=
"name of primary filter")
56 secondary = Field(dtype=str, doc=
"name of secondary filter")
57 c0 = Field(dtype=float, default=0.0, doc=
"Constant parameter")
58 c1 = Field(dtype=float, default=0.0, doc=
"First-order parameter")
59 c2 = Field(dtype=float, default=0.0, doc=
"Second-order parameter")
62 """Return the colorterm corrected magnitudes for a given filter.
66 refCat : `lsst.afw.table.SimpleCatalog`
67 The reference catalog to apply color corrections to.
69 The camera filter to correct the reference catalog into.
74 The corrected AB magnitudes.
75 RefMagErr : `np.ndarray`
76 The corrected AB magnitude errors.
81 Raised if the reference catalog does not have a flux uncertainty
86 WARNING: I do not know that we can trust the propagation of magnitude
87 errors returned by this method. They need more thorough tests.
90 def getFluxes(fluxField):
91 """Get the flux and fluxErr of this field from refCat."""
92 fluxKey = refCat.schema.find(fluxField).key
93 refFlux = refCat[fluxKey]
95 fluxErrKey = refCat.schema.find(fluxField +
"Err").key
96 refFluxErr = refCat[fluxErrKey]
98 raise KeyError(
"Reference catalog does not have flux uncertainties for %s" % fluxField)
from e
100 return refFlux, refFluxErr
102 primaryFlux, primaryErr = getFluxes(self.
primaryprimary +
"_flux")
103 secondaryFlux, secondaryErr = getFluxes(self.
secondarysecondary +
"_flux")
105 primaryMag = u.Quantity(primaryFlux, u.nJy).to_value(u.ABmag)
106 secondaryMag = u.Quantity(secondaryFlux, u.nJy).to_value(u.ABmag)
108 refMag = self.
transformMagstransformMags(primaryMag, secondaryMag)
112 refMagErr = abMagErrFromFluxErr(refFluxErrArr*1e-9, primaryFlux*1e-9)
114 return refMag, refMagErr
117 """!Transform the brightness of a source
119 @param[in] source source whose brightness is to be converted; must support get(filterName)
120 (e.g. source.get("r")) method, as do afw::table::Source and dicts.
121 @return the transformed source magnitude
126 """!Transform brightness
128 @param[in] primary brightness in primary filter (magnitude)
129 @param[in] secondary brightness in secondary filter (magnitude)
130 @return the transformed brightness (as a magnitude)
132 color = primary - secondary
133 return primary + self.
c0c0 + color*(self.
c1c1 + color*self.
c2c2)
136 return np.hypot((1 + self.
c1c1)*primaryFluxErr, self.
c1c1*secondaryFluxErr)
140 """!A mapping of filterName to Colorterm
142 Different reference catalogs may need different ColortermDicts; see ColortermLibrary
144 To construct a ColortermDict use keyword arguments:
145 ColortermDict(data=dataDict)
146 where dataDict is a Python dict of filterName: Colorterm
149 'g': Colorterm(primary="g", secondary="r", c0=-0.00816446, c1=-0.08366937, c2=-0.00726883),
150 'r': Colorterm(primary="r", secondary="i", c0= 0.00231810, c1= 0.01284177, c2=-0.03068248),
151 'i': Colorterm(primary="i", secondary="z", c0= 0.00130204, c1=-0.16922042, c2=-0.01374245),
153 The constructor will likely be simplified at some point.
155 This is subclass of Config. That is a bit of a hack to make it easy to store the data
156 in an appropriate obs_* package as a config override file. In the long term some other
157 means of persistence will be used, at which point the constructor can be made saner.
159 data = ConfigDictField(
160 doc=
"Mapping of filter name to Colorterm",
168 """!A mapping of photometric reference catalog name or glob to ColortermDict
170 This allows photometric calibration using a variety of reference catalogs.
172 To construct a ColortermLibrary, use keyword arguments:
173 ColortermLibrary(data=dataDict)
174 where dataDict is a Python dict of catalog_name_or_glob: ColortermDict
177 ColortermLibrary(data = {
178 "hsc*": ColortermDict(data={
179 'g': Colorterm(primary="g", secondary="g"),
180 'r': Colorterm(primary="r", secondary="r"),
183 "sdss*": ColortermDict(data={
184 'g': Colorterm(primary="g", secondary="r", c0=-0.00816446, c1=-0.08366937, c2=-0.00726883),
185 'r': Colorterm(primary="r", secondary="i", c0= 0.00231810, c1= 0.01284177, c2=-0.03068248),
190 This is subclass of Config. That is a bit of a hack to make it easy to store the data
191 in an appropriate obs_* package as a config override file. In the long term some other
192 means of persistence will be used, at which point the constructor can be made saner.
194 data = ConfigDictField(
195 doc=
"Mapping of reference catalog name (or glob) to ColortermDict",
197 itemtype=ColortermDict,
202 """!Get the appropriate Colorterm from the library
204 Use dict of color terms in the library that matches the photoCatName.
205 If the photoCatName exactly matches an entry in the library, that
206 dict is used; otherwise if the photoCatName matches a single glob (shell syntax,
207 e.g., "sdss-*" will match "sdss-dr8"), then that is used. If there is no
208 exact match and no unique match to the globs, raise an exception.
210 @param filterName name of filter
211 @param photoCatName name of photometric reference catalog from which to retrieve the data.
212 This argument is not glob-expanded (but the catalog names in the library are,
213 if no exact match is found).
214 @param[in] doRaise if True then raise ColortermNotFoundError if no suitable Colorterm found;
215 if False then return a null Colorterm with filterName as the primary and secondary filter
216 @return the appropriate Colorterm
218 @throw ColortermNotFoundError if no suitable Colorterm found and doRaise true;
219 other exceptions may be raised for unexpected errors, regardless of the value of doRaise
222 trueRefCatName =
None
223 ctDictConfig = self.
datadata.get(photoCatName)
224 if ctDictConfig
is None:
226 matchList = [libRefNameGlob
for libRefNameGlob
in self.
datadata
227 if fnmatch.fnmatch(photoCatName, libRefNameGlob)]
228 if len(matchList) == 1:
229 trueRefCatName = matchList[0]
230 ctDictConfig = self.
datadata[trueRefCatName]
231 elif len(matchList) > 1:
233 "Multiple library globs match photoCatName %r: %s" % (photoCatName, matchList))
236 "No colorterm dict found with photoCatName %r" % photoCatName)
237 ctDict = ctDictConfig.data
238 if filterName
not in ctDict:
239 errMsg =
"No colorterm found for filter %r with photoCatName %r" % (
240 filterName, photoCatName)
241 if trueRefCatName
is not None:
242 errMsg +=
" = catalog %r" % (trueRefCatName,)
244 return ctDict[filterName]
245 except ColortermNotFoundError:
A mapping of filterName to Colorterm.
Colorterm correction for one pair of filters.
def propagateFluxErrors(self, primaryFluxErr, secondaryFluxErr)
def getCorrectedMagnitudes(self, refCat, filterName)
def transformMags(self, primary, secondary)
Transform brightness.
def transformSource(self, source)
Transform the brightness of a source.
A mapping of photometric reference catalog name or glob to ColortermDict.
def getColorterm(self, filterName, photoCatName, doRaise=True)
Get the appropriate Colorterm from the library.