LSST Applications  21.0.0-172-gfb10e10a+18fedfabac,22.0.0+297cba6710,22.0.0+80564b0ff1,22.0.0+8d77f4f51a,22.0.0+a28f4c53b1,22.0.0+dcf3732eb2,22.0.1-1-g7d6de66+2a20fdde0d,22.0.1-1-g8e32f31+297cba6710,22.0.1-1-geca5380+7fa3b7d9b6,22.0.1-12-g44dc1dc+2a20fdde0d,22.0.1-15-g6a90155+515f58c32b,22.0.1-16-g9282f48+790f5f2caa,22.0.1-2-g92698f7+dcf3732eb2,22.0.1-2-ga9b0f51+7fa3b7d9b6,22.0.1-2-gd1925c9+bf4f0e694f,22.0.1-24-g1ad7a390+a9625a72a8,22.0.1-25-g5bf6245+3ad8ecd50b,22.0.1-25-gb120d7b+8b5510f75f,22.0.1-27-g97737f7+2a20fdde0d,22.0.1-32-gf62ce7b1+aa4237961e,22.0.1-4-g0b3f228+2a20fdde0d,22.0.1-4-g243d05b+871c1b8305,22.0.1-4-g3a563be+32dcf1063f,22.0.1-4-g44f2e3d+9e4ab0f4fa,22.0.1-42-gca6935d93+ba5e5ca3eb,22.0.1-5-g15c806e+85460ae5f3,22.0.1-5-g58711c4+611d128589,22.0.1-5-g75bb458+99c117b92f,22.0.1-6-g1c63a23+7fa3b7d9b6,22.0.1-6-g50866e6+84ff5a128b,22.0.1-6-g8d3140d+720564cf76,22.0.1-6-gd805d02+cc5644f571,22.0.1-8-ge5750ce+85460ae5f3,master-g6e05de7fdc+babf819c66,master-g99da0e417a+8d77f4f51a,w.2021.48
LSST Data Management Base Package
colorterms.py
Go to the documentation of this file.
1 #
2 # LSST Data Management System
3 # Copyright 2008, 2009, 2010, 2011 LSST Corporation.
4 #
5 # This product includes software developed by the
6 # LSST Project (http://www.lsst.org/).
7 #
8 # This program is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
12 #
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the LSST License Statement and
19 # the GNU General Public License along with this program. If not,
20 # see <http://www.lsstcorp.org/LegalNotices/>.
21 #
22 import fnmatch
23 import warnings
24 
25 import numpy as np
26 import astropy.units as u
27 
28 from lsst.afw.image import abMagErrFromFluxErr
29 from lsst.pex.config import Config, Field, ConfigDictField
30 
31 __all__ = ["ColortermNotFoundError", "Colorterm", "ColortermDict", "ColortermLibrary"]
32 
33 
34 class ColortermNotFoundError(LookupError):
35  """Exception class indicating we couldn't find a colorterm
36  """
37  pass
38 
39 
41  """!Colorterm correction for one pair of filters
42 
43  The transformed magnitude p' is given by
44  p' = primary + c0 + c1*(primary - secondary) + c2*(primary - secondary)**2
45 
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)
50 
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).
55  """
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")
61 
62  def getCorrectedMagnitudes(self, refCat, filterName="deprecatedArgument"):
63  """Return the colorterm corrected magnitudes for a given filter.
64 
65  Parameters
66  ----------
67  refCat : `lsst.afw.table.SimpleCatalog`
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.
72 
73  Returns
74  -------
75  RefMag : `np.ndarray`
76  The corrected AB magnitudes.
77  RefMagErr : `np.ndarray`
78  The corrected AB magnitude errors.
79 
80  Raises
81  ------
82  KeyError
83  Raised if the reference catalog does not have a flux uncertainty
84  for that filter.
85 
86  Notes
87  -----
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.
90  """
91 
92  if filterName != "deprecatedArgument":
93  msg = "Colorterm.getCorrectedMagnitudes() `filterName` arg is unused and will be removed in v23."
94  warnings.warn(msg, category=FutureWarning)
95 
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]
100  try:
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
105 
106  return refFlux, refFluxErr
107 
108  primaryFlux, primaryErr = getFluxes(self.primaryprimary + "_flux")
109  secondaryFlux, secondaryErr = getFluxes(self.secondarysecondary + "_flux")
110 
111  primaryMag = u.Quantity(primaryFlux, u.nJy).to_value(u.ABmag)
112  secondaryMag = u.Quantity(secondaryFlux, u.nJy).to_value(u.ABmag)
113 
114  refMag = self.transformMagstransformMags(primaryMag, secondaryMag)
115  refFluxErrArr = self.propagateFluxErrorspropagateFluxErrors(primaryErr, secondaryErr)
116 
117  # HACK convert to Jy until we have a replacement for this (DM-16903)
118  refMagErr = abMagErrFromFluxErr(refFluxErrArr*1e-9, primaryFlux*1e-9)
119 
120  return refMag, refMagErr
121 
122  def transformSource(self, source):
123  """!Transform the brightness of a source
124 
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
128  """
129  return self.transformMagstransformMags(source.get(self.primaryprimary), source.get(self.secondarysecondary))
130 
131  def transformMags(self, primary, secondary):
132  """!Transform brightness
133 
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)
137  """
138  color = primary - secondary
139  return primary + self.c0c0 + color*(self.c1c1 + color*self.c2c2)
140 
141  def propagateFluxErrors(self, primaryFluxErr, secondaryFluxErr):
142  return np.hypot((1 + self.c1c1)*primaryFluxErr, self.c1c1*secondaryFluxErr)
143 
144 
146  """A mapping of physical filter label to Colorterm
147 
148  Different reference catalogs may need different ColortermDicts; see ColortermLibrary
149 
150  To construct a ColortermDict use keyword arguments:
151  ColortermDict(data=dataDict)
152  where dataDict is a Python dict of filterName: Colorterm
153  For example:
154  ColortermDict(data={
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),
158  })
159  The constructor will likely be simplified at some point.
160 
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.
164  """
166  doc="Mapping of filter name to Colorterm",
167  keytype=str,
168  itemtype=Colorterm,
169  default={},
170  )
171 
172 
174  """!A mapping of photometric reference catalog name or glob to ColortermDict
175 
176  This allows photometric calibration using a variety of reference catalogs.
177 
178  To construct a ColortermLibrary, use keyword arguments:
179  ColortermLibrary(data=dataDict)
180  where dataDict is a Python dict of catalog_name_or_glob: ColortermDict
181 
182  For example:
183  ColortermLibrary(data = {
184  "hsc*": ColortermDict(data={
185  'g': Colorterm(primary="g", secondary="g"),
186  'r': Colorterm(primary="r", secondary="r"),
187  ...
188  }),
189  "sdss*": ColortermDict(data={
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),
192  ...
193  }),
194  })
195 
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.
199  """
201  doc="Mapping of reference catalog name (or glob) to ColortermDict",
202  keytype=str,
203  itemtype=ColortermDict,
204  default={},
205  )
206 
207  def getColorterm(self, physicalFilter, photoCatName, doRaise=True):
208  """!Get the appropriate Colorterm from the library
209 
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.
215 
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
223 
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
226  """
227  try:
228  trueRefCatName = None
229  ctDictConfig = self.datadata.get(photoCatName)
230  if ctDictConfig is None:
231  # try glob expression
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))
240  else:
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,)
249  raise ColortermNotFoundError(errMsg)
250  return ctDict[physicalFilter]
251  except ColortermNotFoundError:
252  if doRaise:
253  raise
254  else:
255  return Colorterm(physicalFilter, physicalFilter)
Colorterm correction for one pair of filters.
Definition: colorterms.py:40
def propagateFluxErrors(self, primaryFluxErr, secondaryFluxErr)
Definition: colorterms.py:141
def transformMags(self, primary, secondary)
Transform brightness.
Definition: colorterms.py:131
def getCorrectedMagnitudes(self, refCat, filterName="deprecatedArgument")
Definition: colorterms.py:62
def transformSource(self, source)
Transform the brightness of a source.
Definition: colorterms.py:122
A mapping of photometric reference catalog name or glob to ColortermDict.
Definition: colorterms.py:173
def getColorterm(self, physicalFilter, photoCatName, doRaise=True)
Get the appropriate Colorterm from the library.
Definition: colorterms.py:207
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
double abMagErrFromFluxErr(double fluxErr, double flux)
Compute AB magnitude error from flux and flux error in Janskys.
Definition: Calib.h:52