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'
46 FGCM_ILLEGAL_VALUE = -9999.0
50 resetFitParameters, outputZeropoints,
51 lutFilterNames, tract=None):
53 Make the FGCM fit cycle configuration dict
57 config: `lsst.fgcmcal.FgcmFitCycleConfig`
61 camera: `lsst.afw.cameraGeom.Camera`
62 Camera from the butler
64 Maximum number of iterations
65 resetFitParameters: `bool`
66 Reset fit parameters before fitting?
67 outputZeropoints: `bool`
68 Compute zeropoints for output?
69 lutFilterNames : array-like, `str`
70 Array of physical filter names in the LUT.
71 tract: `int`, optional
72 Tract number for extending the output file name for debugging.
78 Configuration dictionary for fgcm
81 notFitBands = [b
for b
in config.bands
if b
not in config.fitBands]
85 for ccut
in config.starColorCuts:
86 parts = ccut.split(
',')
87 starColorCutList.append([parts[0], parts[1], float(parts[2]), float(parts[3])])
92 mirrorArea = np.pi*(camera.telescopeDiameter*100./2.)**2.
95 gains = [amp.getGain()
for detector
in camera
for amp
in detector.getAmplifiers()]
96 cameraGain = float(np.median(gains))
99 filterToBand = {filterName: config.physicalFilterMap[filterName]
for
100 filterName
in lutFilterNames}
103 outfileBase = config.outfileBase
105 outfileBase =
'%s-%06d' % (config.outfileBase, tract)
108 configDict = {
'outfileBase': outfileBase,
110 'exposureFile':
None,
114 'mirrorArea': mirrorArea,
115 'cameraGain': cameraGain,
116 'ccdStartIndex': camera[0].getId(),
117 'expField': FGCM_EXP_FIELD,
118 'ccdField': FGCM_CCD_FIELD,
119 'seeingField':
'DELTA_APER',
120 'fwhmField':
'PSFSIGMA',
121 'skyBrightnessField':
'SKYBACKGROUND',
122 'deepFlag':
'DEEPFLAG',
123 'bands':
list(config.bands),
124 'fitBands':
list(config.fitBands),
125 'notFitBands': notFitBands,
126 'requiredBands':
list(config.requiredBands),
127 'filterToBand': filterToBand,
129 'nCore': config.nCore,
130 'nStarPerRun': config.nStarPerRun,
131 'nExpPerRun': config.nExpPerRun,
132 'reserveFraction': config.reserveFraction,
133 'freezeStdAtmosphere': config.freezeStdAtmosphere,
134 'precomputeSuperStarInitialCycle': config.precomputeSuperStarInitialCycle,
135 'superStarSubCCDDict': dict(config.superStarSubCcdDict),
136 'superStarSubCCDChebyshevOrder': config.superStarSubCcdChebyshevOrder,
137 'superStarSubCCDTriangular': config.superStarSubCcdTriangular,
138 'superStarSigmaClip': config.superStarSigmaClip,
139 'focalPlaneSigmaClip': config.focalPlaneSigmaClip,
140 'ccdGraySubCCDDict': dict(config.ccdGraySubCcdDict),
141 'ccdGraySubCCDChebyshevOrder': config.ccdGraySubCcdChebyshevOrder,
142 'ccdGraySubCCDTriangular': config.ccdGraySubCcdTriangular,
143 'ccdGrayFocalPlaneDict': dict(config.ccdGrayFocalPlaneDict),
144 'ccdGrayFocalPlaneChebyshevOrder': config.ccdGrayFocalPlaneChebyshevOrder,
145 'ccdGrayFocalPlaneFitMinCcd': config.ccdGrayFocalPlaneFitMinCcd,
146 'cycleNumber': config.cycleNumber,
148 'deltaMagBkgOffsetPercentile': config.deltaMagBkgOffsetPercentile,
149 'deltaMagBkgPerCcd': config.deltaMagBkgPerCcd,
150 'UTBoundary': config.utBoundary,
151 'washMJDs': config.washMjds,
152 'epochMJDs': config.epochMjds,
153 'coatingMJDs': config.coatingMjds,
154 'minObsPerBand': config.minObsPerBand,
155 'latitude': config.latitude,
156 'brightObsGrayMax': config.brightObsGrayMax,
157 'minStarPerCCD': config.minStarPerCcd,
158 'minCCDPerExp': config.minCcdPerExp,
159 'maxCCDGrayErr': config.maxCcdGrayErr,
160 'minStarPerExp': config.minStarPerExp,
161 'minExpPerNight': config.minExpPerNight,
162 'expGrayInitialCut': config.expGrayInitialCut,
163 'expGrayPhotometricCutDict': dict(config.expGrayPhotometricCutDict),
164 'expGrayHighCutDict': dict(config.expGrayHighCutDict),
165 'expGrayRecoverCut': config.expGrayRecoverCut,
166 'expVarGrayPhotometricCutDict': dict(config.expVarGrayPhotometricCutDict),
167 'expGrayErrRecoverCut': config.expGrayErrRecoverCut,
168 'refStarSnMin': config.refStarSnMin,
169 'refStarOutlierNSig': config.refStarOutlierNSig,
170 'applyRefStarColorCuts': config.applyRefStarColorCuts,
171 'illegalValue': FGCM_ILLEGAL_VALUE,
172 'starColorCuts': starColorCutList,
173 'aperCorrFitNBins': config.aperCorrFitNBins,
174 'aperCorrInputSlopeDict': dict(config.aperCorrInputSlopeDict),
175 'sedBoundaryTermDict': config.sedboundaryterms.toDict()[
'data'],
176 'sedTermDict': config.sedterms.toDict()[
'data'],
177 'colorSplitBands':
list(config.colorSplitBands),
178 'sigFgcmMaxErr': config.sigFgcmMaxErr,
179 'sigFgcmMaxEGrayDict': dict(config.sigFgcmMaxEGrayDict),
180 'ccdGrayMaxStarErr': config.ccdGrayMaxStarErr,
181 'approxThroughputDict': dict(config.approxThroughputDict),
182 'sigmaCalRange':
list(config.sigmaCalRange),
183 'sigmaCalFitPercentile':
list(config.sigmaCalFitPercentile),
184 'sigmaCalPlotPercentile':
list(config.sigmaCalPlotPercentile),
185 'sigma0Phot': config.sigma0Phot,
186 'mapLongitudeRef': config.mapLongitudeRef,
187 'mapNSide': config.mapNSide,
190 'useRetrievedPwv':
False,
191 'useNightlyRetrievedPwv':
False,
192 'pwvRetrievalSmoothBlock': 25,
193 'useQuadraticPwv': config.useQuadraticPwv,
194 'useRetrievedTauInit':
False,
195 'tauRetrievalMinCCDPerNight': 500,
196 'modelMagErrors': config.modelMagErrors,
197 'instrumentParsPerBand': config.instrumentParsPerBand,
198 'instrumentSlopeMinDeltaT': config.instrumentSlopeMinDeltaT,
199 'fitMirrorChromaticity': config.fitMirrorChromaticity,
200 'useRepeatabilityForExpGrayCutsDict': dict(config.useRepeatabilityForExpGrayCutsDict),
201 'autoPhotometricCutNSig': config.autoPhotometricCutNSig,
202 'autoHighCutNSig': config.autoHighCutNSig,
204 'quietMode': config.quietMode,
205 'randomSeed': config.randomSeed,
206 'outputStars':
False,
207 'outputPath': os.path.abspath(
'.'),
210 'resetParameters': resetFitParameters,
211 'doPlots': config.doPlots,
212 'outputFgcmcalZpts':
True,
213 'outputZeropoints': outputZeropoints}
220 Translate the FGCM look-up-table into an fgcm-compatible object
224 lutCat: `lsst.afw.table.BaseCatalog`
225 Catalog describing the FGCM look-up table
226 physicalFilterMap: `dict`
227 Physical filter to band mapping
231 fgcmLut: `lsst.fgcm.FgcmLut`
232 Lookup table for FGCM
233 lutIndexVals: `numpy.ndarray`
234 Numpy array with LUT index information for FGCM
235 lutStd: `numpy.ndarray`
236 Numpy array with LUT standard throughput values for FGCM
240 After running this code, it is wise to `del lutCat` to clear the memory.
244 lutFilterNames = np.array(lutCat[0][
'physicalFilters'].split(
','), dtype=
'U')
245 lutStdFilterNames = np.array(lutCat[0][
'stdPhysicalFilters'].split(
','), dtype=
'U')
250 lutIndexVals = np.zeros(1, dtype=[(
'FILTERNAMES', lutFilterNames.dtype.str,
251 lutFilterNames.size),
252 (
'STDFILTERNAMES', lutStdFilterNames.dtype.str,
253 lutStdFilterNames.size),
254 (
'PMB',
'f8', lutCat[0][
'pmb'].size),
255 (
'PMBFACTOR',
'f8', lutCat[0][
'pmbFactor'].size),
256 (
'PMBELEVATION',
'f8'),
257 (
'LAMBDANORM',
'f8'),
258 (
'PWV',
'f8', lutCat[0][
'pwv'].size),
259 (
'O3',
'f8', lutCat[0][
'o3'].size),
260 (
'TAU',
'f8', lutCat[0][
'tau'].size),
261 (
'ALPHA',
'f8', lutCat[0][
'alpha'].size),
262 (
'ZENITH',
'f8', lutCat[0][
'zenith'].size),
265 lutIndexVals[
'FILTERNAMES'][:] = lutFilterNames
266 lutIndexVals[
'STDFILTERNAMES'][:] = lutStdFilterNames
267 lutIndexVals[
'PMB'][:] = lutCat[0][
'pmb']
268 lutIndexVals[
'PMBFACTOR'][:] = lutCat[0][
'pmbFactor']
269 lutIndexVals[
'PMBELEVATION'] = lutCat[0][
'pmbElevation']
270 lutIndexVals[
'LAMBDANORM'] = lutCat[0][
'lambdaNorm']
271 lutIndexVals[
'PWV'][:] = lutCat[0][
'pwv']
272 lutIndexVals[
'O3'][:] = lutCat[0][
'o3']
273 lutIndexVals[
'TAU'][:] = lutCat[0][
'tau']
274 lutIndexVals[
'ALPHA'][:] = lutCat[0][
'alpha']
275 lutIndexVals[
'ZENITH'][:] = lutCat[0][
'zenith']
276 lutIndexVals[
'NCCD'] = lutCat[0][
'nCcd']
279 lutStd = np.zeros(1, dtype=[(
'PMBSTD',
'f8'),
285 (
'LAMBDARANGE',
'f8', 2),
286 (
'LAMBDASTEP',
'f8'),
287 (
'LAMBDASTD',
'f8', lutFilterNames.size),
288 (
'LAMBDASTDFILTER',
'f8', lutStdFilterNames.size),
289 (
'I0STD',
'f8', lutFilterNames.size),
290 (
'I1STD',
'f8', lutFilterNames.size),
291 (
'I10STD',
'f8', lutFilterNames.size),
292 (
'I2STD',
'f8', lutFilterNames.size),
293 (
'LAMBDAB',
'f8', lutFilterNames.size),
294 (
'ATMLAMBDA',
'f8', lutCat[0][
'atmLambda'].size),
295 (
'ATMSTDTRANS',
'f8', lutCat[0][
'atmStdTrans'].size)])
296 lutStd[
'PMBSTD'] = lutCat[0][
'pmbStd']
297 lutStd[
'PWVSTD'] = lutCat[0][
'pwvStd']
298 lutStd[
'O3STD'] = lutCat[0][
'o3Std']
299 lutStd[
'TAUSTD'] = lutCat[0][
'tauStd']
300 lutStd[
'ALPHASTD'] = lutCat[0][
'alphaStd']
301 lutStd[
'ZENITHSTD'] = lutCat[0][
'zenithStd']
302 lutStd[
'LAMBDARANGE'][:] = lutCat[0][
'lambdaRange'][:]
303 lutStd[
'LAMBDASTEP'] = lutCat[0][
'lambdaStep']
304 lutStd[
'LAMBDASTD'][:] = lutCat[0][
'lambdaStd']
305 lutStd[
'LAMBDASTDFILTER'][:] = lutCat[0][
'lambdaStdFilter']
306 lutStd[
'I0STD'][:] = lutCat[0][
'i0Std']
307 lutStd[
'I1STD'][:] = lutCat[0][
'i1Std']
308 lutStd[
'I10STD'][:] = lutCat[0][
'i10Std']
309 lutStd[
'I2STD'][:] = lutCat[0][
'i2Std']
310 lutStd[
'LAMBDAB'][:] = lutCat[0][
'lambdaB']
311 lutStd[
'ATMLAMBDA'][:] = lutCat[0][
'atmLambda'][:]
312 lutStd[
'ATMSTDTRANS'][:] = lutCat[0][
'atmStdTrans'][:]
314 lutTypes = [row[
'luttype']
for row
in lutCat]
317 lutFlat = np.zeros(lutCat[0][
'lut'].size, dtype=[(
'I0',
'f4'),
320 lutFlat[
'I0'][:] = lutCat[lutTypes.index(
'I0')][
'lut'][:]
321 lutFlat[
'I1'][:] = lutCat[lutTypes.index(
'I1')][
'lut'][:]
323 lutDerivFlat = np.zeros(lutCat[0][
'lut'].size, dtype=[(
'D_LNPWV',
'f4'),
327 (
'D_SECZENITH',
'f4'),
328 (
'D_LNPWV_I1',
'f4'),
330 (
'D_LNTAU_I1',
'f4'),
331 (
'D_ALPHA_I1',
'f4'),
332 (
'D_SECZENITH_I1',
'f4')])
334 for name
in lutDerivFlat.dtype.names:
335 lutDerivFlat[name][:] = lutCat[lutTypes.index(name)][
'lut'][:]
342 fgcmLut = fgcm.FgcmLUT(lutIndexVals, lutFlat, lutDerivFlat, lutStd,
343 filterToBand=physicalFilterMap)
345 return fgcmLut, lutIndexVals, lutStd
350 Translate the FGCM visit catalog to an fgcm-compatible object
354 visitCat: `lsst.afw.table.BaseCatalog`
355 FGCM visitCat from `lsst.fgcmcal.FgcmBuildStarsTask`
359 fgcmExpInfo: `numpy.ndarray`
360 Numpy array for visit information for FGCM
364 After running this code, it is wise to `del visitCat` to clear the memory.
367 fgcmExpInfo = np.zeros(len(visitCat), dtype=[(
'VISIT',
'i8'),
371 (
'DELTA_APER',
'f8'),
372 (
'SKYBACKGROUND',
'f8'),
379 (
'FILTERNAME',
'a50')])
380 fgcmExpInfo[
'VISIT'][:] = visitCat[
'visit']
381 fgcmExpInfo[
'MJD'][:] = visitCat[
'mjd']
382 fgcmExpInfo[
'EXPTIME'][:] = visitCat[
'exptime']
383 fgcmExpInfo[
'DEEPFLAG'][:] = visitCat[
'deepFlag']
384 fgcmExpInfo[
'TELHA'][:] = visitCat[
'telha']
385 fgcmExpInfo[
'TELRA'][:] = visitCat[
'telra']
386 fgcmExpInfo[
'TELDEC'][:] = visitCat[
'teldec']
387 fgcmExpInfo[
'TELROT'][:] = visitCat[
'telrot']
388 fgcmExpInfo[
'PMB'][:] = visitCat[
'pmb']
389 fgcmExpInfo[
'PSFSIGMA'][:] = visitCat[
'psfSigma']
390 fgcmExpInfo[
'DELTA_APER'][:] = visitCat[
'deltaAper']
391 fgcmExpInfo[
'SKYBACKGROUND'][:] = visitCat[
'skyBackground']
394 fgcmExpInfo[
'FILTERNAME'][:] = visitCat.asAstropy()[
'physicalFilter']
401 Compute the CCD offsets in ra/dec and x/y space
405 camera: `lsst.afw.cameraGeom.Camera`
406 defaultOrientation: `float`
407 Default camera orientation (degrees)
411 ccdOffsets: `numpy.ndarray`
412 Numpy array with ccd offset information for input to FGCM.
413 Angular units are degrees, and x/y units are pixels.
418 ccdOffsets = np.zeros(len(camera), dtype=[(
'CCDNUM',
'i4'),
433 if camera.getName() ==
'HSC' and np.isnan(defaultOrientation):
434 orientation = 270*geom.degrees
436 orientation = defaultOrientation*geom.degrees
441 boresightRotAngle=orientation,
442 rotType=afwImage.RotType.SKY)
444 for i, detector
in enumerate(camera):
445 ccdOffsets[
'CCDNUM'][i] = detector.getId()
447 wcs = createInitialSkyWcs(visitInfo, detector, flipX)
449 detCenter = wcs.pixelToSky(detector.getCenter(afwCameraGeom.PIXELS))
450 ccdOffsets[
'DELTA_RA'][i] = (detCenter.getRa() - boresight.getRa()).asDegrees()
451 ccdOffsets[
'DELTA_DEC'][i] = (detCenter.getDec() - boresight.getDec()).asDegrees()
453 bbox = detector.getBBox()
455 detCorner1 = wcs.pixelToSky(
geom.Point2D(bbox.getMin()))
456 detCorner2 = wcs.pixelToSky(
geom.Point2D(bbox.getMax()))
458 ccdOffsets[
'RA_SIZE'][i] = np.abs((detCorner2.getRa() - detCorner1.getRa()).asDegrees())
459 ccdOffsets[
'DEC_SIZE'][i] = np.abs((detCorner2.getDec() - detCorner1.getDec()).asDegrees())
461 ccdOffsets[
'X_SIZE'][i] = bbox.getMaxX()
462 ccdOffsets[
'Y_SIZE'][i] = bbox.getMaxY()
469 Compute the median pixel scale in the camera
474 Average pixel scale (arcsecond) over the camera
478 orientation = 0.0*geom.degrees
483 boresightRotAngle=orientation,
484 rotType=afwImage.RotType.SKY)
486 pixelScales = np.zeros(len(camera))
487 for i, detector
in enumerate(camera):
488 wcs = createInitialSkyWcs(visitInfo, detector, flipX)
489 pixelScales[i] = wcs.getPixelScale().asArcseconds()
491 ok, = np.where(pixelScales > 0.0)
492 return np.median(pixelScales[ok])
497 Compute the approximate pixel area bounded fields from the camera
502 camera: `lsst.afw.cameraGeom.Camera`
506 approxPixelAreaFields: `dict`
507 Dictionary of approximate area fields, keyed with detector ID
520 boresightRotAngle=0.0*geom.degrees,
521 rotType=afwImage.RotType.SKY)
523 approxPixelAreaFields = {}
525 for i, detector
in enumerate(camera):
526 key = detector.getId()
528 wcs = createInitialSkyWcs(visitInfo, detector, flipX)
529 bbox = detector.getBBox()
532 unit=geom.arcseconds, scaling=areaScaling)
533 approxAreaField = afwMath.ChebyshevBoundedField.approximate(areaField)
535 approxPixelAreaFields[key] = approxAreaField
537 return approxPixelAreaFields
542 Make the zeropoint schema
546 superStarChebyshevSize: `int`
547 Length of the superstar chebyshev array
548 zptChebyshevSize: `int`
549 Length of the zeropoint chebyshev array
553 zptSchema: `lsst.afw.table.schema`
558 zptSchema.addField(
'visit', type=np.int32, doc=
'Visit number')
559 zptSchema.addField(
'detector', type=np.int32, doc=
'Detector ID number')
560 zptSchema.addField(
'fgcmFlag', type=np.int32, doc=(
'FGCM flag value: '
561 '1: Photometric, used in fit; '
562 '2: Photometric, not used in fit; '
563 '4: Non-photometric, on partly photometric night; '
564 '8: Non-photometric, on non-photometric night; '
565 '16: No zeropoint could be determined; '
566 '32: Too few stars for reliable gray computation'))
567 zptSchema.addField(
'fgcmZpt', type=np.float64, doc=
'FGCM zeropoint (center of CCD)')
568 zptSchema.addField(
'fgcmZptErr', type=np.float64,
569 doc=
'Error on zeropoint, estimated from repeatability + number of obs')
570 zptSchema.addField(
'fgcmfZptChebXyMax', type=
'ArrayD', size=2,
571 doc=
'maximum x/maximum y to scale to apply chebyshev parameters')
572 zptSchema.addField(
'fgcmfZptCheb', type=
'ArrayD',
573 size=zptChebyshevSize,
574 doc=
'Chebyshev parameters (flattened) for zeropoint')
575 zptSchema.addField(
'fgcmfZptSstarCheb', type=
'ArrayD',
576 size=superStarChebyshevSize,
577 doc=
'Chebyshev parameters (flattened) for superStarFlat')
578 zptSchema.addField(
'fgcmI0', type=np.float64, doc=
'Integral of the passband')
579 zptSchema.addField(
'fgcmI10', type=np.float64, doc=
'Normalized chromatic integral')
580 zptSchema.addField(
'fgcmR0', type=np.float64,
581 doc=
'Retrieved i0 integral, estimated from stars (only for flag 1)')
582 zptSchema.addField(
'fgcmR10', type=np.float64,
583 doc=
'Retrieved i10 integral, estimated from stars (only for flag 1)')
584 zptSchema.addField(
'fgcmGry', type=np.float64,
585 doc=
'Estimated gray extinction relative to atmospheric solution; '
586 'only for fgcmFlag <= 4 (see fgcmFlag) ')
587 zptSchema.addField(
'fgcmDeltaChrom', type=np.float64,
588 doc=
'Mean chromatic correction for stars in this ccd; '
589 'only for fgcmFlag <= 4 (see fgcmFlag)')
590 zptSchema.addField(
'fgcmZptVar', type=np.float64, doc=
'Variance of zeropoint over ccd')
591 zptSchema.addField(
'fgcmTilings', type=np.float64,
592 doc=
'Number of photometric tilings used for solution for ccd')
593 zptSchema.addField(
'fgcmFpGry', type=np.float64,
594 doc=
'Average gray extinction over the full focal plane '
595 '(same for all ccds in a visit)')
596 zptSchema.addField(
'fgcmFpGryBlue', type=np.float64,
597 doc=
'Average gray extinction over the full focal plane '
598 'for 25% bluest stars')
599 zptSchema.addField(
'fgcmFpGryBlueErr', type=np.float64,
600 doc=
'Error on Average gray extinction over the full focal plane '
601 'for 25% bluest stars')
602 zptSchema.addField(
'fgcmFpGryRed', type=np.float64,
603 doc=
'Average gray extinction over the full focal plane '
604 'for 25% reddest stars')
605 zptSchema.addField(
'fgcmFpGryRedErr', type=np.float64,
606 doc=
'Error on Average gray extinction over the full focal plane '
607 'for 25% reddest stars')
608 zptSchema.addField(
'fgcmFpVar', type=np.float64,
609 doc=
'Variance of gray extinction over the full focal plane '
610 '(same for all ccds in a visit)')
611 zptSchema.addField(
'fgcmDust', type=np.float64,
612 doc=
'Gray dust extinction from the primary/corrector'
613 'at the time of the exposure')
614 zptSchema.addField(
'fgcmFlat', type=np.float64, doc=
'Superstarflat illumination correction')
615 zptSchema.addField(
'fgcmAperCorr', type=np.float64, doc=
'Aperture correction estimated by fgcm')
616 zptSchema.addField(
'fgcmDeltaMagBkg', type=np.float64,
617 doc=(
'Local background correction from brightest percentile '
618 '(value set by deltaMagBkgOffsetPercentile) calibration '
620 zptSchema.addField(
'exptime', type=np.float32, doc=
'Exposure time')
621 zptSchema.addField(
'filtername', type=str, size=10, doc=
'Filter name')
628 Make the zeropoint catalog for persistence
632 zptSchema: `lsst.afw.table.Schema`
633 Zeropoint catalog schema
634 zpStruct: `numpy.ndarray`
635 Zeropoint structure from fgcm
639 zptCat: `afwTable.BaseCatalog`
640 Zeropoint catalog for persistence
644 zptCat.reserve(zpStruct.size)
646 for filterName
in zpStruct[
'FILTERNAME']:
647 rec = zptCat.addNew()
648 rec[
'filtername'] = filterName.decode(
'utf-8')
650 zptCat[
'visit'][:] = zpStruct[FGCM_EXP_FIELD]
651 zptCat[
'detector'][:] = zpStruct[FGCM_CCD_FIELD]
652 zptCat[
'fgcmFlag'][:] = zpStruct[
'FGCM_FLAG']
653 zptCat[
'fgcmZpt'][:] = zpStruct[
'FGCM_ZPT']
654 zptCat[
'fgcmZptErr'][:] = zpStruct[
'FGCM_ZPTERR']
655 zptCat[
'fgcmfZptChebXyMax'][:, :] = zpStruct[
'FGCM_FZPT_XYMAX']
656 zptCat[
'fgcmfZptCheb'][:, :] = zpStruct[
'FGCM_FZPT_CHEB']
657 zptCat[
'fgcmfZptSstarCheb'][:, :] = zpStruct[
'FGCM_FZPT_SSTAR_CHEB']
658 zptCat[
'fgcmI0'][:] = zpStruct[
'FGCM_I0']
659 zptCat[
'fgcmI10'][:] = zpStruct[
'FGCM_I10']
660 zptCat[
'fgcmR0'][:] = zpStruct[
'FGCM_R0']
661 zptCat[
'fgcmR10'][:] = zpStruct[
'FGCM_R10']
662 zptCat[
'fgcmGry'][:] = zpStruct[
'FGCM_GRY']
663 zptCat[
'fgcmDeltaChrom'][:] = zpStruct[
'FGCM_DELTACHROM']
664 zptCat[
'fgcmZptVar'][:] = zpStruct[
'FGCM_ZPTVAR']
665 zptCat[
'fgcmTilings'][:] = zpStruct[
'FGCM_TILINGS']
666 zptCat[
'fgcmFpGry'][:] = zpStruct[
'FGCM_FPGRY']
667 zptCat[
'fgcmFpGryBlue'][:] = zpStruct[
'FGCM_FPGRY_CSPLIT'][:, 0]
668 zptCat[
'fgcmFpGryBlueErr'][:] = zpStruct[
'FGCM_FPGRY_CSPLITERR'][:, 0]
669 zptCat[
'fgcmFpGryRed'][:] = zpStruct[
'FGCM_FPGRY_CSPLIT'][:, 2]
670 zptCat[
'fgcmFpGryRedErr'][:] = zpStruct[
'FGCM_FPGRY_CSPLITERR'][:, 2]
671 zptCat[
'fgcmFpVar'][:] = zpStruct[
'FGCM_FPVAR']
672 zptCat[
'fgcmDust'][:] = zpStruct[
'FGCM_DUST']
673 zptCat[
'fgcmFlat'][:] = zpStruct[
'FGCM_FLAT']
674 zptCat[
'fgcmAperCorr'][:] = zpStruct[
'FGCM_APERCORR']
675 zptCat[
'fgcmDeltaMagBkg'][:] = zpStruct[
'FGCM_DELTAMAGBKG']
676 zptCat[
'exptime'][:] = zpStruct[
'EXPTIME']
683 Make the atmosphere schema
687 atmSchema: `lsst.afw.table.Schema`
692 atmSchema.addField(
'visit', type=np.int32, doc=
'Visit number')
693 atmSchema.addField(
'pmb', type=np.float64, doc=
'Barometric pressure (mb)')
694 atmSchema.addField(
'pwv', type=np.float64, doc=
'Water vapor (mm)')
695 atmSchema.addField(
'tau', type=np.float64, doc=
'Aerosol optical depth')
696 atmSchema.addField(
'alpha', type=np.float64, doc=
'Aerosol slope')
697 atmSchema.addField(
'o3', type=np.float64, doc=
'Ozone (dobson)')
698 atmSchema.addField(
'secZenith', type=np.float64, doc=
'Secant(zenith) (~ airmass)')
699 atmSchema.addField(
'cTrans', type=np.float64, doc=
'Transmission correction factor')
700 atmSchema.addField(
'lamStd', type=np.float64, doc=
'Wavelength for transmission correction')
707 Make the atmosphere catalog for persistence
711 atmSchema: `lsst.afw.table.Schema`
712 Atmosphere catalog schema
713 atmStruct: `numpy.ndarray`
714 Atmosphere structure from fgcm
718 atmCat: `lsst.afw.table.BaseCatalog`
719 Atmosphere catalog for persistence
723 atmCat.resize(atmStruct.size)
725 atmCat[
'visit'][:] = atmStruct[
'VISIT']
726 atmCat[
'pmb'][:] = atmStruct[
'PMB']
727 atmCat[
'pwv'][:] = atmStruct[
'PWV']
728 atmCat[
'tau'][:] = atmStruct[
'TAU']
729 atmCat[
'alpha'][:] = atmStruct[
'ALPHA']
730 atmCat[
'o3'][:] = atmStruct[
'O3']
731 atmCat[
'secZenith'][:] = atmStruct[
'SECZENITH']
732 atmCat[
'cTrans'][:] = atmStruct[
'CTRANS']
733 atmCat[
'lamStd'][:] = atmStruct[
'LAMSTD']
740 Make the standard star schema
745 Number of bands in standard star catalog
749 stdSchema: `lsst.afw.table.Schema`
752 stdSchema = afwTable.SimpleTable.makeMinimalSchema()
753 stdSchema.addField(
'ngood', type=
'ArrayI', doc=
'Number of good observations',
755 stdSchema.addField(
'ntotal', type=
'ArrayI', doc=
'Number of total observations',
757 stdSchema.addField(
'mag_std_noabs', type=
'ArrayF',
758 doc=
'Standard magnitude (no absolute calibration)',
760 stdSchema.addField(
'magErr_std', type=
'ArrayF',
761 doc=
'Standard magnitude error',
763 stdSchema.addField(
'npsfcand', type=
'ArrayI',
764 doc=
'Number of observations flagged as psf candidates',
772 Make the standard star catalog for persistence
776 stdSchema: `lsst.afw.table.Schema`
777 Standard star catalog schema
778 stdStruct: `numpy.ndarray`
779 Standard star structure in FGCM format
781 List of good band names used in stdStruct
785 stdCat: `lsst.afw.table.BaseCatalog`
786 Standard star catalog for persistence
790 stdCat.resize(stdStruct.size)
792 stdCat[
'id'][:] = stdStruct[
'FGCM_ID']
793 stdCat[
'coord_ra'][:] = stdStruct[
'RA'] * geom.degrees
794 stdCat[
'coord_dec'][:] = stdStruct[
'DEC'] * geom.degrees
795 stdCat[
'ngood'][:, :] = stdStruct[
'NGOOD'][:, :]
796 stdCat[
'ntotal'][:, :] = stdStruct[
'NTOTAL'][:, :]
797 stdCat[
'mag_std_noabs'][:, :] = stdStruct[
'MAG_STD'][:, :]
798 stdCat[
'magErr_std'][:, :] = stdStruct[
'MAGERR_STD'][:, :]
799 stdCat[
'npsfcand'][:, :] = stdStruct[
'NPSFCAND'][:, :]
802 md.set(
"BANDS",
list(goodBands))
803 stdCat.setMetadata(md)
810 Compute the radius associated with a CircularApertureFlux field or
815 dataRef : `lsst.daf.persistence.ButlerDataRef` or
816 `lsst.daf.butler.DeferredDatasetHandle`
818 CircularApertureFlux or associated slot.
822 apertureRadius : `float`
823 Radius of the aperture field, in pixels.
827 RuntimeError: Raised if flux field is not a CircularApertureFlux, ApFlux,
828 apFlux, or associated slot.
833 datasetType = dataRef.butlerSubset.datasetType
836 datasetType = dataRef.ref.datasetType.name
838 if datasetType ==
'src':
839 schema = dataRef.get(datasetType=
'src_schema').schema
841 fluxFieldName = schema[fluxField].asField().
getName()
843 raise RuntimeError(
"Could not find %s or associated slot in schema." % (fluxField))
850 return apertureRadius
855 Compute the radius associated with a CircularApertureFlux or ApFlux field.
860 CircularApertureFlux or ApFlux
864 apertureRadius : `float`
865 Radius of the aperture field, in pixels.
869 RuntimeError: Raised if flux field is not a CircularApertureFlux,
873 m = re.search(
r'(CircularApertureFlux|ApFlux|apFlux)_(\d+)_(\d+)_', fluxField)
876 raise RuntimeError(f
"Flux field {fluxField} does not correspond to a CircularApertureFlux or ApFlux")
878 apertureRadius = float(m.groups()[1]) + float(m.groups()[2])/10.
880 return apertureRadius
885 Extract reference magnitudes from refStars for given bands and
886 associated filterMap.
890 refStars : `lsst.afw.table.BaseCatalog`
891 FGCM reference star catalog
893 List of bands for calibration
895 FGCM mapping of filter to band
899 refMag : `np.ndarray`
900 nstar x nband array of reference magnitudes
901 refMagErr : `np.ndarray`
902 nstar x nband array of reference magnitude errors
908 md = refStars.getMetadata()
909 if 'FILTERNAMES' in md:
910 filternames = md.getArray(
'FILTERNAMES')
914 refMag = np.zeros((len(refStars), len(bands)),
915 dtype=refStars[
'refMag'].dtype) + 99.0
916 refMagErr = np.zeros_like(refMag) + 99.0
917 for i, filtername
in enumerate(filternames):
921 band = filterMap[filtername]
925 ind = bands.index(band)
929 refMag[:, ind] = refStars[
'refMag'][:, i]
930 refMagErr[:, ind] = refStars[
'refMagErr'][:, i]
934 refMag = refStars[
'refMag'][:, :]
935 refMagErr = refStars[
'refMagErr'][:, :]
937 return refMag, refMagErr
941 instrument = Instrument.fromName(quantumDataId[
"instrument"], registry)
942 unboundedCollection = instrument.makeUnboundedCalibrationRunName()
944 return registry.queryDatasets(datasetType,
945 dataId=quantumDataId,
946 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)