21"""Base class for running fgcmcal on a single tract using src tables
22or sourceTable_visit tables.
32from .fgcmBuildStarsTable
import FgcmBuildStarsTableTask
33from .fgcmFitCycle
import FgcmFitCycleConfig
34from .fgcmOutputProducts
import FgcmOutputProductsTask
35from .utilities
import makeConfigDict, translateFgcmLut, translateVisitCatalog
36from .utilities
import computeApertureRadiusFromName, extractReferenceMags
37from .utilities
import makeZptSchema, makeZptCat
38from .utilities
import makeAtmSchema, makeAtmCat
39from .utilities
import makeStdSchema, makeStdCat
40from .focalPlaneProjector
import FocalPlaneProjector
44__all__ = [
'FgcmCalibrateTractConfigBase',
'FgcmCalibrateTractBaseTask']
48 """Config for FgcmCalibrateTract"""
50 fgcmBuildStars = pexConfig.ConfigurableField(
51 target=FgcmBuildStarsTableTask,
52 doc=
"Task to load and match stars for fgcm",
54 fgcmFitCycle = pexConfig.ConfigField(
55 dtype=FgcmFitCycleConfig,
56 doc=
"Config to run a single fgcm fit cycle",
58 fgcmOutputProducts = pexConfig.ConfigurableField(
59 target=FgcmOutputProductsTask,
60 doc=
"Task to output fgcm products",
62 convergenceTolerance = pexConfig.Field(
63 doc=
"Tolerance on repeatability convergence (per band)",
67 maxFitCycles = pexConfig.Field(
68 doc=
"Maximum number of fit cycles",
72 doDebuggingPlots = pexConfig.Field(
73 doc=
"Make plots for debugging purposes?",
79 pexConfig.Config.setDefaults(self)
90 if not self.
fgcmFitCycle.useRepeatabilityForExpGrayCutsDict[band]:
91 msg =
'Must set useRepeatabilityForExpGrayCutsDict[band]=True for all bands'
92 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.useRepeatabilityForExpGrayCutsDict,
97 """Base class to calibrate a single tract using fgcmcal
99 def __init__(self, initInputs=None, **kwargs):
100 super().__init__(**kwargs)
101 self.makeSubtask(
"fgcmBuildStars", initInputs=initInputs)
102 self.makeSubtask(
"fgcmOutputProducts")
104 def run(self, handleDict, tract,
105 buildStarsRefObjLoader=None, returnCatalogs=True):
106 """Run the calibrations for a single tract with fgcm.
111 All handles are `lsst.daf.butler.DeferredDatasetHandle`
112 handle dictionary with the following keys. Note that all
113 keys need
not be set based on config parameters.
117 ``
"source_catalogs"``
118 `list` of handles
for input source catalogs.
120 Schema
for the source catalogs.
121 ``
"fgcmLookUpTable"``
122 handle
for the FGCM look-up table.
124 `list` of handles
for the input calexps
125 ``
"fgcmPhotoCalibs"``
126 `dict` of output photoCalib handles. Key
is
127 (tract, visit, detector).
128 Present
if doZeropointOutput
is True.
129 ``
"fgcmTransmissionAtmospheres"``
130 `dict` of output atmosphere transmission handles.
131 Key
is (tract, visit).
132 Present
if doAtmosphereOutput
is True.
136 Reference object loader object
for fgcmBuildStars.
137 returnCatalogs : `bool`, optional
138 Return photoCalibs
as per-visit exposure catalogs.
142 outstruct : `lsst.pipe.base.Struct`
143 Output structure
with keys:
145 offsets : `np.ndarray`
146 Final reference offsets, per band.
147 repeatability : `np.ndarray`
148 Raw fgcm repeatability
for bright stars, per band.
150 Generator that returns (visit, transmissionCurve) tuples.
152 Generator that returns (visit, ccd, filtername, photoCalib) tuples.
153 (returned
if returnCatalogs
is False).
155 Generator that returns (visit, exposureCatalog) tuples.
156 (returned
if returnCatalogs
is True).
158 self.log.info("Running on tract %d", (tract))
162 calibFluxApertureRadius =
None
163 if self.config.fgcmBuildStars.doSubtractLocalBackground:
165 field = self.config.fgcmBuildStars.instFluxField
166 calibFluxApertureRadius = computeApertureRadiusFromName(field)
168 raise RuntimeError(
"Could not determine aperture radius from %s. "
169 "Cannot use doSubtractLocalBackground." %
175 groupedHandles = self.fgcmBuildStars._groupHandles(handleDict[
'sourceTableHandleDict'],
176 handleDict[
'visitSummaryHandleDict'])
177 visitCat = self.fgcmBuildStars.fgcmMakeVisitCatalog(handleDict[
'camera'], groupedHandles)
178 rad = calibFluxApertureRadius
179 fgcmStarObservationCat = self.fgcmBuildStars.fgcmMakeAllStarObservations(groupedHandles,
181 handleDict[
'sourceSchema'],
182 handleDict[
'camera'],
183 calibFluxApertureRadius=rad)
185 if self.fgcmBuildStars.config.doReferenceMatches:
186 lutHandle = handleDict[
'fgcmLookUpTable']
187 self.fgcmBuildStars.makeSubtask(
"fgcmLoadReferenceCatalog",
188 refObjLoader=buildStarsRefObjLoader,
189 refCatName=self.fgcmBuildStars.config.connections.refCat)
193 fgcmStarIdCat, fgcmStarIndicesCat, fgcmRefCat = \
194 self.fgcmBuildStars.fgcmMatchStars(visitCat,
195 fgcmStarObservationCat,
199 lutCat = handleDict[
'fgcmLookUpTable'].get()
200 fgcmLut, lutIndexVals, lutStd = translateFgcmLut(lutCat,
201 dict(self.config.fgcmFitCycle.physicalFilterMap))
205 fgcmExpInfo = translateVisitCatalog(visitCat)
207 configDict = makeConfigDict(self.config.fgcmFitCycle, self.log, handleDict[
'camera'],
208 self.config.fgcmFitCycle.maxIterBeforeFinalCycle,
209 True,
False, lutIndexVals[0][
'FILTERNAMES'],
213 self.config.fgcmFitCycle.defaultCameraOrientation)
217 noFitsDict = {
'lutIndex': lutIndexVals,
219 'expInfo': fgcmExpInfo,
220 'focalPlaneProjector': focalPlaneProjector}
222 fgcmFitCycle = fgcm.FgcmFitCycle(configDict, useFits=
False,
223 noFitsDict=noFitsDict, noOutput=
True)
228 conv = fgcmStarObservationCat[0][
'ra'].asDegrees() / float(fgcmStarObservationCat[0][
'ra'])
231 fgcmPars = fgcm.FgcmParameters.newParsWithArrays(fgcmFitCycle.fgcmConfig,
239 obsIndex = fgcmStarIndicesCat[
'obsIndex']
240 visitIndex = np.searchsorted(fgcmExpInfo[
'VISIT'],
241 fgcmStarObservationCat[
'visit'][obsIndex])
243 refMag, refMagErr = extractReferenceMags(fgcmRefCat,
244 self.config.fgcmFitCycle.bands,
245 self.config.fgcmFitCycle.physicalFilterMap)
246 refId = fgcmRefCat[
'fgcm_id'][:]
248 fgcmStars = fgcm.FgcmStars(fgcmFitCycle.fgcmConfig)
249 fgcmStars.loadStars(fgcmPars,
250 fgcmStarObservationCat[
'visit'][obsIndex],
251 fgcmStarObservationCat[
'ccd'][obsIndex],
252 fgcmStarObservationCat[
'ra'][obsIndex] * conv,
253 fgcmStarObservationCat[
'dec'][obsIndex] * conv,
254 fgcmStarObservationCat[
'instMag'][obsIndex],
255 fgcmStarObservationCat[
'instMagErr'][obsIndex],
256 fgcmExpInfo[
'FILTERNAME'][visitIndex],
257 fgcmStarIdCat[
'fgcm_id'][:],
258 fgcmStarIdCat[
'ra'][:],
259 fgcmStarIdCat[
'dec'][:],
260 fgcmStarIdCat[
'obsArrIndex'][:],
261 fgcmStarIdCat[
'nObs'][:],
262 obsX=fgcmStarObservationCat[
'x'][obsIndex],
263 obsY=fgcmStarObservationCat[
'y'][obsIndex],
264 obsDeltaMagBkg=fgcmStarObservationCat[
'deltaMagBkg'][obsIndex],
265 obsDeltaAper=fgcmStarObservationCat[
'deltaMagAper'][obsIndex],
266 psfCandidate=fgcmStarObservationCat[
'psf_candidate'][obsIndex],
276 del fgcmStarIndicesCat
279 fgcmFitCycle.setLUT(fgcmLut)
280 fgcmFitCycle.setStars(fgcmStars, fgcmPars)
285 previousReservedRawRepeatability = np.zeros(fgcmPars.nBands) + 1000.0
286 previousParInfo =
None
287 previousParams =
None
288 previousSuperStar =
None
290 while (
not converged
and cycleNumber < self.config.maxFitCycles):
292 fgcmFitCycle.fgcmConfig.updateCycleNumber(cycleNumber)
296 fgcmPars = fgcm.FgcmParameters.loadParsWithArrays(fgcmFitCycle.fgcmConfig,
303 fgcmFitCycle.fgcmStars.reloadStarMagnitudes(fgcmStarObservationCat[
'instMag'][obsIndex],
304 fgcmStarObservationCat[
'instMagErr'][obsIndex])
305 fgcmFitCycle.initialCycle =
False
307 fgcmFitCycle.setPars(fgcmPars)
308 fgcmFitCycle.finishSetup()
313 previousParInfo, previousParams = fgcmFitCycle.fgcmPars.parsToArrays()
314 previousSuperStar = fgcmFitCycle.fgcmPars.parSuperStarFlat.copy()
316 self.log.info(
"Raw repeatability after cycle number %d is:" % (cycleNumber))
317 for i, band
in enumerate(fgcmFitCycle.fgcmPars.bands):
318 if not fgcmFitCycle.fgcmPars.hasExposuresInBand[i]:
320 rep = fgcmFitCycle.fgcmPars.compReservedRawRepeatability[i] * 1000.0
321 self.log.info(
" Band %s, repeatability: %.2f mmag" % (band, rep))
324 if np.alltrue((previousReservedRawRepeatability
325 - fgcmFitCycle.fgcmPars.compReservedRawRepeatability)
326 < self.config.convergenceTolerance):
327 self.log.info(
"Raw repeatability has converged after cycle number %d." % (cycleNumber))
330 fgcmFitCycle.fgcmConfig.expGrayPhotometricCut[:] = fgcmFitCycle.updatedPhotometricCut
331 fgcmFitCycle.fgcmConfig.expGrayHighCut[:] = fgcmFitCycle.updatedHighCut
332 fgcmFitCycle.fgcmConfig.precomputeSuperStarInitialCycle =
False
333 fgcmFitCycle.fgcmConfig.freezeStdAtmosphere =
False
334 previousReservedRawRepeatability[:] = fgcmFitCycle.fgcmPars.compReservedRawRepeatability
335 self.log.info(
"Setting exposure gray photometricity cuts to:")
336 for i, band
in enumerate(fgcmFitCycle.fgcmPars.bands):
337 if not fgcmFitCycle.fgcmPars.hasExposuresInBand[i]:
339 cut = fgcmFitCycle.updatedPhotometricCut[i] * 1000.0
340 self.log.info(
" Band %s, photometricity cut: %.2f mmag" % (band, cut))
346 self.log.warning(
"Maximum number of fit cycles exceeded (%d) without convergence.", cycleNumber)
349 fgcmFitCycle.fgcmConfig.freezeStdAtmosphere =
False
350 fgcmFitCycle.fgcmConfig.resetParameters =
False
351 fgcmFitCycle.fgcmConfig.maxIter = 0
352 fgcmFitCycle.fgcmConfig.outputZeropoints =
True
353 fgcmFitCycle.fgcmConfig.outputStandards =
True
354 fgcmFitCycle.fgcmConfig.doPlots = self.config.doDebuggingPlots
355 fgcmFitCycle.fgcmConfig.updateCycleNumber(cycleNumber)
356 fgcmFitCycle.initialCycle =
False
358 fgcmPars = fgcm.FgcmParameters.loadParsWithArrays(fgcmFitCycle.fgcmConfig,
363 fgcmFitCycle.fgcmStars.reloadStarMagnitudes(fgcmStarObservationCat[
'instMag'][obsIndex],
364 fgcmStarObservationCat[
'instMagErr'][obsIndex])
365 fgcmFitCycle.setPars(fgcmPars)
366 fgcmFitCycle.finishSetup()
368 self.log.info(
"Running final clean-up fit cycle...")
371 self.log.info(
"Raw repeatability after clean-up cycle is:")
372 for i, band
in enumerate(fgcmFitCycle.fgcmPars.bands):
373 if not fgcmFitCycle.fgcmPars.hasExposuresInBand[i]:
375 rep = fgcmFitCycle.fgcmPars.compReservedRawRepeatability[i] * 1000.0
376 self.log.info(
" Band %s, repeatability: %.2f mmag" % (band, rep))
380 superStarChebSize = fgcmFitCycle.fgcmZpts.zpStruct[
'FGCM_FZPT_SSTAR_CHEB'].shape[1]
381 zptChebSize = fgcmFitCycle.fgcmZpts.zpStruct[
'FGCM_FZPT_CHEB'].shape[1]
383 zptSchema = makeZptSchema(superStarChebSize, zptChebSize)
384 zptCat = makeZptCat(zptSchema, fgcmFitCycle.fgcmZpts.zpStruct)
386 atmSchema = makeAtmSchema()
387 atmCat = makeAtmCat(atmSchema, fgcmFitCycle.fgcmZpts.atmStruct)
389 stdStruct, goodBands = fgcmFitCycle.fgcmStars.retrieveStdStarCatalog(fgcmFitCycle.fgcmPars)
390 stdSchema = makeStdSchema(len(goodBands))
391 stdCat = makeStdCat(stdSchema, stdStruct, goodBands)
393 outStruct = self.fgcmOutputProducts.generateTractOutputProducts(handleDict,
396 zptCat, atmCat, stdCat,
397 self.config.fgcmBuildStars)
399 outStruct.repeatability = fgcmFitCycle.fgcmPars.compReservedRawRepeatability
401 fgcmFitCycle.freeSharedMemory()
An immutable representation of a camera.
The photometric calibration of an exposure.
A spatially-varying transmission curve as a function of wavelength.
Custom catalog class for ExposureRecord/Table.