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)
91 if not self.
fgcmFitCyclefgcmFitCycle.useRepeatabilityForExpGrayCutsDict[band]:
92 msg =
'Must set useRepeatabilityForExpGrayCutsDict[band]=True for all bands'
93 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.useRepeatabilityForExpGrayCutsDict,
98 """Base class to calibrate a single tract using fgcmcal
102 self.makeSubtask(
"fgcmBuildStars", initInputs=initInputs)
103 self.makeSubtask(
"fgcmOutputProducts")
105 def run(self, handleDict, tract,
106 buildStarsRefObjLoader=None, returnCatalogs=True):
107 """Run the calibrations for a single tract with fgcm.
112 All handles are `lsst.daf.butler.DeferredDatasetHandle`
113 handle dictionary with the following keys. Note that all
114 keys need
not be set based on config parameters.
118 ``
"source_catalogs"``
119 `list` of handles
for input source catalogs.
121 Schema
for the source catalogs.
122 ``
"fgcmLookUpTable"``
123 handle
for the FGCM look-up table.
125 `list` of handles
for the input calexps
126 ``
"fgcmPhotoCalibs"``
127 `dict` of output photoCalib handles. Key
is
128 (tract, visit, detector).
129 Present
if doZeropointOutput
is True.
130 ``
"fgcmTransmissionAtmospheres"``
131 `dict` of output atmosphere transmission handles.
132 Key
is (tract, visit).
133 Present
if doAtmosphereOutput
is True.
137 Reference object loader object
for fgcmBuildStars.
138 returnCatalogs : `bool`, optional
139 Return photoCalibs
as per-visit exposure catalogs.
143 outstruct : `lsst.pipe.base.Struct`
144 Output structure
with keys:
146 offsets : `np.ndarray`
147 Final reference offsets, per band.
148 repeatability : `np.ndarray`
149 Raw fgcm repeatability
for bright stars, per band.
151 Generator that returns (visit, transmissionCurve) tuples.
153 Generator that returns (visit, ccd, filtername, photoCalib) tuples.
154 (returned
if returnCatalogs
is False).
156 Generator that returns (visit, exposureCatalog) tuples.
157 (returned
if returnCatalogs
is True).
159 self.log.info("Running on tract %d", (tract))
163 calibFluxApertureRadius =
None
164 if self.config.fgcmBuildStars.doSubtractLocalBackground:
166 field = self.config.fgcmBuildStars.instFluxField
169 raise RuntimeError(
"Could not determine aperture radius from %s. "
170 "Cannot use doSubtractLocalBackground." %
176 groupedHandles = self.fgcmBuildStars._groupHandles(handleDict[
'sourceTableHandleDict'],
177 handleDict[
'visitSummaryHandleDict'])
178 visitCat = self.fgcmBuildStars.fgcmMakeVisitCatalog(handleDict[
'camera'], groupedHandles)
179 rad = calibFluxApertureRadius
180 fgcmStarObservationCat = self.fgcmBuildStars.fgcmMakeAllStarObservations(groupedHandles,
182 handleDict[
'sourceSchema'],
183 handleDict[
'camera'],
184 calibFluxApertureRadius=rad)
186 if self.fgcmBuildStars.config.doReferenceMatches:
187 lutHandle = handleDict[
'fgcmLookUpTable']
188 self.fgcmBuildStars.makeSubtask(
"fgcmLoadReferenceCatalog",
189 refObjLoader=buildStarsRefObjLoader,
190 refCatName=self.fgcmBuildStars.config.connections.refCat)
194 fgcmStarIdCat, fgcmStarIndicesCat, fgcmRefCat = \
195 self.fgcmBuildStars.fgcmMatchStars(visitCat,
196 fgcmStarObservationCat,
200 lutCat = handleDict[
'fgcmLookUpTable'].get()
202 dict(self.config.fgcmFitCycle.physicalFilterMap))
208 configDict =
makeConfigDict(self.config.fgcmFitCycle, self.log, handleDict[
'camera'],
209 self.config.fgcmFitCycle.maxIterBeforeFinalCycle,
210 True,
False, lutIndexVals[0][
'FILTERNAMES'],
214 self.config.fgcmFitCycle.defaultCameraOrientation)
218 noFitsDict = {
'lutIndex': lutIndexVals,
220 'expInfo': fgcmExpInfo,
221 'focalPlaneProjector': focalPlaneProjector}
223 fgcmFitCycle = fgcm.FgcmFitCycle(configDict, useFits=
False,
224 noFitsDict=noFitsDict, noOutput=
True)
229 conv = fgcmStarObservationCat[0][
'ra'].asDegrees() /
float(fgcmStarObservationCat[0][
'ra'])
232 fgcmPars = fgcm.FgcmParameters.newParsWithArrays(fgcmFitCycle.fgcmConfig,
240 obsIndex = fgcmStarIndicesCat[
'obsIndex']
241 visitIndex = np.searchsorted(fgcmExpInfo[
'VISIT'],
242 fgcmStarObservationCat[
'visit'][obsIndex])
245 self.config.fgcmFitCycle.bands,
246 self.config.fgcmFitCycle.physicalFilterMap)
247 refId = fgcmRefCat[
'fgcm_id'][:]
249 fgcmStars = fgcm.FgcmStars(fgcmFitCycle.fgcmConfig)
250 fgcmStars.loadStars(fgcmPars,
251 fgcmStarObservationCat[
'visit'][obsIndex],
252 fgcmStarObservationCat[
'ccd'][obsIndex],
253 fgcmStarObservationCat[
'ra'][obsIndex] * conv,
254 fgcmStarObservationCat[
'dec'][obsIndex] * conv,
255 fgcmStarObservationCat[
'instMag'][obsIndex],
256 fgcmStarObservationCat[
'instMagErr'][obsIndex],
257 fgcmExpInfo[
'FILTERNAME'][visitIndex],
258 fgcmStarIdCat[
'fgcm_id'][:],
259 fgcmStarIdCat[
'ra'][:],
260 fgcmStarIdCat[
'dec'][:],
261 fgcmStarIdCat[
'obsArrIndex'][:],
262 fgcmStarIdCat[
'nObs'][:],
263 obsX=fgcmStarObservationCat[
'x'][obsIndex],
264 obsY=fgcmStarObservationCat[
'y'][obsIndex],
265 obsDeltaMagBkg=fgcmStarObservationCat[
'deltaMagBkg'][obsIndex],
266 obsDeltaAper=fgcmStarObservationCat[
'deltaMagAper'][obsIndex],
267 psfCandidate=fgcmStarObservationCat[
'psf_candidate'][obsIndex],
277 del fgcmStarIndicesCat
280 fgcmFitCycle.setLUT(fgcmLut)
281 fgcmFitCycle.setStars(fgcmStars, fgcmPars)
286 previousReservedRawRepeatability = np.zeros(fgcmPars.nBands) + 1000.0
287 previousParInfo =
None
288 previousParams =
None
289 previousSuperStar =
None
291 while (
not converged
and cycleNumber < self.config.maxFitCycles):
293 fgcmFitCycle.fgcmConfig.updateCycleNumber(cycleNumber)
297 fgcmPars = fgcm.FgcmParameters.loadParsWithArrays(fgcmFitCycle.fgcmConfig,
304 fgcmFitCycle.fgcmStars.reloadStarMagnitudes(fgcmStarObservationCat[
'instMag'][obsIndex],
305 fgcmStarObservationCat[
'instMagErr'][obsIndex])
306 fgcmFitCycle.initialCycle =
False
308 fgcmFitCycle.setPars(fgcmPars)
309 fgcmFitCycle.finishSetup()
314 previousParInfo, previousParams = fgcmFitCycle.fgcmPars.parsToArrays()
315 previousSuperStar = fgcmFitCycle.fgcmPars.parSuperStarFlat.copy()
317 self.log.
info(
"Raw repeatability after cycle number %d is:" % (cycleNumber))
318 for i, band
in enumerate(fgcmFitCycle.fgcmPars.bands):
319 if not fgcmFitCycle.fgcmPars.hasExposuresInBand[i]:
321 rep = fgcmFitCycle.fgcmPars.compReservedRawRepeatability[i] * 1000.0
322 self.log.
info(
" Band %s, repeatability: %.2f mmag" % (band, rep))
325 if np.alltrue((previousReservedRawRepeatability
326 - fgcmFitCycle.fgcmPars.compReservedRawRepeatability)
327 < self.config.convergenceTolerance):
328 self.log.
info(
"Raw repeatability has converged after cycle number %d." % (cycleNumber))
331 fgcmFitCycle.fgcmConfig.expGrayPhotometricCut[:] = fgcmFitCycle.updatedPhotometricCut
332 fgcmFitCycle.fgcmConfig.expGrayHighCut[:] = fgcmFitCycle.updatedHighCut
333 fgcmFitCycle.fgcmConfig.precomputeSuperStarInitialCycle =
False
334 fgcmFitCycle.fgcmConfig.freezeStdAtmosphere =
False
335 previousReservedRawRepeatability[:] = fgcmFitCycle.fgcmPars.compReservedRawRepeatability
336 self.log.
info(
"Setting exposure gray photometricity cuts to:")
337 for i, band
in enumerate(fgcmFitCycle.fgcmPars.bands):
338 if not fgcmFitCycle.fgcmPars.hasExposuresInBand[i]:
340 cut = fgcmFitCycle.updatedPhotometricCut[i] * 1000.0
341 self.log.
info(
" Band %s, photometricity cut: %.2f mmag" % (band, cut))
347 self.log.
warning(
"Maximum number of fit cycles exceeded (%d) without convergence.", cycleNumber)
350 fgcmFitCycle.fgcmConfig.freezeStdAtmosphere =
False
351 fgcmFitCycle.fgcmConfig.resetParameters =
False
352 fgcmFitCycle.fgcmConfig.maxIter = 0
353 fgcmFitCycle.fgcmConfig.outputZeropoints =
True
354 fgcmFitCycle.fgcmConfig.outputStandards =
True
355 fgcmFitCycle.fgcmConfig.doPlots = self.config.doDebuggingPlots
356 fgcmFitCycle.fgcmConfig.updateCycleNumber(cycleNumber)
357 fgcmFitCycle.initialCycle =
False
359 fgcmPars = fgcm.FgcmParameters.loadParsWithArrays(fgcmFitCycle.fgcmConfig,
364 fgcmFitCycle.fgcmStars.reloadStarMagnitudes(fgcmStarObservationCat[
'instMag'][obsIndex],
365 fgcmStarObservationCat[
'instMagErr'][obsIndex])
366 fgcmFitCycle.setPars(fgcmPars)
367 fgcmFitCycle.finishSetup()
369 self.log.
info(
"Running final clean-up fit cycle...")
372 self.log.
info(
"Raw repeatability after clean-up cycle is:")
373 for i, band
in enumerate(fgcmFitCycle.fgcmPars.bands):
374 if not fgcmFitCycle.fgcmPars.hasExposuresInBand[i]:
376 rep = fgcmFitCycle.fgcmPars.compReservedRawRepeatability[i] * 1000.0
377 self.log.
info(
" Band %s, repeatability: %.2f mmag" % (band, rep))
381 superStarChebSize = fgcmFitCycle.fgcmZpts.zpStruct[
'FGCM_FZPT_SSTAR_CHEB'].shape[1]
382 zptChebSize = fgcmFitCycle.fgcmZpts.zpStruct[
'FGCM_FZPT_CHEB'].shape[1]
385 zptCat =
makeZptCat(zptSchema, fgcmFitCycle.fgcmZpts.zpStruct)
388 atmCat =
makeAtmCat(atmSchema, fgcmFitCycle.fgcmZpts.atmStruct)
390 stdStruct, goodBands = fgcmFitCycle.fgcmStars.retrieveStdStarCatalog(fgcmFitCycle.fgcmPars)
392 stdCat =
makeStdCat(stdSchema, stdStruct, goodBands)
394 outStruct = self.fgcmOutputProducts.generateTractOutputProducts(handleDict,
397 zptCat, atmCat, stdCat,
398 self.config.fgcmBuildStars)
400 outStruct.repeatability = fgcmFitCycle.fgcmPars.compReservedRawRepeatability
402 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.
def run(self, handleDict, tract, buildStarsRefObjLoader=None, returnCatalogs=True)
def __init__(self, initInputs=None, **kwargs)
def extractReferenceMags(refStars, bands, filterMap)
def makeStdSchema(nBands)
def makeAtmCat(atmSchema, atmStruct)
def makeConfigDict(config, log, camera, maxIter, resetFitParameters, outputZeropoints, lutFilterNames, tract=None)
def translateFgcmLut(lutCat, physicalFilterMap)
def makeZptCat(zptSchema, zpStruct)
def makeStdCat(stdSchema, stdStruct, goodBands)
def computeApertureRadiusFromName(fluxField)
def makeZptSchema(superStarChebyshevSize, zptChebyshevSize)
def translateVisitCatalog(visitCat)