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'
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'),
428 boresight = geom.SpherePoint(180.0*geom.degrees, 0.0*geom.degrees)
433 if camera.getName() ==
'HSC' and np.isnan(defaultOrientation):
434 orientation = 270*geom.degrees
436 orientation = defaultOrientation*geom.degrees
440 visitInfo = afwImage.VisitInfo(boresightRaDec=boresight,
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
477 boresight = geom.SpherePoint(180.0*geom.degrees, 0.0*geom.degrees)
478 orientation = 0.0*geom.degrees
482 visitInfo = afwImage.VisitInfo(boresightRaDec=boresight,
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
514 boresight = geom.SpherePoint(180.0*geom.degrees, 0.0*geom.degrees)
519 visitInfo = afwImage.VisitInfo(boresightRaDec=boresight,
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()
531 areaField = afwMath.PixelAreaBoundedField(bbox, wcs,
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`
556 zptSchema = afwTable.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
643 zptCat = afwTable.BaseCatalog(zptSchema)
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`
690 atmSchema = afwTable.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
722 atmCat = afwTable.BaseCatalog(atmSchema)
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
789 stdCat = afwTable.SimpleCatalog(stdSchema)
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,
831 if isinstance(dataRef, dafPersist.ButlerDataRef):
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)_(\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])
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)