23 """Load reference catalog objects for input to FGCM.
25 This task will load multi-band reference objects and apply color terms (if
26 configured). This wrapper around LoadReferenceObjects task also allows loading
27 by healpix pixel (the native pixelization of fgcm), and is self-contained so
28 the task can be called by third-party code.
33 from astropy
import units
45 __all__ = [
'FgcmLoadReferenceCatalogConfig',
'FgcmLoadReferenceCatalogTask']
49 """Config for FgcmLoadReferenceCatalogTask"""
51 refObjLoader = pexConfig.ConfigurableField(
52 target=LoadIndexedReferenceObjectsTask,
53 doc=
"Reference object loader for photometry",
55 filterMap = pexConfig.DictField(
56 doc=
"Mapping from physicalFilter label to reference filter name.",
61 applyColorTerms = pexConfig.Field(
62 doc=(
"Apply photometric color terms to reference stars?"
63 "Requires that colorterms be set to a ColorTermLibrary"),
67 colorterms = pexConfig.ConfigField(
68 doc=
"Library of photometric reference catalog name to color term dict.",
69 dtype=ColortermLibrary,
71 referenceSelector = pexConfig.ConfigurableField(
72 target=ReferenceSourceSelectorTask,
73 doc=
"Selection of reference sources",
79 msg =
'Must set filterMap'
80 raise pexConfig.FieldValidationError(FgcmLoadReferenceCatalogConfig.filterMap, self, msg)
82 msg =
"applyColorTerms=True requires the `colorterms` field be set to a ColortermLibrary."
83 raise pexConfig.FieldValidationError(FgcmLoadReferenceCatalogConfig.colorterms, self, msg)
88 Load multi-band reference objects from a reference catalog.
92 butler: `lsst.daf.persistence.Butler`
93 Data butler for reading catalogs
95 ConfigClass = FgcmLoadReferenceCatalogConfig
96 _DefaultName =
'fgcmLoadReferenceCatalog'
98 def __init__(self, butler=None, refObjLoader=None, **kwargs):
99 """Construct an FgcmLoadReferenceCatalogTask
103 butler: `lsst.daf.persistence.Buter`
104 Data butler for reading catalogs.
106 pipeBase.Task.__init__(self, **kwargs)
107 if refObjLoader
is None and butler
is not None:
108 self.makeSubtask(
'refObjLoader', butler=butler)
112 self.makeSubtask(
'referenceSelector')
119 Get a reference catalog that overlaps a healpix pixel, using multiple
120 filters. In addition, apply colorterms if available.
122 Return format is a numpy recarray for use with fgcm, with the format:
124 dtype = ([('ra', `np.float64`),
125 ('dec', `np.float64`),
126 ('refMag', `np.float32`, len(filterList)),
127 ('refMagErr', `np.float32`, len(filterList)])
129 Reference magnitudes (AB) will be 99 for non-detections.
134 Healpix nside of pixel to load
136 Healpix pixel of pixel to load
138 list of `str` of camera filter names.
139 nest: `bool`, optional
140 Is the pixel in nest format? Default is False.
144 fgcmRefCat: `np.recarray`
148 theta, phi = hp.pix2ang(nside, pixel, nest=nest)
151 corners = hp.boundaries(nside, pixel, step=1, nest=nest)
152 theta_phi = hp.vec2ang(np.transpose(corners))
154 radius = 0.0 * lsst.geom.radians
155 for ctheta, cphi
in zip(*theta_phi):
157 (np.pi/2. - ctheta) * lsst.geom.radians))
163 center.getDec().asDegrees(),
166 catPix = hp.ang2pix(nside, np.radians(90.0 - fgcmRefCat[
'dec']),
167 np.radians(fgcmRefCat[
'ra']), nest=nest)
169 inPix, = np.where(catPix == pixel)
171 return fgcmRefCat[inPix]
175 Get a reference catalog that overlaps a circular sky region, using
176 multiple filters. In addition, apply colorterms if available.
178 Return format is a numpy recarray for use with fgcm.
180 dtype = ([('ra', `np.float64`),
181 ('dec', `np.float64`),
182 ('refMag', `np.float32`, len(filterList)),
183 ('refMagErr', `np.float32`, len(filterList)])
185 Reference magnitudes (AB) will be 99 for non-detections.
190 ICRS right ascension, degrees.
192 ICRS declination, degrees.
194 Radius to search, degrees.
196 list of `str` of camera filter names.
200 fgcmRefCat: `np.recarray`
209 skyCircle = self.
refObjLoaderrefObjLoader.loadSkyCircle(center,
210 radius * lsst.geom.degrees,
213 if not skyCircle.refCat.isContiguous():
214 refCat = skyCircle.refCat.copy(deep=
True)
216 refCat = skyCircle.refCat
219 goodSources = self.referenceSelector.selectSources(refCat)
220 selected = goodSources.selected
222 fgcmRefCat = np.zeros(np.sum(selected), dtype=[(
'ra',
'f8'),
224 (
'refMag',
'f4', len(filterList)),
225 (
'refMagErr',
'f4', len(filterList))])
226 if fgcmRefCat.size == 0:
236 conv = refCat[0][
'coord_ra'].asDegrees() / float(refCat[0][
'coord_ra'])
237 fgcmRefCat[
'ra'] = refCat[
'coord_ra'][selected] * conv
238 fgcmRefCat[
'dec'] = refCat[
'coord_dec'][selected] * conv
241 fgcmRefCat[
'refMag'][:, :] = 99.0
242 fgcmRefCat[
'refMagErr'][:, :] = 99.0
244 if self.config.applyColorTerms:
245 if isinstance(self.
refObjLoaderrefObjLoader, ReferenceObjectLoader):
247 refCatName = self.
refObjLoaderrefObjLoader.config.value.ref_dataset_name
250 refCatName = self.
refObjLoaderrefObjLoader.ref_dataset_name
253 if fluxField
is None:
256 self.log.
debug(
"Applying color terms for filtername=%r" % (filterName))
258 colorterm = self.config.colorterms.getColorterm(filterName, refCatName, doRaise=
True)
260 refMag, refMagErr = colorterm.getCorrectedMagnitudes(refCat)
266 good, = np.where((np.nan_to_num(refMag[selected]) < 90.0)
267 & (np.nan_to_num(refMagErr[selected]) < 90.0)
268 & (np.nan_to_num(refMagErr[selected]) > 0.0))
270 fgcmRefCat[
'refMag'][good, i] = refMag[selected][good]
271 fgcmRefCat[
'refMagErr'][good, i] = refMagErr[selected][good]
279 good, = np.where((np.nan_to_num(refCat[fluxField][selected]) > 0.0)
280 & (np.nan_to_num(refCat[fluxField+
'Err'][selected]) > 0.0))
281 refMag = (refCat[fluxField][selected][good] * units.nJy).to_value(units.ABmag)
283 refCat[fluxField][selected][good])
284 fgcmRefCat[
'refMag'][good, i] = refMag
285 fgcmRefCat[
'refMagErr'][good, i] = refMagErr
289 def _determine_flux_fields(self, center, filterList):
291 Determine the flux field names for a reference catalog.
293 Will set self._fluxFields, self._referenceFilter.
297 center: `lsst.geom.SpherePoint`
298 The center around which to load test sources.
300 list of `str` of camera filter names.
308 foundReferenceFilter =
False
309 for filterName
in filterList:
310 refFilterName = self.config.filterMap.get(filterName)
311 if refFilterName
is None:
315 results = self.
refObjLoaderrefObjLoader.loadSkyCircle(center,
316 0.05 * lsst.geom.degrees,
318 foundReferenceFilter =
True
326 if not foundReferenceFilter:
327 raise RuntimeError(
"Could not find any valid flux field(s) %s" %
328 (
", ".join(filterList)))
332 for filterName
in filterList:
335 refFilterName = self.config.filterMap.get(filterName)
337 if refFilterName
is not None:
339 fluxField =
getRefFluxField(results.refCat.schema, filterName=refFilterName)
344 if fluxField
is None:
345 self.log.
warning(f
'No reference flux field for camera filter {filterName}')
def __init__(self, butler=None, refObjLoader=None, **kwargs)
def getFgcmReferenceStarsSkyCircle(self, ra, dec, radius, filterList)
def _determine_flux_fields(self, center, filterList)
def getFgcmReferenceStarsHealpix(self, nside, pixel, filterList, nest=False)
Point in an unspecified spherical coordinate system.
std::shared_ptr< FrameSet > append(FrameSet const &first, FrameSet const &second)
Construct a FrameSet that performs two transformations in series.
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.
def getRefFluxField(schema, filterName=None)
Fit spatial kernel using approximate fluxes for candidates, and solving a linear system of equations.