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.
42 resetFitParameters, outputZeropoints, tract=None):
44 Make the FGCM fit cycle configuration dict
48 config: `lsst.fgcmcal.FgcmFitCycleConfig`
52 camera: `lsst.afw.cameraGeom.Camera`
53 Camera from the butler
55 Maximum number of iterations
56 resetFitParameters: `bool`
57 Reset fit parameters before fitting?
58 outputZeropoints: `bool`
59 Compute zeropoints for output?
60 tract: `int`, optional
61 Tract number for extending the output file name for debugging.
67 Configuration dictionary for fgcm
70 notFitBands = [b
for b
in config.bands
if b
not in config.fitBands]
74 for ccut
in config.starColorCuts:
75 parts = ccut.split(
',')
76 starColorCutList.append([parts[0], parts[1], float(parts[2]), float(parts[3])])
81 mirrorArea = np.pi*(camera.telescopeDiameter*100./2.)**2.
84 gains = [amp.getGain()
for detector
in camera
for amp
in detector.getAmplifiers()]
85 cameraGain = float(np.median(gains))
88 outfileBase = config.outfileBase
90 outfileBase =
'%s-%06d' % (config.outfileBase, tract)
93 configDict = {
'outfileBase': outfileBase,
99 'mirrorArea': mirrorArea,
100 'cameraGain': cameraGain,
101 'ccdStartIndex': camera[0].getId(),
104 'seeingField':
'DELTA_APER',
105 'fwhmField':
'PSFSIGMA',
106 'skyBrightnessField':
'SKYBACKGROUND',
107 'deepFlag':
'DEEPFLAG',
108 'bands':
list(config.bands),
109 'fitBands':
list(config.fitBands),
110 'notFitBands': notFitBands,
111 'requiredBands':
list(config.requiredBands),
112 'filterToBand': dict(config.filterMap),
114 'nCore': config.nCore,
115 'nStarPerRun': config.nStarPerRun,
116 'nExpPerRun': config.nExpPerRun,
117 'reserveFraction': config.reserveFraction,
118 'freezeStdAtmosphere': config.freezeStdAtmosphere,
119 'precomputeSuperStarInitialCycle': config.precomputeSuperStarInitialCycle,
120 'superStarSubCCDDict': dict(config.superStarSubCcdDict),
121 'superStarSubCCDChebyshevOrder': config.superStarSubCcdChebyshevOrder,
122 'superStarSubCCDTriangular': config.superStarSubCcdTriangular,
123 'superStarSigmaClip': config.superStarSigmaClip,
124 'focalPlaneSigmaClip': config.focalPlaneSigmaClip,
125 'ccdGraySubCCDDict': dict(config.ccdGraySubCcdDict),
126 'ccdGraySubCCDChebyshevOrder': config.ccdGraySubCcdChebyshevOrder,
127 'ccdGraySubCCDTriangular': config.ccdGraySubCcdTriangular,
128 'ccdGrayFocalPlaneDict': dict(config.ccdGrayFocalPlaneDict),
129 'ccdGrayFocalPlaneChebyshevOrder': config.ccdGrayFocalPlaneChebyshevOrder,
130 'ccdGrayFocalPlaneFitMinCcd': config.ccdGrayFocalPlaneFitMinCcd,
131 'cycleNumber': config.cycleNumber,
133 'deltaMagBkgOffsetPercentile': config.deltaMagBkgOffsetPercentile,
134 'deltaMagBkgPerCcd': config.deltaMagBkgPerCcd,
135 'UTBoundary': config.utBoundary,
136 'washMJDs': config.washMjds,
137 'epochMJDs': config.epochMjds,
138 'coatingMJDs': config.coatingMjds,
139 'minObsPerBand': config.minObsPerBand,
140 'latitude': config.latitude,
141 'brightObsGrayMax': config.brightObsGrayMax,
142 'minStarPerCCD': config.minStarPerCcd,
143 'minCCDPerExp': config.minCcdPerExp,
144 'maxCCDGrayErr': config.maxCcdGrayErr,
145 'minStarPerExp': config.minStarPerExp,
146 'minExpPerNight': config.minExpPerNight,
147 'expGrayInitialCut': config.expGrayInitialCut,
148 'expGrayPhotometricCutDict': dict(config.expGrayPhotometricCutDict),
149 'expGrayHighCutDict': dict(config.expGrayHighCutDict),
150 'expGrayRecoverCut': config.expGrayRecoverCut,
151 'expVarGrayPhotometricCutDict': dict(config.expVarGrayPhotometricCutDict),
152 'expGrayErrRecoverCut': config.expGrayErrRecoverCut,
153 'refStarSnMin': config.refStarSnMin,
154 'refStarOutlierNSig': config.refStarOutlierNSig,
155 'applyRefStarColorCuts': config.applyRefStarColorCuts,
156 'illegalValue': -9999.0,
157 'starColorCuts': starColorCutList,
158 'aperCorrFitNBins': config.aperCorrFitNBins,
159 'aperCorrInputSlopeDict': dict(config.aperCorrInputSlopeDict),
160 'sedBoundaryTermDict': config.sedboundaryterms.toDict()[
'data'],
161 'sedTermDict': config.sedterms.toDict()[
'data'],
162 'colorSplitBands':
list(config.colorSplitBands),
163 'sigFgcmMaxErr': config.sigFgcmMaxErr,
164 'sigFgcmMaxEGrayDict': dict(config.sigFgcmMaxEGrayDict),
165 'ccdGrayMaxStarErr': config.ccdGrayMaxStarErr,
166 'approxThroughputDict': dict(config.approxThroughputDict),
167 'sigmaCalRange':
list(config.sigmaCalRange),
168 'sigmaCalFitPercentile':
list(config.sigmaCalFitPercentile),
169 'sigmaCalPlotPercentile':
list(config.sigmaCalPlotPercentile),
170 'sigma0Phot': config.sigma0Phot,
171 'mapLongitudeRef': config.mapLongitudeRef,
172 'mapNSide': config.mapNSide,
175 'useRetrievedPwv':
False,
176 'useNightlyRetrievedPwv':
False,
177 'pwvRetrievalSmoothBlock': 25,
178 'useQuadraticPwv': config.useQuadraticPwv,
179 'useRetrievedTauInit':
False,
180 'tauRetrievalMinCCDPerNight': 500,
181 'modelMagErrors': config.modelMagErrors,
182 'instrumentParsPerBand': config.instrumentParsPerBand,
183 'instrumentSlopeMinDeltaT': config.instrumentSlopeMinDeltaT,
184 'fitMirrorChromaticity': config.fitMirrorChromaticity,
185 'useRepeatabilityForExpGrayCutsDict': dict(config.useRepeatabilityForExpGrayCutsDict),
186 'autoPhotometricCutNSig': config.autoPhotometricCutNSig,
187 'autoHighCutNSig': config.autoHighCutNSig,
189 'quietMode': config.quietMode,
190 'randomSeed': config.randomSeed,
191 'outputStars':
False,
194 'resetParameters': resetFitParameters,
195 'outputFgcmcalZpts':
True,
196 'outputZeropoints': outputZeropoints}
203 Translate the FGCM look-up-table into an fgcm-compatible object
207 lutCat: `lsst.afw.table.BaseCatalog`
208 Catalog describing the FGCM look-up table
210 Filter to band mapping
214 fgcmLut: `lsst.fgcm.FgcmLut`
215 Lookup table for FGCM
216 lutIndexVals: `numpy.ndarray`
217 Numpy array with LUT index information for FGCM
218 lutStd: `numpy.ndarray`
219 Numpy array with LUT standard throughput values for FGCM
223 After running this code, it is wise to `del lutCat` to clear the memory.
228 lutFilterNames = np.array(lutCat[0][
'filterNames'].split(
','), dtype=
'a')
229 lutStdFilterNames = np.array(lutCat[0][
'stdFilterNames'].split(
','), dtype=
'a')
234 lutIndexVals = np.zeros(1, dtype=[(
'FILTERNAMES', lutFilterNames.dtype.str,
235 lutFilterNames.size),
236 (
'STDFILTERNAMES', lutStdFilterNames.dtype.str,
237 lutStdFilterNames.size),
238 (
'PMB',
'f8', lutCat[0][
'pmb'].size),
239 (
'PMBFACTOR',
'f8', lutCat[0][
'pmbFactor'].size),
240 (
'PMBELEVATION',
'f8'),
241 (
'LAMBDANORM',
'f8'),
242 (
'PWV',
'f8', lutCat[0][
'pwv'].size),
243 (
'O3',
'f8', lutCat[0][
'o3'].size),
244 (
'TAU',
'f8', lutCat[0][
'tau'].size),
245 (
'ALPHA',
'f8', lutCat[0][
'alpha'].size),
246 (
'ZENITH',
'f8', lutCat[0][
'zenith'].size),
249 lutIndexVals[
'FILTERNAMES'][:] = lutFilterNames
250 lutIndexVals[
'STDFILTERNAMES'][:] = lutStdFilterNames
251 lutIndexVals[
'PMB'][:] = lutCat[0][
'pmb']
252 lutIndexVals[
'PMBFACTOR'][:] = lutCat[0][
'pmbFactor']
253 lutIndexVals[
'PMBELEVATION'] = lutCat[0][
'pmbElevation']
254 lutIndexVals[
'LAMBDANORM'] = lutCat[0][
'lambdaNorm']
255 lutIndexVals[
'PWV'][:] = lutCat[0][
'pwv']
256 lutIndexVals[
'O3'][:] = lutCat[0][
'o3']
257 lutIndexVals[
'TAU'][:] = lutCat[0][
'tau']
258 lutIndexVals[
'ALPHA'][:] = lutCat[0][
'alpha']
259 lutIndexVals[
'ZENITH'][:] = lutCat[0][
'zenith']
260 lutIndexVals[
'NCCD'] = lutCat[0][
'nCcd']
263 lutStd = np.zeros(1, dtype=[(
'PMBSTD',
'f8'),
269 (
'LAMBDARANGE',
'f8', 2),
270 (
'LAMBDASTEP',
'f8'),
271 (
'LAMBDASTD',
'f8', lutFilterNames.size),
272 (
'LAMBDASTDFILTER',
'f8', lutStdFilterNames.size),
273 (
'I0STD',
'f8', lutFilterNames.size),
274 (
'I1STD',
'f8', lutFilterNames.size),
275 (
'I10STD',
'f8', lutFilterNames.size),
276 (
'I2STD',
'f8', lutFilterNames.size),
277 (
'LAMBDAB',
'f8', lutFilterNames.size),
278 (
'ATMLAMBDA',
'f8', lutCat[0][
'atmLambda'].size),
279 (
'ATMSTDTRANS',
'f8', lutCat[0][
'atmStdTrans'].size)])
280 lutStd[
'PMBSTD'] = lutCat[0][
'pmbStd']
281 lutStd[
'PWVSTD'] = lutCat[0][
'pwvStd']
282 lutStd[
'O3STD'] = lutCat[0][
'o3Std']
283 lutStd[
'TAUSTD'] = lutCat[0][
'tauStd']
284 lutStd[
'ALPHASTD'] = lutCat[0][
'alphaStd']
285 lutStd[
'ZENITHSTD'] = lutCat[0][
'zenithStd']
286 lutStd[
'LAMBDARANGE'][:] = lutCat[0][
'lambdaRange'][:]
287 lutStd[
'LAMBDASTEP'] = lutCat[0][
'lambdaStep']
288 lutStd[
'LAMBDASTD'][:] = lutCat[0][
'lambdaStd']
289 lutStd[
'LAMBDASTDFILTER'][:] = lutCat[0][
'lambdaStdFilter']
290 lutStd[
'I0STD'][:] = lutCat[0][
'i0Std']
291 lutStd[
'I1STD'][:] = lutCat[0][
'i1Std']
292 lutStd[
'I10STD'][:] = lutCat[0][
'i10Std']
293 lutStd[
'I2STD'][:] = lutCat[0][
'i2Std']
294 lutStd[
'LAMBDAB'][:] = lutCat[0][
'lambdaB']
295 lutStd[
'ATMLAMBDA'][:] = lutCat[0][
'atmLambda'][:]
296 lutStd[
'ATMSTDTRANS'][:] = lutCat[0][
'atmStdTrans'][:]
298 lutTypes = [row[
'luttype']
for row
in lutCat]
301 lutFlat = np.zeros(lutCat[0][
'lut'].size, dtype=[(
'I0',
'f4'),
304 lutFlat[
'I0'][:] = lutCat[lutTypes.index(
'I0')][
'lut'][:]
305 lutFlat[
'I1'][:] = lutCat[lutTypes.index(
'I1')][
'lut'][:]
307 lutDerivFlat = np.zeros(lutCat[0][
'lut'].size, dtype=[(
'D_LNPWV',
'f4'),
311 (
'D_SECZENITH',
'f4'),
312 (
'D_LNPWV_I1',
'f4'),
314 (
'D_LNTAU_I1',
'f4'),
315 (
'D_ALPHA_I1',
'f4'),
316 (
'D_SECZENITH_I1',
'f4')])
318 for name
in lutDerivFlat.dtype.names:
319 lutDerivFlat[name][:] = lutCat[lutTypes.index(name)][
'lut'][:]
326 fgcmLut = fgcm.FgcmLUT(lutIndexVals, lutFlat, lutDerivFlat, lutStd,
327 filterToBand=filterMap)
329 return fgcmLut, lutIndexVals, lutStd
334 Translate the FGCM visit catalog to an fgcm-compatible object
338 visitCat: `lsst.afw.table.BaseCatalog`
339 FGCM visitCat from `lsst.fgcmcal.FgcmBuildStarsTask`
343 fgcmExpInfo: `numpy.ndarray`
344 Numpy array for visit information for FGCM
348 After running this code, it is wise to `del visitCat` to clear the memory.
351 fgcmExpInfo = np.zeros(len(visitCat), dtype=[(
'VISIT',
'i8'),
355 (
'DELTA_APER',
'f8'),
356 (
'SKYBACKGROUND',
'f8'),
363 (
'FILTERNAME',
'a10')])
364 fgcmExpInfo[
'VISIT'][:] = visitCat[
'visit']
365 fgcmExpInfo[
'MJD'][:] = visitCat[
'mjd']
366 fgcmExpInfo[
'EXPTIME'][:] = visitCat[
'exptime']
367 fgcmExpInfo[
'DEEPFLAG'][:] = visitCat[
'deepFlag']
368 fgcmExpInfo[
'TELHA'][:] = visitCat[
'telha']
369 fgcmExpInfo[
'TELRA'][:] = visitCat[
'telra']
370 fgcmExpInfo[
'TELDEC'][:] = visitCat[
'teldec']
371 fgcmExpInfo[
'TELROT'][:] = visitCat[
'telrot']
372 fgcmExpInfo[
'PMB'][:] = visitCat[
'pmb']
373 fgcmExpInfo[
'PSFSIGMA'][:] = visitCat[
'psfSigma']
374 fgcmExpInfo[
'DELTA_APER'][:] = visitCat[
'deltaAper']
375 fgcmExpInfo[
'SKYBACKGROUND'][:] = visitCat[
'skyBackground']
378 fgcmExpInfo[
'FILTERNAME'][:] = visitCat.asAstropy()[
'filtername']
385 Compute the CCD offsets in ra/dec and x/y space
389 camera: `lsst.afw.cameraGeom.Camera`
390 defaultOrientation: `float`
391 Default camera orientation (degrees)
395 ccdOffsets: `numpy.ndarray`
396 Numpy array with ccd offset information for input to FGCM.
397 Angular units are degrees, and x/y units are pixels.
402 ccdOffsets = np.zeros(len(camera), dtype=[(
'CCDNUM',
'i4'),
417 if camera.getName() ==
'HSC' and np.isnan(defaultOrientation):
418 orientation = 270*geom.degrees
420 orientation = defaultOrientation*geom.degrees
425 boresightRotAngle=orientation,
426 rotType=afwImage.visitInfo.RotType.SKY)
428 for i, detector
in enumerate(camera):
429 ccdOffsets[
'CCDNUM'][i] = detector.getId()
433 detCenter = wcs.pixelToSky(detector.getCenter(afwCameraGeom.PIXELS))
434 ccdOffsets[
'DELTA_RA'][i] = (detCenter.getRa() - boresight.getRa()).asDegrees()
435 ccdOffsets[
'DELTA_DEC'][i] = (detCenter.getDec() - boresight.getDec()).asDegrees()
437 bbox = detector.getBBox()
439 detCorner1 = wcs.pixelToSky(
geom.Point2D(bbox.getMin()))
440 detCorner2 = wcs.pixelToSky(
geom.Point2D(bbox.getMax()))
442 ccdOffsets[
'RA_SIZE'][i] = np.abs((detCorner2.getRa() - detCorner1.getRa()).asDegrees())
443 ccdOffsets[
'DEC_SIZE'][i] = np.abs((detCorner2.getDec() - detCorner1.getDec()).asDegrees())
445 ccdOffsets[
'X_SIZE'][i] = bbox.getMaxX()
446 ccdOffsets[
'Y_SIZE'][i] = bbox.getMaxY()
453 Compute the median pixel scale in the camera
458 Average pixel scale (arcsecond) over the camera
462 orientation = 0.0*geom.degrees
467 boresightRotAngle=orientation,
468 rotType=afwImage.visitInfo.RotType.SKY)
470 pixelScales = np.zeros(len(camera))
471 for i, detector
in enumerate(camera):
473 pixelScales[i] = wcs.getPixelScale().asArcseconds()
475 ok, = np.where(pixelScales > 0.0)
476 return np.median(pixelScales[ok])
481 Compute the approximate pixel area bounded fields from the camera
486 camera: `lsst.afw.cameraGeom.Camera`
490 approxPixelAreaFields: `dict`
491 Dictionary of approximate area fields, keyed with detector ID
504 boresightRotAngle=0.0*geom.degrees,
505 rotType=afwImage.visitInfo.RotType.SKY)
507 approxPixelAreaFields = {}
509 for i, detector
in enumerate(camera):
510 key = detector.getId()
513 bbox = detector.getBBox()
516 unit=geom.arcseconds, scaling=areaScaling)
517 approxAreaField = afwMath.ChebyshevBoundedField.approximate(areaField)
519 approxPixelAreaFields[key] = approxAreaField
521 return approxPixelAreaFields
526 Make the zeropoint schema
530 superStarChebyshevSize: `int`
531 Length of the superstar chebyshev array
532 zptChebyshevSize: `int`
533 Length of the zeropoint chebyshev array
537 zptSchema: `lsst.afw.table.schema`
542 zptSchema.addField(
'visit', type=np.int32, doc=
'Visit number')
543 zptSchema.addField(
'ccd', type=np.int32, doc=
'CCD number')
544 zptSchema.addField(
'fgcmFlag', type=np.int32, doc=(
'FGCM flag value: '
545 '1: Photometric, used in fit; '
546 '2: Photometric, not used in fit; '
547 '4: Non-photometric, on partly photometric night; '
548 '8: Non-photometric, on non-photometric night; '
549 '16: No zeropoint could be determined; '
550 '32: Too few stars for reliable gray computation'))
551 zptSchema.addField(
'fgcmZpt', type=np.float64, doc=
'FGCM zeropoint (center of CCD)')
552 zptSchema.addField(
'fgcmZptErr', type=np.float64,
553 doc=
'Error on zeropoint, estimated from repeatability + number of obs')
554 zptSchema.addField(
'fgcmfZptChebXyMax', type=
'ArrayD', size=2,
555 doc=
'maximum x/maximum y to scale to apply chebyshev parameters')
556 zptSchema.addField(
'fgcmfZptCheb', type=
'ArrayD',
557 size=zptChebyshevSize,
558 doc=
'Chebyshev parameters (flattened) for zeropoint')
559 zptSchema.addField(
'fgcmfZptSstarCheb', type=
'ArrayD',
560 size=superStarChebyshevSize,
561 doc=
'Chebyshev parameters (flattened) for superStarFlat')
562 zptSchema.addField(
'fgcmI0', type=np.float64, doc=
'Integral of the passband')
563 zptSchema.addField(
'fgcmI10', type=np.float64, doc=
'Normalized chromatic integral')
564 zptSchema.addField(
'fgcmR0', type=np.float64,
565 doc=
'Retrieved i0 integral, estimated from stars (only for flag 1)')
566 zptSchema.addField(
'fgcmR10', type=np.float64,
567 doc=
'Retrieved i10 integral, estimated from stars (only for flag 1)')
568 zptSchema.addField(
'fgcmGry', type=np.float64,
569 doc=
'Estimated gray extinction relative to atmospheric solution; '
570 'only for fgcmFlag <= 4 (see fgcmFlag) ')
571 zptSchema.addField(
'fgcmDeltaChrom', type=np.float64,
572 doc=
'Mean chromatic correction for stars in this ccd; '
573 'only for fgcmFlag <= 4 (see fgcmFlag)')
574 zptSchema.addField(
'fgcmZptVar', type=np.float64, doc=
'Variance of zeropoint over ccd')
575 zptSchema.addField(
'fgcmTilings', type=np.float64,
576 doc=
'Number of photometric tilings used for solution for ccd')
577 zptSchema.addField(
'fgcmFpGry', type=np.float64,
578 doc=
'Average gray extinction over the full focal plane '
579 '(same for all ccds in a visit)')
580 zptSchema.addField(
'fgcmFpGryBlue', type=np.float64,
581 doc=
'Average gray extinction over the full focal plane '
582 'for 25% bluest stars')
583 zptSchema.addField(
'fgcmFpGryBlueErr', type=np.float64,
584 doc=
'Error on Average gray extinction over the full focal plane '
585 'for 25% bluest stars')
586 zptSchema.addField(
'fgcmFpGryRed', type=np.float64,
587 doc=
'Average gray extinction over the full focal plane '
588 'for 25% reddest stars')
589 zptSchema.addField(
'fgcmFpGryRedErr', type=np.float64,
590 doc=
'Error on Average gray extinction over the full focal plane '
591 'for 25% reddest stars')
592 zptSchema.addField(
'fgcmFpVar', type=np.float64,
593 doc=
'Variance of gray extinction over the full focal plane '
594 '(same for all ccds in a visit)')
595 zptSchema.addField(
'fgcmDust', type=np.float64,
596 doc=
'Gray dust extinction from the primary/corrector'
597 'at the time of the exposure')
598 zptSchema.addField(
'fgcmFlat', type=np.float64, doc=
'Superstarflat illumination correction')
599 zptSchema.addField(
'fgcmAperCorr', type=np.float64, doc=
'Aperture correction estimated by fgcm')
600 zptSchema.addField(
'fgcmDeltaMagBkg', type=np.float64,
601 doc=(
'Local background correction from brightest percentile '
602 '(value set by deltaMagBkgOffsetPercentile) calibration '
604 zptSchema.addField(
'exptime', type=np.float32, doc=
'Exposure time')
605 zptSchema.addField(
'filtername', type=str, size=10, doc=
'Filter name')
612 Make the zeropoint catalog for persistence
616 zptSchema: `lsst.afw.table.Schema`
617 Zeropoint catalog schema
618 zpStruct: `numpy.ndarray`
619 Zeropoint structure from fgcm
623 zptCat: `afwTable.BaseCatalog`
624 Zeropoint catalog for persistence
628 zptCat.reserve(zpStruct.size)
630 for filterName
in zpStruct[
'FILTERNAME']:
631 rec = zptCat.addNew()
632 rec[
'filtername'] = filterName.decode(
'utf-8')
634 zptCat[
'visit'][:] = zpStruct[
'VISIT']
635 zptCat[
'ccd'][:] = zpStruct[
'CCD']
636 zptCat[
'fgcmFlag'][:] = zpStruct[
'FGCM_FLAG']
637 zptCat[
'fgcmZpt'][:] = zpStruct[
'FGCM_ZPT']
638 zptCat[
'fgcmZptErr'][:] = zpStruct[
'FGCM_ZPTERR']
639 zptCat[
'fgcmfZptChebXyMax'][:, :] = zpStruct[
'FGCM_FZPT_XYMAX']
640 zptCat[
'fgcmfZptCheb'][:, :] = zpStruct[
'FGCM_FZPT_CHEB']
641 zptCat[
'fgcmfZptSstarCheb'][:, :] = zpStruct[
'FGCM_FZPT_SSTAR_CHEB']
642 zptCat[
'fgcmI0'][:] = zpStruct[
'FGCM_I0']
643 zptCat[
'fgcmI10'][:] = zpStruct[
'FGCM_I10']
644 zptCat[
'fgcmR0'][:] = zpStruct[
'FGCM_R0']
645 zptCat[
'fgcmR10'][:] = zpStruct[
'FGCM_R10']
646 zptCat[
'fgcmGry'][:] = zpStruct[
'FGCM_GRY']
647 zptCat[
'fgcmDeltaChrom'][:] = zpStruct[
'FGCM_DELTACHROM']
648 zptCat[
'fgcmZptVar'][:] = zpStruct[
'FGCM_ZPTVAR']
649 zptCat[
'fgcmTilings'][:] = zpStruct[
'FGCM_TILINGS']
650 zptCat[
'fgcmFpGry'][:] = zpStruct[
'FGCM_FPGRY']
651 zptCat[
'fgcmFpGryBlue'][:] = zpStruct[
'FGCM_FPGRY_CSPLIT'][:, 0]
652 zptCat[
'fgcmFpGryBlueErr'][:] = zpStruct[
'FGCM_FPGRY_CSPLITERR'][:, 0]
653 zptCat[
'fgcmFpGryRed'][:] = zpStruct[
'FGCM_FPGRY_CSPLIT'][:, 2]
654 zptCat[
'fgcmFpGryRedErr'][:] = zpStruct[
'FGCM_FPGRY_CSPLITERR'][:, 2]
655 zptCat[
'fgcmFpVar'][:] = zpStruct[
'FGCM_FPVAR']
656 zptCat[
'fgcmDust'][:] = zpStruct[
'FGCM_DUST']
657 zptCat[
'fgcmFlat'][:] = zpStruct[
'FGCM_FLAT']
658 zptCat[
'fgcmAperCorr'][:] = zpStruct[
'FGCM_APERCORR']
659 zptCat[
'fgcmDeltaMagBkg'][:] = zpStruct[
'FGCM_DELTAMAGBKG']
660 zptCat[
'exptime'][:] = zpStruct[
'EXPTIME']
667 Make the atmosphere schema
671 atmSchema: `lsst.afw.table.Schema`
676 atmSchema.addField(
'visit', type=np.int32, doc=
'Visit number')
677 atmSchema.addField(
'pmb', type=np.float64, doc=
'Barometric pressure (mb)')
678 atmSchema.addField(
'pwv', type=np.float64, doc=
'Water vapor (mm)')
679 atmSchema.addField(
'tau', type=np.float64, doc=
'Aerosol optical depth')
680 atmSchema.addField(
'alpha', type=np.float64, doc=
'Aerosol slope')
681 atmSchema.addField(
'o3', type=np.float64, doc=
'Ozone (dobson)')
682 atmSchema.addField(
'secZenith', type=np.float64, doc=
'Secant(zenith) (~ airmass)')
683 atmSchema.addField(
'cTrans', type=np.float64, doc=
'Transmission correction factor')
684 atmSchema.addField(
'lamStd', type=np.float64, doc=
'Wavelength for transmission correction')
691 Make the atmosphere catalog for persistence
695 atmSchema: `lsst.afw.table.Schema`
696 Atmosphere catalog schema
697 atmStruct: `numpy.ndarray`
698 Atmosphere structure from fgcm
702 atmCat: `lsst.afw.table.BaseCatalog`
703 Atmosphere catalog for persistence
707 atmCat.resize(atmStruct.size)
709 atmCat[
'visit'][:] = atmStruct[
'VISIT']
710 atmCat[
'pmb'][:] = atmStruct[
'PMB']
711 atmCat[
'pwv'][:] = atmStruct[
'PWV']
712 atmCat[
'tau'][:] = atmStruct[
'TAU']
713 atmCat[
'alpha'][:] = atmStruct[
'ALPHA']
714 atmCat[
'o3'][:] = atmStruct[
'O3']
715 atmCat[
'secZenith'][:] = atmStruct[
'SECZENITH']
716 atmCat[
'cTrans'][:] = atmStruct[
'CTRANS']
717 atmCat[
'lamStd'][:] = atmStruct[
'LAMSTD']
724 Make the standard star schema
729 Number of bands in standard star catalog
733 stdSchema: `lsst.afw.table.Schema`
736 stdSchema = afwTable.SimpleTable.makeMinimalSchema()
737 stdSchema.addField(
'ngood', type=
'ArrayI', doc=
'Number of good observations',
739 stdSchema.addField(
'ntotal', type=
'ArrayI', doc=
'Number of total observations',
741 stdSchema.addField(
'mag_std_noabs', type=
'ArrayF',
742 doc=
'Standard magnitude (no absolute calibration)',
744 stdSchema.addField(
'magErr_std', type=
'ArrayF',
745 doc=
'Standard magnitude error',
747 stdSchema.addField(
'npsfcand', type=
'ArrayI',
748 doc=
'Number of observations flagged as psf candidates',
756 Make the standard star catalog for persistence
760 stdSchema: `lsst.afw.table.Schema`
761 Standard star catalog schema
762 stdStruct: `numpy.ndarray`
763 Standard star structure in FGCM format
765 List of good band names used in stdStruct
769 stdCat: `lsst.afw.table.BaseCatalog`
770 Standard star catalog for persistence
774 stdCat.resize(stdStruct.size)
776 stdCat[
'id'][:] = stdStruct[
'FGCM_ID']
777 stdCat[
'coord_ra'][:] = stdStruct[
'RA'] * geom.degrees
778 stdCat[
'coord_dec'][:] = stdStruct[
'DEC'] * geom.degrees
779 stdCat[
'ngood'][:, :] = stdStruct[
'NGOOD'][:, :]
780 stdCat[
'ntotal'][:, :] = stdStruct[
'NTOTAL'][:, :]
781 stdCat[
'mag_std_noabs'][:, :] = stdStruct[
'MAG_STD'][:, :]
782 stdCat[
'magErr_std'][:, :] = stdStruct[
'MAGERR_STD'][:, :]
783 stdCat[
'npsfcand'][:, :] = stdStruct[
'NPSFCAND'][:, :]
786 md.set(
"BANDS",
list(goodBands))
787 stdCat.setMetadata(md)
794 Compute the radius associated with a CircularApertureFlux field or
799 dataRef : `lsst.daf.persistence.ButlerDataRef`
801 CircularApertureFlux or associated slot.
805 apertureRadius : `float`
806 Radius of the aperture field, in pixels.
810 RuntimeError: Raised if flux field is not a CircularApertureFlux, ApFlux,
814 datasetType = dataRef.butlerSubset.datasetType
816 if datasetType ==
'src':
817 schema = dataRef.get(datasetType=
'src_schema').schema
819 fluxFieldName = schema[fluxField].asField().getName()
821 raise RuntimeError(
"Could not find %s or associated slot in schema." % (fluxField))
828 return apertureRadius
833 Compute the radius associated with a CircularApertureFlux or ApFlux field.
838 CircularApertureFlux or ApFlux
842 apertureRadius : `float`
843 Radius of the aperture field, in pixels.
847 RuntimeError: Raised if flux field is not a CircularApertureFlux
851 m = re.search(
r'(CircularApertureFlux|ApFlux)_(\d+)_(\d+)_', fluxField)
854 raise RuntimeError(f
"Flux field {fluxField} does not correspond to a CircularApertureFlux or ApFlux")
856 apertureRadius = float(m.groups()[1]) + float(m.groups()[2])/10.
858 return apertureRadius
863 Extract reference magnitudes from refStars for given bands and
864 associated filterMap.
868 refStars : `lsst.afw.table.BaseCatalog`
869 FGCM reference star catalog
871 List of bands for calibration
873 FGCM mapping of filter to band
877 refMag : `np.ndarray`
878 nstar x nband array of reference magnitudes
879 refMagErr : `np.ndarray`
880 nstar x nband array of reference magnitude errors
886 md = refStars.getMetadata()
887 if 'FILTERNAMES' in md:
888 filternames = md.getArray(
'FILTERNAMES')
892 refMag = np.zeros((len(refStars), len(bands)),
893 dtype=refStars[
'refMag'].dtype) + 99.0
894 refMagErr = np.zeros_like(refMag) + 99.0
895 for i, filtername
in enumerate(filternames):
899 band = filterMap[filtername]
903 ind = bands.index(band)
907 refMag[:, ind] = refStars[
'refMag'][:, i]
908 refMagErr[:, ind] = refStars[
'refMagErr'][:, i]
912 refMag = refStars[
'refMag'][:, :]
913 refMagErr = refStars[
'refMagErr'][:, :]
915 return refMag, refMagErr