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.
31 from lsst.daf.base
import PropertyList
32 import lsst.daf.persistence
as dafPersist
33 import lsst.afw.cameraGeom
as afwCameraGeom
34 import lsst.afw.table
as afwTable
35 import lsst.afw.image
as afwImage
36 import lsst.afw.math
as afwMath
37 import lsst.geom
as geom
38 from lsst.obs.base
import createInitialSkyWcs
39 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,
206 'outputPath': os.path.abspath(
'.'),
209 'resetParameters': resetFitParameters,
210 'doPlots': config.doPlots,
211 'outputFgcmcalZpts':
True,
212 'outputZeropoints': outputZeropoints}
219 Translate the FGCM look-up-table into an fgcm-compatible object
223 lutCat: `lsst.afw.table.BaseCatalog`
224 Catalog describing the FGCM look-up table
225 physicalFilterMap: `dict`
226 Physical filter to band mapping
230 fgcmLut: `lsst.fgcm.FgcmLut`
231 Lookup table for FGCM
232 lutIndexVals: `numpy.ndarray`
233 Numpy array with LUT index information for FGCM
234 lutStd: `numpy.ndarray`
235 Numpy array with LUT standard throughput values for FGCM
239 After running this code, it is wise to `del lutCat` to clear the memory.
243 lutFilterNames = np.array(lutCat[0][
'physicalFilters'].split(
','), dtype=
'U')
244 lutStdFilterNames = np.array(lutCat[0][
'stdPhysicalFilters'].split(
','), dtype=
'U')
249 lutIndexVals = np.zeros(1, dtype=[(
'FILTERNAMES', lutFilterNames.dtype.str,
250 lutFilterNames.size),
251 (
'STDFILTERNAMES', lutStdFilterNames.dtype.str,
252 lutStdFilterNames.size),
253 (
'PMB',
'f8', lutCat[0][
'pmb'].size),
254 (
'PMBFACTOR',
'f8', lutCat[0][
'pmbFactor'].size),
255 (
'PMBELEVATION',
'f8'),
256 (
'LAMBDANORM',
'f8'),
257 (
'PWV',
'f8', lutCat[0][
'pwv'].size),
258 (
'O3',
'f8', lutCat[0][
'o3'].size),
259 (
'TAU',
'f8', lutCat[0][
'tau'].size),
260 (
'ALPHA',
'f8', lutCat[0][
'alpha'].size),
261 (
'ZENITH',
'f8', lutCat[0][
'zenith'].size),
264 lutIndexVals[
'FILTERNAMES'][:] = lutFilterNames
265 lutIndexVals[
'STDFILTERNAMES'][:] = lutStdFilterNames
266 lutIndexVals[
'PMB'][:] = lutCat[0][
'pmb']
267 lutIndexVals[
'PMBFACTOR'][:] = lutCat[0][
'pmbFactor']
268 lutIndexVals[
'PMBELEVATION'] = lutCat[0][
'pmbElevation']
269 lutIndexVals[
'LAMBDANORM'] = lutCat[0][
'lambdaNorm']
270 lutIndexVals[
'PWV'][:] = lutCat[0][
'pwv']
271 lutIndexVals[
'O3'][:] = lutCat[0][
'o3']
272 lutIndexVals[
'TAU'][:] = lutCat[0][
'tau']
273 lutIndexVals[
'ALPHA'][:] = lutCat[0][
'alpha']
274 lutIndexVals[
'ZENITH'][:] = lutCat[0][
'zenith']
275 lutIndexVals[
'NCCD'] = lutCat[0][
'nCcd']
278 lutStd = np.zeros(1, dtype=[(
'PMBSTD',
'f8'),
284 (
'LAMBDARANGE',
'f8', 2),
285 (
'LAMBDASTEP',
'f8'),
286 (
'LAMBDASTD',
'f8', lutFilterNames.size),
287 (
'LAMBDASTDFILTER',
'f8', lutStdFilterNames.size),
288 (
'I0STD',
'f8', lutFilterNames.size),
289 (
'I1STD',
'f8', lutFilterNames.size),
290 (
'I10STD',
'f8', lutFilterNames.size),
291 (
'I2STD',
'f8', lutFilterNames.size),
292 (
'LAMBDAB',
'f8', lutFilterNames.size),
293 (
'ATMLAMBDA',
'f8', lutCat[0][
'atmLambda'].size),
294 (
'ATMSTDTRANS',
'f8', lutCat[0][
'atmStdTrans'].size)])
295 lutStd[
'PMBSTD'] = lutCat[0][
'pmbStd']
296 lutStd[
'PWVSTD'] = lutCat[0][
'pwvStd']
297 lutStd[
'O3STD'] = lutCat[0][
'o3Std']
298 lutStd[
'TAUSTD'] = lutCat[0][
'tauStd']
299 lutStd[
'ALPHASTD'] = lutCat[0][
'alphaStd']
300 lutStd[
'ZENITHSTD'] = lutCat[0][
'zenithStd']
301 lutStd[
'LAMBDARANGE'][:] = lutCat[0][
'lambdaRange'][:]
302 lutStd[
'LAMBDASTEP'] = lutCat[0][
'lambdaStep']
303 lutStd[
'LAMBDASTD'][:] = lutCat[0][
'lambdaStd']
304 lutStd[
'LAMBDASTDFILTER'][:] = lutCat[0][
'lambdaStdFilter']
305 lutStd[
'I0STD'][:] = lutCat[0][
'i0Std']
306 lutStd[
'I1STD'][:] = lutCat[0][
'i1Std']
307 lutStd[
'I10STD'][:] = lutCat[0][
'i10Std']
308 lutStd[
'I2STD'][:] = lutCat[0][
'i2Std']
309 lutStd[
'LAMBDAB'][:] = lutCat[0][
'lambdaB']
310 lutStd[
'ATMLAMBDA'][:] = lutCat[0][
'atmLambda'][:]
311 lutStd[
'ATMSTDTRANS'][:] = lutCat[0][
'atmStdTrans'][:]
313 lutTypes = [row[
'luttype']
for row
in lutCat]
316 lutFlat = np.zeros(lutCat[0][
'lut'].size, dtype=[(
'I0',
'f4'),
319 lutFlat[
'I0'][:] = lutCat[lutTypes.index(
'I0')][
'lut'][:]
320 lutFlat[
'I1'][:] = lutCat[lutTypes.index(
'I1')][
'lut'][:]
322 lutDerivFlat = np.zeros(lutCat[0][
'lut'].size, dtype=[(
'D_LNPWV',
'f4'),
326 (
'D_SECZENITH',
'f4'),
327 (
'D_LNPWV_I1',
'f4'),
329 (
'D_LNTAU_I1',
'f4'),
330 (
'D_ALPHA_I1',
'f4'),
331 (
'D_SECZENITH_I1',
'f4')])
333 for name
in lutDerivFlat.dtype.names:
334 lutDerivFlat[name][:] = lutCat[lutTypes.index(name)][
'lut'][:]
341 fgcmLut = fgcm.FgcmLUT(lutIndexVals, lutFlat, lutDerivFlat, lutStd,
342 filterToBand=physicalFilterMap)
344 return fgcmLut, lutIndexVals, lutStd
349 Translate the FGCM visit catalog to an fgcm-compatible object
353 visitCat: `lsst.afw.table.BaseCatalog`
354 FGCM visitCat from `lsst.fgcmcal.FgcmBuildStarsTask`
358 fgcmExpInfo: `numpy.ndarray`
359 Numpy array for visit information for FGCM
363 After running this code, it is wise to `del visitCat` to clear the memory.
366 fgcmExpInfo = np.zeros(len(visitCat), dtype=[(
'VISIT',
'i8'),
370 (
'DELTA_APER',
'f8'),
371 (
'SKYBACKGROUND',
'f8'),
378 (
'FILTERNAME',
'a50')])
379 fgcmExpInfo[
'VISIT'][:] = visitCat[
'visit']
380 fgcmExpInfo[
'MJD'][:] = visitCat[
'mjd']
381 fgcmExpInfo[
'EXPTIME'][:] = visitCat[
'exptime']
382 fgcmExpInfo[
'DEEPFLAG'][:] = visitCat[
'deepFlag']
383 fgcmExpInfo[
'TELHA'][:] = visitCat[
'telha']
384 fgcmExpInfo[
'TELRA'][:] = visitCat[
'telra']
385 fgcmExpInfo[
'TELDEC'][:] = visitCat[
'teldec']
386 fgcmExpInfo[
'TELROT'][:] = visitCat[
'telrot']
387 fgcmExpInfo[
'PMB'][:] = visitCat[
'pmb']
388 fgcmExpInfo[
'PSFSIGMA'][:] = visitCat[
'psfSigma']
389 fgcmExpInfo[
'DELTA_APER'][:] = visitCat[
'deltaAper']
390 fgcmExpInfo[
'SKYBACKGROUND'][:] = visitCat[
'skyBackground']
393 fgcmExpInfo[
'FILTERNAME'][:] = visitCat.asAstropy()[
'physicalFilter']
400 Compute the CCD offsets in ra/dec and x/y space
404 camera: `lsst.afw.cameraGeom.Camera`
405 defaultOrientation: `float`
406 Default camera orientation (degrees)
410 ccdOffsets: `numpy.ndarray`
411 Numpy array with ccd offset information for input to FGCM.
412 Angular units are degrees, and x/y units are pixels.
417 ccdOffsets = np.zeros(len(camera), dtype=[(
'CCDNUM',
'i4'),
427 boresight = geom.SpherePoint(180.0*geom.degrees, 0.0*geom.degrees)
432 if camera.getName() ==
'HSC' and np.isnan(defaultOrientation):
433 orientation = 270*geom.degrees
435 orientation = defaultOrientation*geom.degrees
439 visitInfo = afwImage.VisitInfo(boresightRaDec=boresight,
440 boresightRotAngle=orientation,
441 rotType=afwImage.RotType.SKY)
443 for i, detector
in enumerate(camera):
444 ccdOffsets[
'CCDNUM'][i] = detector.getId()
446 wcs = createInitialSkyWcs(visitInfo, detector, flipX)
448 detCenter = wcs.pixelToSky(detector.getCenter(afwCameraGeom.PIXELS))
449 ccdOffsets[
'DELTA_RA'][i] = (detCenter.getRa() - boresight.getRa()).asDegrees()
450 ccdOffsets[
'DELTA_DEC'][i] = (detCenter.getDec() - boresight.getDec()).asDegrees()
452 bbox = detector.getBBox()
454 detCorner1 = wcs.pixelToSky(geom.Point2D(bbox.getMin()))
455 detCorner2 = wcs.pixelToSky(geom.Point2D(bbox.getMax()))
457 ccdOffsets[
'RA_SIZE'][i] = np.abs((detCorner2.getRa() - detCorner1.getRa()).asDegrees())
458 ccdOffsets[
'DEC_SIZE'][i] = np.abs((detCorner2.getDec() - detCorner1.getDec()).asDegrees())
460 ccdOffsets[
'X_SIZE'][i] = bbox.getMaxX()
461 ccdOffsets[
'Y_SIZE'][i] = bbox.getMaxY()
468 Compute the median pixel scale in the camera
473 Average pixel scale (arcsecond) over the camera
476 boresight = geom.SpherePoint(180.0*geom.degrees, 0.0*geom.degrees)
477 orientation = 0.0*geom.degrees
481 visitInfo = afwImage.VisitInfo(boresightRaDec=boresight,
482 boresightRotAngle=orientation,
483 rotType=afwImage.RotType.SKY)
485 pixelScales = np.zeros(len(camera))
486 for i, detector
in enumerate(camera):
487 wcs = createInitialSkyWcs(visitInfo, detector, flipX)
488 pixelScales[i] = wcs.getPixelScale().asArcseconds()
490 ok, = np.where(pixelScales > 0.0)
491 return np.median(pixelScales[ok])
496 Compute the approximate pixel area bounded fields from the camera
501 camera: `lsst.afw.cameraGeom.Camera`
505 approxPixelAreaFields: `dict`
506 Dictionary of approximate area fields, keyed with detector ID
513 boresight = geom.SpherePoint(180.0*geom.degrees, 0.0*geom.degrees)
518 visitInfo = afwImage.VisitInfo(boresightRaDec=boresight,
519 boresightRotAngle=0.0*geom.degrees,
520 rotType=afwImage.RotType.SKY)
522 approxPixelAreaFields = {}
524 for i, detector
in enumerate(camera):
525 key = detector.getId()
527 wcs = createInitialSkyWcs(visitInfo, detector, flipX)
528 bbox = detector.getBBox()
530 areaField = afwMath.PixelAreaBoundedField(bbox, wcs,
531 unit=geom.arcseconds, scaling=areaScaling)
532 approxAreaField = afwMath.ChebyshevBoundedField.approximate(areaField)
534 approxPixelAreaFields[key] = approxAreaField
536 return approxPixelAreaFields
541 Make the zeropoint schema
545 superStarChebyshevSize: `int`
546 Length of the superstar chebyshev array
547 zptChebyshevSize: `int`
548 Length of the zeropoint chebyshev array
552 zptSchema: `lsst.afw.table.schema`
555 zptSchema = afwTable.Schema()
557 zptSchema.addField(
'visit', type=np.int32, doc=
'Visit number')
558 zptSchema.addField(
'detector', type=np.int32, doc=
'Detector ID number')
559 zptSchema.addField(
'fgcmFlag', type=np.int32, doc=(
'FGCM flag value: '
560 '1: Photometric, used in fit; '
561 '2: Photometric, not used in fit; '
562 '4: Non-photometric, on partly photometric night; '
563 '8: Non-photometric, on non-photometric night; '
564 '16: No zeropoint could be determined; '
565 '32: Too few stars for reliable gray computation'))
566 zptSchema.addField(
'fgcmZpt', type=np.float64, doc=
'FGCM zeropoint (center of CCD)')
567 zptSchema.addField(
'fgcmZptErr', type=np.float64,
568 doc=
'Error on zeropoint, estimated from repeatability + number of obs')
569 zptSchema.addField(
'fgcmfZptChebXyMax', type=
'ArrayD', size=2,
570 doc=
'maximum x/maximum y to scale to apply chebyshev parameters')
571 zptSchema.addField(
'fgcmfZptCheb', type=
'ArrayD',
572 size=zptChebyshevSize,
573 doc=
'Chebyshev parameters (flattened) for zeropoint')
574 zptSchema.addField(
'fgcmfZptSstarCheb', type=
'ArrayD',
575 size=superStarChebyshevSize,
576 doc=
'Chebyshev parameters (flattened) for superStarFlat')
577 zptSchema.addField(
'fgcmI0', type=np.float64, doc=
'Integral of the passband')
578 zptSchema.addField(
'fgcmI10', type=np.float64, doc=
'Normalized chromatic integral')
579 zptSchema.addField(
'fgcmR0', type=np.float64,
580 doc=
'Retrieved i0 integral, estimated from stars (only for flag 1)')
581 zptSchema.addField(
'fgcmR10', type=np.float64,
582 doc=
'Retrieved i10 integral, estimated from stars (only for flag 1)')
583 zptSchema.addField(
'fgcmGry', type=np.float64,
584 doc=
'Estimated gray extinction relative to atmospheric solution; '
585 'only for fgcmFlag <= 4 (see fgcmFlag) ')
586 zptSchema.addField(
'fgcmDeltaChrom', type=np.float64,
587 doc=
'Mean chromatic correction for stars in this ccd; '
588 'only for fgcmFlag <= 4 (see fgcmFlag)')
589 zptSchema.addField(
'fgcmZptVar', type=np.float64, doc=
'Variance of zeropoint over ccd')
590 zptSchema.addField(
'fgcmTilings', type=np.float64,
591 doc=
'Number of photometric tilings used for solution for ccd')
592 zptSchema.addField(
'fgcmFpGry', type=np.float64,
593 doc=
'Average gray extinction over the full focal plane '
594 '(same for all ccds in a visit)')
595 zptSchema.addField(
'fgcmFpGryBlue', type=np.float64,
596 doc=
'Average gray extinction over the full focal plane '
597 'for 25% bluest stars')
598 zptSchema.addField(
'fgcmFpGryBlueErr', type=np.float64,
599 doc=
'Error on Average gray extinction over the full focal plane '
600 'for 25% bluest stars')
601 zptSchema.addField(
'fgcmFpGryRed', type=np.float64,
602 doc=
'Average gray extinction over the full focal plane '
603 'for 25% reddest stars')
604 zptSchema.addField(
'fgcmFpGryRedErr', type=np.float64,
605 doc=
'Error on Average gray extinction over the full focal plane '
606 'for 25% reddest stars')
607 zptSchema.addField(
'fgcmFpVar', type=np.float64,
608 doc=
'Variance of gray extinction over the full focal plane '
609 '(same for all ccds in a visit)')
610 zptSchema.addField(
'fgcmDust', type=np.float64,
611 doc=
'Gray dust extinction from the primary/corrector'
612 'at the time of the exposure')
613 zptSchema.addField(
'fgcmFlat', type=np.float64, doc=
'Superstarflat illumination correction')
614 zptSchema.addField(
'fgcmAperCorr', type=np.float64, doc=
'Aperture correction estimated by fgcm')
615 zptSchema.addField(
'fgcmDeltaMagBkg', type=np.float64,
616 doc=(
'Local background correction from brightest percentile '
617 '(value set by deltaMagBkgOffsetPercentile) calibration '
619 zptSchema.addField(
'exptime', type=np.float32, doc=
'Exposure time')
620 zptSchema.addField(
'filtername', type=str, size=10, doc=
'Filter name')
627 Make the zeropoint catalog for persistence
631 zptSchema: `lsst.afw.table.Schema`
632 Zeropoint catalog schema
633 zpStruct: `numpy.ndarray`
634 Zeropoint structure from fgcm
638 zptCat: `afwTable.BaseCatalog`
639 Zeropoint catalog for persistence
642 zptCat = afwTable.BaseCatalog(zptSchema)
643 zptCat.reserve(zpStruct.size)
645 for filterName
in zpStruct[
'FILTERNAME']:
646 rec = zptCat.addNew()
647 rec[
'filtername'] = filterName.decode(
'utf-8')
649 zptCat[
'visit'][:] = zpStruct[FGCM_EXP_FIELD]
650 zptCat[
'detector'][:] = zpStruct[FGCM_CCD_FIELD]
651 zptCat[
'fgcmFlag'][:] = zpStruct[
'FGCM_FLAG']
652 zptCat[
'fgcmZpt'][:] = zpStruct[
'FGCM_ZPT']
653 zptCat[
'fgcmZptErr'][:] = zpStruct[
'FGCM_ZPTERR']
654 zptCat[
'fgcmfZptChebXyMax'][:, :] = zpStruct[
'FGCM_FZPT_XYMAX']
655 zptCat[
'fgcmfZptCheb'][:, :] = zpStruct[
'FGCM_FZPT_CHEB']
656 zptCat[
'fgcmfZptSstarCheb'][:, :] = zpStruct[
'FGCM_FZPT_SSTAR_CHEB']
657 zptCat[
'fgcmI0'][:] = zpStruct[
'FGCM_I0']
658 zptCat[
'fgcmI10'][:] = zpStruct[
'FGCM_I10']
659 zptCat[
'fgcmR0'][:] = zpStruct[
'FGCM_R0']
660 zptCat[
'fgcmR10'][:] = zpStruct[
'FGCM_R10']
661 zptCat[
'fgcmGry'][:] = zpStruct[
'FGCM_GRY']
662 zptCat[
'fgcmDeltaChrom'][:] = zpStruct[
'FGCM_DELTACHROM']
663 zptCat[
'fgcmZptVar'][:] = zpStruct[
'FGCM_ZPTVAR']
664 zptCat[
'fgcmTilings'][:] = zpStruct[
'FGCM_TILINGS']
665 zptCat[
'fgcmFpGry'][:] = zpStruct[
'FGCM_FPGRY']
666 zptCat[
'fgcmFpGryBlue'][:] = zpStruct[
'FGCM_FPGRY_CSPLIT'][:, 0]
667 zptCat[
'fgcmFpGryBlueErr'][:] = zpStruct[
'FGCM_FPGRY_CSPLITERR'][:, 0]
668 zptCat[
'fgcmFpGryRed'][:] = zpStruct[
'FGCM_FPGRY_CSPLIT'][:, 2]
669 zptCat[
'fgcmFpGryRedErr'][:] = zpStruct[
'FGCM_FPGRY_CSPLITERR'][:, 2]
670 zptCat[
'fgcmFpVar'][:] = zpStruct[
'FGCM_FPVAR']
671 zptCat[
'fgcmDust'][:] = zpStruct[
'FGCM_DUST']
672 zptCat[
'fgcmFlat'][:] = zpStruct[
'FGCM_FLAT']
673 zptCat[
'fgcmAperCorr'][:] = zpStruct[
'FGCM_APERCORR']
674 zptCat[
'fgcmDeltaMagBkg'][:] = zpStruct[
'FGCM_DELTAMAGBKG']
675 zptCat[
'exptime'][:] = zpStruct[
'EXPTIME']
682 Make the atmosphere schema
686 atmSchema: `lsst.afw.table.Schema`
689 atmSchema = afwTable.Schema()
691 atmSchema.addField(
'visit', type=np.int32, doc=
'Visit number')
692 atmSchema.addField(
'pmb', type=np.float64, doc=
'Barometric pressure (mb)')
693 atmSchema.addField(
'pwv', type=np.float64, doc=
'Water vapor (mm)')
694 atmSchema.addField(
'tau', type=np.float64, doc=
'Aerosol optical depth')
695 atmSchema.addField(
'alpha', type=np.float64, doc=
'Aerosol slope')
696 atmSchema.addField(
'o3', type=np.float64, doc=
'Ozone (dobson)')
697 atmSchema.addField(
'secZenith', type=np.float64, doc=
'Secant(zenith) (~ airmass)')
698 atmSchema.addField(
'cTrans', type=np.float64, doc=
'Transmission correction factor')
699 atmSchema.addField(
'lamStd', type=np.float64, doc=
'Wavelength for transmission correction')
706 Make the atmosphere catalog for persistence
710 atmSchema: `lsst.afw.table.Schema`
711 Atmosphere catalog schema
712 atmStruct: `numpy.ndarray`
713 Atmosphere structure from fgcm
717 atmCat: `lsst.afw.table.BaseCatalog`
718 Atmosphere catalog for persistence
721 atmCat = afwTable.BaseCatalog(atmSchema)
722 atmCat.resize(atmStruct.size)
724 atmCat[
'visit'][:] = atmStruct[
'VISIT']
725 atmCat[
'pmb'][:] = atmStruct[
'PMB']
726 atmCat[
'pwv'][:] = atmStruct[
'PWV']
727 atmCat[
'tau'][:] = atmStruct[
'TAU']
728 atmCat[
'alpha'][:] = atmStruct[
'ALPHA']
729 atmCat[
'o3'][:] = atmStruct[
'O3']
730 atmCat[
'secZenith'][:] = atmStruct[
'SECZENITH']
731 atmCat[
'cTrans'][:] = atmStruct[
'CTRANS']
732 atmCat[
'lamStd'][:] = atmStruct[
'LAMSTD']
739 Make the standard star schema
744 Number of bands in standard star catalog
748 stdSchema: `lsst.afw.table.Schema`
751 stdSchema = afwTable.SimpleTable.makeMinimalSchema()
752 stdSchema.addField(
'ngood', type=
'ArrayI', doc=
'Number of good observations',
754 stdSchema.addField(
'ntotal', type=
'ArrayI', doc=
'Number of total observations',
756 stdSchema.addField(
'mag_std_noabs', type=
'ArrayF',
757 doc=
'Standard magnitude (no absolute calibration)',
759 stdSchema.addField(
'magErr_std', type=
'ArrayF',
760 doc=
'Standard magnitude error',
762 stdSchema.addField(
'npsfcand', type=
'ArrayI',
763 doc=
'Number of observations flagged as psf candidates',
771 Make the standard star catalog for persistence
775 stdSchema: `lsst.afw.table.Schema`
776 Standard star catalog schema
777 stdStruct: `numpy.ndarray`
778 Standard star structure in FGCM format
780 List of good band names used in stdStruct
784 stdCat: `lsst.afw.table.BaseCatalog`
785 Standard star catalog for persistence
788 stdCat = afwTable.SimpleCatalog(stdSchema)
789 stdCat.resize(stdStruct.size)
791 stdCat[
'id'][:] = stdStruct[
'FGCM_ID']
792 stdCat[
'coord_ra'][:] = stdStruct[
'RA'] * geom.degrees
793 stdCat[
'coord_dec'][:] = stdStruct[
'DEC'] * geom.degrees
794 stdCat[
'ngood'][:, :] = stdStruct[
'NGOOD'][:, :]
795 stdCat[
'ntotal'][:, :] = stdStruct[
'NTOTAL'][:, :]
796 stdCat[
'mag_std_noabs'][:, :] = stdStruct[
'MAG_STD'][:, :]
797 stdCat[
'magErr_std'][:, :] = stdStruct[
'MAGERR_STD'][:, :]
798 stdCat[
'npsfcand'][:, :] = stdStruct[
'NPSFCAND'][:, :]
801 md.set(
"BANDS", list(goodBands))
802 stdCat.setMetadata(md)
809 Compute the radius associated with a CircularApertureFlux field or
814 dataRef : `lsst.daf.persistence.ButlerDataRef` or
815 `lsst.daf.butler.DeferredDatasetHandle`
817 CircularApertureFlux or associated slot.
821 apertureRadius : `float`
822 Radius of the aperture field, in pixels.
826 RuntimeError: Raised if flux field is not a CircularApertureFlux, ApFlux,
830 if isinstance(dataRef, dafPersist.ButlerDataRef):
832 datasetType = dataRef.butlerSubset.datasetType
835 datasetType = dataRef.ref.datasetType.name
837 if datasetType ==
'src':
838 schema = dataRef.get(datasetType=
'src_schema').schema
840 fluxFieldName = schema[fluxField].asField().getName()
842 raise RuntimeError(
"Could not find %s or associated slot in schema." % (fluxField))
849 return apertureRadius
854 Compute the radius associated with a CircularApertureFlux or ApFlux field.
859 CircularApertureFlux or ApFlux
863 apertureRadius : `float`
864 Radius of the aperture field, in pixels.
868 RuntimeError: Raised if flux field is not a CircularApertureFlux
872 m = re.search(
r'(CircularApertureFlux|ApFlux)_(\d+)_(\d+)_', fluxField)
875 raise RuntimeError(f
"Flux field {fluxField} does not correspond to a CircularApertureFlux or ApFlux")
877 apertureRadius = float(m.groups()[1]) + float(m.groups()[2])/10.
879 return apertureRadius
884 Extract reference magnitudes from refStars for given bands and
885 associated filterMap.
889 refStars : `lsst.afw.table.BaseCatalog`
890 FGCM reference star catalog
892 List of bands for calibration
894 FGCM mapping of filter to band
898 refMag : `np.ndarray`
899 nstar x nband array of reference magnitudes
900 refMagErr : `np.ndarray`
901 nstar x nband array of reference magnitude errors
907 md = refStars.getMetadata()
908 if 'FILTERNAMES' in md:
909 filternames = md.getArray(
'FILTERNAMES')
913 refMag = np.zeros((len(refStars), len(bands)),
914 dtype=refStars[
'refMag'].dtype) + 99.0
915 refMagErr = np.zeros_like(refMag) + 99.0
916 for i, filtername
in enumerate(filternames):
920 band = filterMap[filtername]
924 ind = bands.index(band)
928 refMag[:, ind] = refStars[
'refMag'][:, i]
929 refMagErr[:, ind] = refStars[
'refMagErr'][:, i]
933 refMag = refStars[
'refMag'][:, :]
934 refMagErr = refStars[
'refMagErr'][:, :]
936 return refMag, refMagErr
940 instrument = Instrument.fromName(quantumDataId[
"instrument"], registry)
941 unboundedCollection = instrument.makeUnboundedCalibrationRunName()
943 return registry.queryDatasets(datasetType,
944 dataId=quantumDataId,
945 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)