21 """Utility functions for fgcmcal.
23 This file contains utility functions that are used by more than one task,
24 and do not need to be part of a task.
30 from lsst.daf.base
import PropertyList
31 import lsst.daf.persistence
as dafPersist
32 import lsst.afw.cameraGeom
as afwCameraGeom
33 import lsst.afw.table
as afwTable
34 import lsst.afw.image
as afwImage
35 import lsst.afw.math
as afwMath
36 import lsst.geom
as geom
37 from lsst.obs.base
import createInitialSkyWcs
38 from lsst.obs.base
import Instrument
44 FGCM_EXP_FIELD =
'VISIT'
45 FGCM_CCD_FIELD =
'DETECTOR'
49 resetFitParameters, outputZeropoints,
50 lutFilterNames, tract=None):
52 Make the FGCM fit cycle configuration dict
56 config: `lsst.fgcmcal.FgcmFitCycleConfig`
60 camera: `lsst.afw.cameraGeom.Camera`
61 Camera from the butler
63 Maximum number of iterations
64 resetFitParameters: `bool`
65 Reset fit parameters before fitting?
66 outputZeropoints: `bool`
67 Compute zeropoints for output?
68 lutFilterNames : array-like, `str`
69 Array of physical filter names in the LUT.
70 tract: `int`, optional
71 Tract number for extending the output file name for debugging.
77 Configuration dictionary for fgcm
80 notFitBands = [b
for b
in config.bands
if b
not in config.fitBands]
84 for ccut
in config.starColorCuts:
85 parts = ccut.split(
',')
86 starColorCutList.append([parts[0], parts[1], float(parts[2]), float(parts[3])])
91 mirrorArea = np.pi*(camera.telescopeDiameter*100./2.)**2.
94 gains = [amp.getGain()
for detector
in camera
for amp
in detector.getAmplifiers()]
95 cameraGain = float(np.median(gains))
98 filterToBand = {filterName: config.physicalFilterMap[filterName]
for
99 filterName
in lutFilterNames}
102 outfileBase = config.outfileBase
104 outfileBase =
'%s-%06d' % (config.outfileBase, tract)
107 configDict = {
'outfileBase': outfileBase,
109 'exposureFile':
None,
113 'mirrorArea': mirrorArea,
114 'cameraGain': cameraGain,
115 'ccdStartIndex': camera[0].getId(),
116 'expField': FGCM_EXP_FIELD,
117 'ccdField': FGCM_CCD_FIELD,
118 'seeingField':
'DELTA_APER',
119 'fwhmField':
'PSFSIGMA',
120 'skyBrightnessField':
'SKYBACKGROUND',
121 'deepFlag':
'DEEPFLAG',
122 'bands': list(config.bands),
123 'fitBands': list(config.fitBands),
124 'notFitBands': notFitBands,
125 'requiredBands': list(config.requiredBands),
126 'filterToBand': filterToBand,
128 'nCore': config.nCore,
129 'nStarPerRun': config.nStarPerRun,
130 'nExpPerRun': config.nExpPerRun,
131 'reserveFraction': config.reserveFraction,
132 'freezeStdAtmosphere': config.freezeStdAtmosphere,
133 'precomputeSuperStarInitialCycle': config.precomputeSuperStarInitialCycle,
134 'superStarSubCCDDict': dict(config.superStarSubCcdDict),
135 'superStarSubCCDChebyshevOrder': config.superStarSubCcdChebyshevOrder,
136 'superStarSubCCDTriangular': config.superStarSubCcdTriangular,
137 'superStarSigmaClip': config.superStarSigmaClip,
138 'focalPlaneSigmaClip': config.focalPlaneSigmaClip,
139 'ccdGraySubCCDDict': dict(config.ccdGraySubCcdDict),
140 'ccdGraySubCCDChebyshevOrder': config.ccdGraySubCcdChebyshevOrder,
141 'ccdGraySubCCDTriangular': config.ccdGraySubCcdTriangular,
142 'ccdGrayFocalPlaneDict': dict(config.ccdGrayFocalPlaneDict),
143 'ccdGrayFocalPlaneChebyshevOrder': config.ccdGrayFocalPlaneChebyshevOrder,
144 'ccdGrayFocalPlaneFitMinCcd': config.ccdGrayFocalPlaneFitMinCcd,
145 'cycleNumber': config.cycleNumber,
147 'deltaMagBkgOffsetPercentile': config.deltaMagBkgOffsetPercentile,
148 'deltaMagBkgPerCcd': config.deltaMagBkgPerCcd,
149 'UTBoundary': config.utBoundary,
150 'washMJDs': config.washMjds,
151 'epochMJDs': config.epochMjds,
152 'coatingMJDs': config.coatingMjds,
153 'minObsPerBand': config.minObsPerBand,
154 'latitude': config.latitude,
155 'brightObsGrayMax': config.brightObsGrayMax,
156 'minStarPerCCD': config.minStarPerCcd,
157 'minCCDPerExp': config.minCcdPerExp,
158 'maxCCDGrayErr': config.maxCcdGrayErr,
159 'minStarPerExp': config.minStarPerExp,
160 'minExpPerNight': config.minExpPerNight,
161 'expGrayInitialCut': config.expGrayInitialCut,
162 'expGrayPhotometricCutDict': dict(config.expGrayPhotometricCutDict),
163 'expGrayHighCutDict': dict(config.expGrayHighCutDict),
164 'expGrayRecoverCut': config.expGrayRecoverCut,
165 'expVarGrayPhotometricCutDict': dict(config.expVarGrayPhotometricCutDict),
166 'expGrayErrRecoverCut': config.expGrayErrRecoverCut,
167 'refStarSnMin': config.refStarSnMin,
168 'refStarOutlierNSig': config.refStarOutlierNSig,
169 'applyRefStarColorCuts': config.applyRefStarColorCuts,
170 'illegalValue': -9999.0,
171 'starColorCuts': starColorCutList,
172 'aperCorrFitNBins': config.aperCorrFitNBins,
173 'aperCorrInputSlopeDict': dict(config.aperCorrInputSlopeDict),
174 'sedBoundaryTermDict': config.sedboundaryterms.toDict()[
'data'],
175 'sedTermDict': config.sedterms.toDict()[
'data'],
176 'colorSplitBands': list(config.colorSplitBands),
177 'sigFgcmMaxErr': config.sigFgcmMaxErr,
178 'sigFgcmMaxEGrayDict': dict(config.sigFgcmMaxEGrayDict),
179 'ccdGrayMaxStarErr': config.ccdGrayMaxStarErr,
180 'approxThroughputDict': dict(config.approxThroughputDict),
181 'sigmaCalRange': list(config.sigmaCalRange),
182 'sigmaCalFitPercentile': list(config.sigmaCalFitPercentile),
183 'sigmaCalPlotPercentile': list(config.sigmaCalPlotPercentile),
184 'sigma0Phot': config.sigma0Phot,
185 'mapLongitudeRef': config.mapLongitudeRef,
186 'mapNSide': config.mapNSide,
189 'useRetrievedPwv':
False,
190 'useNightlyRetrievedPwv':
False,
191 'pwvRetrievalSmoothBlock': 25,
192 'useQuadraticPwv': config.useQuadraticPwv,
193 'useRetrievedTauInit':
False,
194 'tauRetrievalMinCCDPerNight': 500,
195 'modelMagErrors': config.modelMagErrors,
196 'instrumentParsPerBand': config.instrumentParsPerBand,
197 'instrumentSlopeMinDeltaT': config.instrumentSlopeMinDeltaT,
198 'fitMirrorChromaticity': config.fitMirrorChromaticity,
199 'useRepeatabilityForExpGrayCutsDict': dict(config.useRepeatabilityForExpGrayCutsDict),
200 'autoPhotometricCutNSig': config.autoPhotometricCutNSig,
201 'autoHighCutNSig': config.autoHighCutNSig,
203 'quietMode': config.quietMode,
204 'randomSeed': config.randomSeed,
205 'outputStars':
False,
208 'resetParameters': resetFitParameters,
209 'outputFgcmcalZpts':
True,
210 'outputZeropoints': outputZeropoints}
217 Translate the FGCM look-up-table into an fgcm-compatible object
221 lutCat: `lsst.afw.table.BaseCatalog`
222 Catalog describing the FGCM look-up table
223 physicalFilterMap: `dict`
224 Physical filter to band mapping
228 fgcmLut: `lsst.fgcm.FgcmLut`
229 Lookup table for FGCM
230 lutIndexVals: `numpy.ndarray`
231 Numpy array with LUT index information for FGCM
232 lutStd: `numpy.ndarray`
233 Numpy array with LUT standard throughput values for FGCM
237 After running this code, it is wise to `del lutCat` to clear the memory.
241 lutFilterNames = np.array(lutCat[0][
'physicalFilters'].split(
','), dtype=
'U')
242 lutStdFilterNames = np.array(lutCat[0][
'stdPhysicalFilters'].split(
','), dtype=
'U')
247 lutIndexVals = np.zeros(1, dtype=[(
'FILTERNAMES', lutFilterNames.dtype.str,
248 lutFilterNames.size),
249 (
'STDFILTERNAMES', lutStdFilterNames.dtype.str,
250 lutStdFilterNames.size),
251 (
'PMB',
'f8', lutCat[0][
'pmb'].size),
252 (
'PMBFACTOR',
'f8', lutCat[0][
'pmbFactor'].size),
253 (
'PMBELEVATION',
'f8'),
254 (
'LAMBDANORM',
'f8'),
255 (
'PWV',
'f8', lutCat[0][
'pwv'].size),
256 (
'O3',
'f8', lutCat[0][
'o3'].size),
257 (
'TAU',
'f8', lutCat[0][
'tau'].size),
258 (
'ALPHA',
'f8', lutCat[0][
'alpha'].size),
259 (
'ZENITH',
'f8', lutCat[0][
'zenith'].size),
262 lutIndexVals[
'FILTERNAMES'][:] = lutFilterNames
263 lutIndexVals[
'STDFILTERNAMES'][:] = lutStdFilterNames
264 lutIndexVals[
'PMB'][:] = lutCat[0][
'pmb']
265 lutIndexVals[
'PMBFACTOR'][:] = lutCat[0][
'pmbFactor']
266 lutIndexVals[
'PMBELEVATION'] = lutCat[0][
'pmbElevation']
267 lutIndexVals[
'LAMBDANORM'] = lutCat[0][
'lambdaNorm']
268 lutIndexVals[
'PWV'][:] = lutCat[0][
'pwv']
269 lutIndexVals[
'O3'][:] = lutCat[0][
'o3']
270 lutIndexVals[
'TAU'][:] = lutCat[0][
'tau']
271 lutIndexVals[
'ALPHA'][:] = lutCat[0][
'alpha']
272 lutIndexVals[
'ZENITH'][:] = lutCat[0][
'zenith']
273 lutIndexVals[
'NCCD'] = lutCat[0][
'nCcd']
276 lutStd = np.zeros(1, dtype=[(
'PMBSTD',
'f8'),
282 (
'LAMBDARANGE',
'f8', 2),
283 (
'LAMBDASTEP',
'f8'),
284 (
'LAMBDASTD',
'f8', lutFilterNames.size),
285 (
'LAMBDASTDFILTER',
'f8', lutStdFilterNames.size),
286 (
'I0STD',
'f8', lutFilterNames.size),
287 (
'I1STD',
'f8', lutFilterNames.size),
288 (
'I10STD',
'f8', lutFilterNames.size),
289 (
'I2STD',
'f8', lutFilterNames.size),
290 (
'LAMBDAB',
'f8', lutFilterNames.size),
291 (
'ATMLAMBDA',
'f8', lutCat[0][
'atmLambda'].size),
292 (
'ATMSTDTRANS',
'f8', lutCat[0][
'atmStdTrans'].size)])
293 lutStd[
'PMBSTD'] = lutCat[0][
'pmbStd']
294 lutStd[
'PWVSTD'] = lutCat[0][
'pwvStd']
295 lutStd[
'O3STD'] = lutCat[0][
'o3Std']
296 lutStd[
'TAUSTD'] = lutCat[0][
'tauStd']
297 lutStd[
'ALPHASTD'] = lutCat[0][
'alphaStd']
298 lutStd[
'ZENITHSTD'] = lutCat[0][
'zenithStd']
299 lutStd[
'LAMBDARANGE'][:] = lutCat[0][
'lambdaRange'][:]
300 lutStd[
'LAMBDASTEP'] = lutCat[0][
'lambdaStep']
301 lutStd[
'LAMBDASTD'][:] = lutCat[0][
'lambdaStd']
302 lutStd[
'LAMBDASTDFILTER'][:] = lutCat[0][
'lambdaStdFilter']
303 lutStd[
'I0STD'][:] = lutCat[0][
'i0Std']
304 lutStd[
'I1STD'][:] = lutCat[0][
'i1Std']
305 lutStd[
'I10STD'][:] = lutCat[0][
'i10Std']
306 lutStd[
'I2STD'][:] = lutCat[0][
'i2Std']
307 lutStd[
'LAMBDAB'][:] = lutCat[0][
'lambdaB']
308 lutStd[
'ATMLAMBDA'][:] = lutCat[0][
'atmLambda'][:]
309 lutStd[
'ATMSTDTRANS'][:] = lutCat[0][
'atmStdTrans'][:]
311 lutTypes = [row[
'luttype']
for row
in lutCat]
314 lutFlat = np.zeros(lutCat[0][
'lut'].size, dtype=[(
'I0',
'f4'),
317 lutFlat[
'I0'][:] = lutCat[lutTypes.index(
'I0')][
'lut'][:]
318 lutFlat[
'I1'][:] = lutCat[lutTypes.index(
'I1')][
'lut'][:]
320 lutDerivFlat = np.zeros(lutCat[0][
'lut'].size, dtype=[(
'D_LNPWV',
'f4'),
324 (
'D_SECZENITH',
'f4'),
325 (
'D_LNPWV_I1',
'f4'),
327 (
'D_LNTAU_I1',
'f4'),
328 (
'D_ALPHA_I1',
'f4'),
329 (
'D_SECZENITH_I1',
'f4')])
331 for name
in lutDerivFlat.dtype.names:
332 lutDerivFlat[name][:] = lutCat[lutTypes.index(name)][
'lut'][:]
339 fgcmLut = fgcm.FgcmLUT(lutIndexVals, lutFlat, lutDerivFlat, lutStd,
340 filterToBand=physicalFilterMap)
342 return fgcmLut, lutIndexVals, lutStd
347 Translate the FGCM visit catalog to an fgcm-compatible object
351 visitCat: `lsst.afw.table.BaseCatalog`
352 FGCM visitCat from `lsst.fgcmcal.FgcmBuildStarsTask`
356 fgcmExpInfo: `numpy.ndarray`
357 Numpy array for visit information for FGCM
361 After running this code, it is wise to `del visitCat` to clear the memory.
364 fgcmExpInfo = np.zeros(len(visitCat), dtype=[(
'VISIT',
'i8'),
368 (
'DELTA_APER',
'f8'),
369 (
'SKYBACKGROUND',
'f8'),
376 (
'FILTERNAME',
'a50')])
377 fgcmExpInfo[
'VISIT'][:] = visitCat[
'visit']
378 fgcmExpInfo[
'MJD'][:] = visitCat[
'mjd']
379 fgcmExpInfo[
'EXPTIME'][:] = visitCat[
'exptime']
380 fgcmExpInfo[
'DEEPFLAG'][:] = visitCat[
'deepFlag']
381 fgcmExpInfo[
'TELHA'][:] = visitCat[
'telha']
382 fgcmExpInfo[
'TELRA'][:] = visitCat[
'telra']
383 fgcmExpInfo[
'TELDEC'][:] = visitCat[
'teldec']
384 fgcmExpInfo[
'TELROT'][:] = visitCat[
'telrot']
385 fgcmExpInfo[
'PMB'][:] = visitCat[
'pmb']
386 fgcmExpInfo[
'PSFSIGMA'][:] = visitCat[
'psfSigma']
387 fgcmExpInfo[
'DELTA_APER'][:] = visitCat[
'deltaAper']
388 fgcmExpInfo[
'SKYBACKGROUND'][:] = visitCat[
'skyBackground']
391 fgcmExpInfo[
'FILTERNAME'][:] = visitCat.asAstropy()[
'physicalFilter']
398 Compute the CCD offsets in ra/dec and x/y space
402 camera: `lsst.afw.cameraGeom.Camera`
403 defaultOrientation: `float`
404 Default camera orientation (degrees)
408 ccdOffsets: `numpy.ndarray`
409 Numpy array with ccd offset information for input to FGCM.
410 Angular units are degrees, and x/y units are pixels.
415 ccdOffsets = np.zeros(len(camera), dtype=[(
'CCDNUM',
'i4'),
425 boresight = geom.SpherePoint(180.0*geom.degrees, 0.0*geom.degrees)
430 if camera.getName() ==
'HSC' and np.isnan(defaultOrientation):
431 orientation = 270*geom.degrees
433 orientation = defaultOrientation*geom.degrees
437 visitInfo = afwImage.VisitInfo(boresightRaDec=boresight,
438 boresightRotAngle=orientation,
439 rotType=afwImage.RotType.SKY)
441 for i, detector
in enumerate(camera):
442 ccdOffsets[
'CCDNUM'][i] = detector.getId()
444 wcs = createInitialSkyWcs(visitInfo, detector, flipX)
446 detCenter = wcs.pixelToSky(detector.getCenter(afwCameraGeom.PIXELS))
447 ccdOffsets[
'DELTA_RA'][i] = (detCenter.getRa() - boresight.getRa()).asDegrees()
448 ccdOffsets[
'DELTA_DEC'][i] = (detCenter.getDec() - boresight.getDec()).asDegrees()
450 bbox = detector.getBBox()
452 detCorner1 = wcs.pixelToSky(geom.Point2D(bbox.getMin()))
453 detCorner2 = wcs.pixelToSky(geom.Point2D(bbox.getMax()))
455 ccdOffsets[
'RA_SIZE'][i] = np.abs((detCorner2.getRa() - detCorner1.getRa()).asDegrees())
456 ccdOffsets[
'DEC_SIZE'][i] = np.abs((detCorner2.getDec() - detCorner1.getDec()).asDegrees())
458 ccdOffsets[
'X_SIZE'][i] = bbox.getMaxX()
459 ccdOffsets[
'Y_SIZE'][i] = bbox.getMaxY()
466 Compute the median pixel scale in the camera
471 Average pixel scale (arcsecond) over the camera
474 boresight = geom.SpherePoint(180.0*geom.degrees, 0.0*geom.degrees)
475 orientation = 0.0*geom.degrees
479 visitInfo = afwImage.VisitInfo(boresightRaDec=boresight,
480 boresightRotAngle=orientation,
481 rotType=afwImage.RotType.SKY)
483 pixelScales = np.zeros(len(camera))
484 for i, detector
in enumerate(camera):
485 wcs = createInitialSkyWcs(visitInfo, detector, flipX)
486 pixelScales[i] = wcs.getPixelScale().asArcseconds()
488 ok, = np.where(pixelScales > 0.0)
489 return np.median(pixelScales[ok])
494 Compute the approximate pixel area bounded fields from the camera
499 camera: `lsst.afw.cameraGeom.Camera`
503 approxPixelAreaFields: `dict`
504 Dictionary of approximate area fields, keyed with detector ID
511 boresight = geom.SpherePoint(180.0*geom.degrees, 0.0*geom.degrees)
516 visitInfo = afwImage.VisitInfo(boresightRaDec=boresight,
517 boresightRotAngle=0.0*geom.degrees,
518 rotType=afwImage.RotType.SKY)
520 approxPixelAreaFields = {}
522 for i, detector
in enumerate(camera):
523 key = detector.getId()
525 wcs = createInitialSkyWcs(visitInfo, detector, flipX)
526 bbox = detector.getBBox()
528 areaField = afwMath.PixelAreaBoundedField(bbox, wcs,
529 unit=geom.arcseconds, scaling=areaScaling)
530 approxAreaField = afwMath.ChebyshevBoundedField.approximate(areaField)
532 approxPixelAreaFields[key] = approxAreaField
534 return approxPixelAreaFields
539 Make the zeropoint schema
543 superStarChebyshevSize: `int`
544 Length of the superstar chebyshev array
545 zptChebyshevSize: `int`
546 Length of the zeropoint chebyshev array
550 zptSchema: `lsst.afw.table.schema`
553 zptSchema = afwTable.Schema()
555 zptSchema.addField(
'visit', type=np.int32, doc=
'Visit number')
556 zptSchema.addField(
'detector', type=np.int32, doc=
'Detector ID number')
557 zptSchema.addField(
'fgcmFlag', type=np.int32, doc=(
'FGCM flag value: '
558 '1: Photometric, used in fit; '
559 '2: Photometric, not used in fit; '
560 '4: Non-photometric, on partly photometric night; '
561 '8: Non-photometric, on non-photometric night; '
562 '16: No zeropoint could be determined; '
563 '32: Too few stars for reliable gray computation'))
564 zptSchema.addField(
'fgcmZpt', type=np.float64, doc=
'FGCM zeropoint (center of CCD)')
565 zptSchema.addField(
'fgcmZptErr', type=np.float64,
566 doc=
'Error on zeropoint, estimated from repeatability + number of obs')
567 zptSchema.addField(
'fgcmfZptChebXyMax', type=
'ArrayD', size=2,
568 doc=
'maximum x/maximum y to scale to apply chebyshev parameters')
569 zptSchema.addField(
'fgcmfZptCheb', type=
'ArrayD',
570 size=zptChebyshevSize,
571 doc=
'Chebyshev parameters (flattened) for zeropoint')
572 zptSchema.addField(
'fgcmfZptSstarCheb', type=
'ArrayD',
573 size=superStarChebyshevSize,
574 doc=
'Chebyshev parameters (flattened) for superStarFlat')
575 zptSchema.addField(
'fgcmI0', type=np.float64, doc=
'Integral of the passband')
576 zptSchema.addField(
'fgcmI10', type=np.float64, doc=
'Normalized chromatic integral')
577 zptSchema.addField(
'fgcmR0', type=np.float64,
578 doc=
'Retrieved i0 integral, estimated from stars (only for flag 1)')
579 zptSchema.addField(
'fgcmR10', type=np.float64,
580 doc=
'Retrieved i10 integral, estimated from stars (only for flag 1)')
581 zptSchema.addField(
'fgcmGry', type=np.float64,
582 doc=
'Estimated gray extinction relative to atmospheric solution; '
583 'only for fgcmFlag <= 4 (see fgcmFlag) ')
584 zptSchema.addField(
'fgcmDeltaChrom', type=np.float64,
585 doc=
'Mean chromatic correction for stars in this ccd; '
586 'only for fgcmFlag <= 4 (see fgcmFlag)')
587 zptSchema.addField(
'fgcmZptVar', type=np.float64, doc=
'Variance of zeropoint over ccd')
588 zptSchema.addField(
'fgcmTilings', type=np.float64,
589 doc=
'Number of photometric tilings used for solution for ccd')
590 zptSchema.addField(
'fgcmFpGry', type=np.float64,
591 doc=
'Average gray extinction over the full focal plane '
592 '(same for all ccds in a visit)')
593 zptSchema.addField(
'fgcmFpGryBlue', type=np.float64,
594 doc=
'Average gray extinction over the full focal plane '
595 'for 25% bluest stars')
596 zptSchema.addField(
'fgcmFpGryBlueErr', type=np.float64,
597 doc=
'Error on Average gray extinction over the full focal plane '
598 'for 25% bluest stars')
599 zptSchema.addField(
'fgcmFpGryRed', type=np.float64,
600 doc=
'Average gray extinction over the full focal plane '
601 'for 25% reddest stars')
602 zptSchema.addField(
'fgcmFpGryRedErr', type=np.float64,
603 doc=
'Error on Average gray extinction over the full focal plane '
604 'for 25% reddest stars')
605 zptSchema.addField(
'fgcmFpVar', type=np.float64,
606 doc=
'Variance of gray extinction over the full focal plane '
607 '(same for all ccds in a visit)')
608 zptSchema.addField(
'fgcmDust', type=np.float64,
609 doc=
'Gray dust extinction from the primary/corrector'
610 'at the time of the exposure')
611 zptSchema.addField(
'fgcmFlat', type=np.float64, doc=
'Superstarflat illumination correction')
612 zptSchema.addField(
'fgcmAperCorr', type=np.float64, doc=
'Aperture correction estimated by fgcm')
613 zptSchema.addField(
'fgcmDeltaMagBkg', type=np.float64,
614 doc=(
'Local background correction from brightest percentile '
615 '(value set by deltaMagBkgOffsetPercentile) calibration '
617 zptSchema.addField(
'exptime', type=np.float32, doc=
'Exposure time')
618 zptSchema.addField(
'filtername', type=str, size=10, doc=
'Filter name')
625 Make the zeropoint catalog for persistence
629 zptSchema: `lsst.afw.table.Schema`
630 Zeropoint catalog schema
631 zpStruct: `numpy.ndarray`
632 Zeropoint structure from fgcm
636 zptCat: `afwTable.BaseCatalog`
637 Zeropoint catalog for persistence
640 zptCat = afwTable.BaseCatalog(zptSchema)
641 zptCat.reserve(zpStruct.size)
643 for filterName
in zpStruct[
'FILTERNAME']:
644 rec = zptCat.addNew()
645 rec[
'filtername'] = filterName.decode(
'utf-8')
647 zptCat[
'visit'][:] = zpStruct[FGCM_EXP_FIELD]
648 zptCat[
'detector'][:] = zpStruct[FGCM_CCD_FIELD]
649 zptCat[
'fgcmFlag'][:] = zpStruct[
'FGCM_FLAG']
650 zptCat[
'fgcmZpt'][:] = zpStruct[
'FGCM_ZPT']
651 zptCat[
'fgcmZptErr'][:] = zpStruct[
'FGCM_ZPTERR']
652 zptCat[
'fgcmfZptChebXyMax'][:, :] = zpStruct[
'FGCM_FZPT_XYMAX']
653 zptCat[
'fgcmfZptCheb'][:, :] = zpStruct[
'FGCM_FZPT_CHEB']
654 zptCat[
'fgcmfZptSstarCheb'][:, :] = zpStruct[
'FGCM_FZPT_SSTAR_CHEB']
655 zptCat[
'fgcmI0'][:] = zpStruct[
'FGCM_I0']
656 zptCat[
'fgcmI10'][:] = zpStruct[
'FGCM_I10']
657 zptCat[
'fgcmR0'][:] = zpStruct[
'FGCM_R0']
658 zptCat[
'fgcmR10'][:] = zpStruct[
'FGCM_R10']
659 zptCat[
'fgcmGry'][:] = zpStruct[
'FGCM_GRY']
660 zptCat[
'fgcmDeltaChrom'][:] = zpStruct[
'FGCM_DELTACHROM']
661 zptCat[
'fgcmZptVar'][:] = zpStruct[
'FGCM_ZPTVAR']
662 zptCat[
'fgcmTilings'][:] = zpStruct[
'FGCM_TILINGS']
663 zptCat[
'fgcmFpGry'][:] = zpStruct[
'FGCM_FPGRY']
664 zptCat[
'fgcmFpGryBlue'][:] = zpStruct[
'FGCM_FPGRY_CSPLIT'][:, 0]
665 zptCat[
'fgcmFpGryBlueErr'][:] = zpStruct[
'FGCM_FPGRY_CSPLITERR'][:, 0]
666 zptCat[
'fgcmFpGryRed'][:] = zpStruct[
'FGCM_FPGRY_CSPLIT'][:, 2]
667 zptCat[
'fgcmFpGryRedErr'][:] = zpStruct[
'FGCM_FPGRY_CSPLITERR'][:, 2]
668 zptCat[
'fgcmFpVar'][:] = zpStruct[
'FGCM_FPVAR']
669 zptCat[
'fgcmDust'][:] = zpStruct[
'FGCM_DUST']
670 zptCat[
'fgcmFlat'][:] = zpStruct[
'FGCM_FLAT']
671 zptCat[
'fgcmAperCorr'][:] = zpStruct[
'FGCM_APERCORR']
672 zptCat[
'fgcmDeltaMagBkg'][:] = zpStruct[
'FGCM_DELTAMAGBKG']
673 zptCat[
'exptime'][:] = zpStruct[
'EXPTIME']
680 Make the atmosphere schema
684 atmSchema: `lsst.afw.table.Schema`
687 atmSchema = afwTable.Schema()
689 atmSchema.addField(
'visit', type=np.int32, doc=
'Visit number')
690 atmSchema.addField(
'pmb', type=np.float64, doc=
'Barometric pressure (mb)')
691 atmSchema.addField(
'pwv', type=np.float64, doc=
'Water vapor (mm)')
692 atmSchema.addField(
'tau', type=np.float64, doc=
'Aerosol optical depth')
693 atmSchema.addField(
'alpha', type=np.float64, doc=
'Aerosol slope')
694 atmSchema.addField(
'o3', type=np.float64, doc=
'Ozone (dobson)')
695 atmSchema.addField(
'secZenith', type=np.float64, doc=
'Secant(zenith) (~ airmass)')
696 atmSchema.addField(
'cTrans', type=np.float64, doc=
'Transmission correction factor')
697 atmSchema.addField(
'lamStd', type=np.float64, doc=
'Wavelength for transmission correction')
704 Make the atmosphere catalog for persistence
708 atmSchema: `lsst.afw.table.Schema`
709 Atmosphere catalog schema
710 atmStruct: `numpy.ndarray`
711 Atmosphere structure from fgcm
715 atmCat: `lsst.afw.table.BaseCatalog`
716 Atmosphere catalog for persistence
719 atmCat = afwTable.BaseCatalog(atmSchema)
720 atmCat.resize(atmStruct.size)
722 atmCat[
'visit'][:] = atmStruct[
'VISIT']
723 atmCat[
'pmb'][:] = atmStruct[
'PMB']
724 atmCat[
'pwv'][:] = atmStruct[
'PWV']
725 atmCat[
'tau'][:] = atmStruct[
'TAU']
726 atmCat[
'alpha'][:] = atmStruct[
'ALPHA']
727 atmCat[
'o3'][:] = atmStruct[
'O3']
728 atmCat[
'secZenith'][:] = atmStruct[
'SECZENITH']
729 atmCat[
'cTrans'][:] = atmStruct[
'CTRANS']
730 atmCat[
'lamStd'][:] = atmStruct[
'LAMSTD']
737 Make the standard star schema
742 Number of bands in standard star catalog
746 stdSchema: `lsst.afw.table.Schema`
749 stdSchema = afwTable.SimpleTable.makeMinimalSchema()
750 stdSchema.addField(
'ngood', type=
'ArrayI', doc=
'Number of good observations',
752 stdSchema.addField(
'ntotal', type=
'ArrayI', doc=
'Number of total observations',
754 stdSchema.addField(
'mag_std_noabs', type=
'ArrayF',
755 doc=
'Standard magnitude (no absolute calibration)',
757 stdSchema.addField(
'magErr_std', type=
'ArrayF',
758 doc=
'Standard magnitude error',
760 stdSchema.addField(
'npsfcand', type=
'ArrayI',
761 doc=
'Number of observations flagged as psf candidates',
769 Make the standard star catalog for persistence
773 stdSchema: `lsst.afw.table.Schema`
774 Standard star catalog schema
775 stdStruct: `numpy.ndarray`
776 Standard star structure in FGCM format
778 List of good band names used in stdStruct
782 stdCat: `lsst.afw.table.BaseCatalog`
783 Standard star catalog for persistence
786 stdCat = afwTable.SimpleCatalog(stdSchema)
787 stdCat.resize(stdStruct.size)
789 stdCat[
'id'][:] = stdStruct[
'FGCM_ID']
790 stdCat[
'coord_ra'][:] = stdStruct[
'RA'] * geom.degrees
791 stdCat[
'coord_dec'][:] = stdStruct[
'DEC'] * geom.degrees
792 stdCat[
'ngood'][:, :] = stdStruct[
'NGOOD'][:, :]
793 stdCat[
'ntotal'][:, :] = stdStruct[
'NTOTAL'][:, :]
794 stdCat[
'mag_std_noabs'][:, :] = stdStruct[
'MAG_STD'][:, :]
795 stdCat[
'magErr_std'][:, :] = stdStruct[
'MAGERR_STD'][:, :]
796 stdCat[
'npsfcand'][:, :] = stdStruct[
'NPSFCAND'][:, :]
799 md.set(
"BANDS", list(goodBands))
800 stdCat.setMetadata(md)
807 Compute the radius associated with a CircularApertureFlux field or
812 dataRef : `lsst.daf.persistence.ButlerDataRef` or
813 `lsst.daf.butler.DeferredDatasetHandle`
815 CircularApertureFlux or associated slot.
819 apertureRadius : `float`
820 Radius of the aperture field, in pixels.
824 RuntimeError: Raised if flux field is not a CircularApertureFlux, ApFlux,
828 if isinstance(dataRef, dafPersist.ButlerDataRef):
830 datasetType = dataRef.butlerSubset.datasetType
833 datasetType = dataRef.ref.datasetType.name
835 if datasetType ==
'src':
836 schema = dataRef.get(datasetType=
'src_schema').schema
838 fluxFieldName = schema[fluxField].asField().getName()
840 raise RuntimeError(
"Could not find %s or associated slot in schema." % (fluxField))
847 return apertureRadius
852 Compute the radius associated with a CircularApertureFlux or ApFlux field.
857 CircularApertureFlux or ApFlux
861 apertureRadius : `float`
862 Radius of the aperture field, in pixels.
866 RuntimeError: Raised if flux field is not a CircularApertureFlux
870 m = re.search(
r'(CircularApertureFlux|ApFlux)_(\d+)_(\d+)_', fluxField)
873 raise RuntimeError(f
"Flux field {fluxField} does not correspond to a CircularApertureFlux or ApFlux")
875 apertureRadius = float(m.groups()[1]) + float(m.groups()[2])/10.
877 return apertureRadius
882 Extract reference magnitudes from refStars for given bands and
883 associated filterMap.
887 refStars : `lsst.afw.table.BaseCatalog`
888 FGCM reference star catalog
890 List of bands for calibration
892 FGCM mapping of filter to band
896 refMag : `np.ndarray`
897 nstar x nband array of reference magnitudes
898 refMagErr : `np.ndarray`
899 nstar x nband array of reference magnitude errors
905 md = refStars.getMetadata()
906 if 'FILTERNAMES' in md:
907 filternames = md.getArray(
'FILTERNAMES')
911 refMag = np.zeros((len(refStars), len(bands)),
912 dtype=refStars[
'refMag'].dtype) + 99.0
913 refMagErr = np.zeros_like(refMag) + 99.0
914 for i, filtername
in enumerate(filternames):
918 band = filterMap[filtername]
922 ind = bands.index(band)
926 refMag[:, ind] = refStars[
'refMag'][:, i]
927 refMagErr[:, ind] = refStars[
'refMagErr'][:, i]
931 refMag = refStars[
'refMag'][:, :]
932 refMagErr = refStars[
'refMagErr'][:, :]
934 return refMag, refMagErr
938 instrument = Instrument.fromName(quantumDataId[
"instrument"], registry)
939 unboundedCollection = instrument.makeUnboundedCalibrationRunName()
941 return registry.queryDatasets(datasetType,
942 dataId=quantumDataId,
943 collections=[unboundedCollection])
def extractReferenceMags(refStars, bands, filterMap)
def lookupStaticCalibrations(datasetType, registry, quantumDataId, collections)
def computeApertureRadiusFromDataRef(dataRef, fluxField)
def makeStdSchema(nBands)
def makeAtmCat(atmSchema, atmStruct)
def makeConfigDict(config, log, camera, maxIter, resetFitParameters, outputZeropoints, lutFilterNames, tract=None)
def translateFgcmLut(lutCat, physicalFilterMap)
def computeReferencePixelScale(camera)
def makeZptCat(zptSchema, zpStruct)
def makeStdCat(stdSchema, stdStruct, goodBands)
def computeApertureRadiusFromName(fluxField)
def computeApproxPixelAreaFields(camera)
def makeZptSchema(superStarChebyshevSize, zptChebyshevSize)
def computeCcdOffsets(camera, defaultOrientation)
def translateVisitCatalog(visitCat)