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.
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'),
430 if camera.getName() ==
'HSC' and np.isnan(defaultOrientation):
431 orientation = 270*geom.degrees
433 orientation = defaultOrientation*geom.degrees
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
475 orientation = 0.0*geom.degrees
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
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()
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`
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
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`
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
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
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,
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])
Information about a single exposure of an imaging camera.
A BoundedField that evaluate the pixel area of a SkyWcs in angular units.
Defines the fields and offsets for a table.
Custom catalog class for record/table subclasses that are guaranteed to have an ID,...
Class for storing ordered metadata with comments.
Point in an unspecified spherical coordinate system.
daf::base::PropertyList * list
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
std::string const & getName() const noexcept
Return a filter's name.
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)