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.
116 Camera object (`lsst.afw.cameraGeom.Camera`)
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.
135 buildStarsRefObjLoader : `lsst.meas.algorithms.ReferenceObjectLoader`, optional
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.
149 atmospheres : `generator` [(`int`, `lsst.afw.image.TransmissionCurve`)]
150 Generator that returns (visit, transmissionCurve) tuples.
151 photoCalibs : `generator` [(`int`, `int`, `str`, `lsst.afw.image.PhotoCalib`)]
152 Generator that returns (visit, ccd, filtername, photoCalib) tuples.
153 (returned if returnCatalogs is False).
154 photoCalibCatalogs : `generator` [(`int`, `lsst.afw.table.ExposureCatalog`)]
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.all((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()