21"""Utility functions for fgcmcal.
23This file contains utility functions that are used by more than one task,
24and do not need to be part of a task.
30from deprecated.sphinx
import deprecated
32from lsst.daf.base
import PropertyList
33import lsst.daf.persistence
as dafPersist
34import lsst.afw.cameraGeom
as afwCameraGeom
35import lsst.afw.table
as afwTable
36import lsst.afw.image
as afwImage
37import lsst.afw.math
as afwMath
38import lsst.geom
as geom
39from lsst.obs.base
import createInitialSkyWcs
40from lsst.obs.base
import Instrument
45FGCM_EXP_FIELD =
'VISIT'
46FGCM_CCD_FIELD =
'DETECTOR'
47FGCM_ILLEGAL_VALUE = -9999.0
51 resetFitParameters, outputZeropoints,
52 lutFilterNames, tract=None):
54 Make the FGCM fit cycle configuration dict
58 config: `lsst.fgcmcal.FgcmFitCycleConfig`
62 camera: `lsst.afw.cameraGeom.Camera`
63 Camera from the butler
65 Maximum number of iterations
66 resetFitParameters: `bool`
67 Reset fit parameters before fitting?
68 outputZeropoints: `bool`
69 Compute zeropoints
for output?
70 lutFilterNames : array-like, `str`
71 Array of physical filter names
in the LUT.
72 tract: `int`, optional
73 Tract number
for extending the output file name
for debugging.
79 Configuration dictionary
for fgcm
82 notFitBands = [b
for b
in config.bands
if b
not in config.fitBands]
86 for ccut
in config.starColorCuts:
87 parts = ccut.split(
',')
88 starColorCutList.append([parts[0], parts[1], float(parts[2]), float(parts[3])])
93 mirrorArea = np.pi*(camera.telescopeDiameter*100./2.)**2.
96 gains = [amp.getGain()
for detector
in camera
for amp
in detector.getAmplifiers()]
97 cameraGain = float(np.median(gains))
100 filterToBand = {filterName: config.physicalFilterMap[filterName]
for
101 filterName
in lutFilterNames}
104 outfileBase = config.outfileBase
106 outfileBase =
'%s-%06d' % (config.outfileBase, tract)
109 configDict = {
'outfileBase': outfileBase,
111 'exposureFile':
None,
115 'mirrorArea': mirrorArea,
116 'cameraGain': cameraGain,
117 'ccdStartIndex': camera[0].getId(),
118 'expField': FGCM_EXP_FIELD,
119 'ccdField': FGCM_CCD_FIELD,
120 'seeingField':
'DELTA_APER',
121 'fwhmField':
'PSFSIGMA',
122 'skyBrightnessField':
'SKYBACKGROUND',
123 'deepFlag':
'DEEPFLAG',
124 'bands': list(config.bands),
125 'fitBands': list(config.fitBands),
126 'notFitBands': notFitBands,
127 'requiredBands': list(config.requiredBands),
128 'filterToBand': filterToBand,
130 'nCore': config.nCore,
131 'nStarPerRun': config.nStarPerRun,
132 'nExpPerRun': config.nExpPerRun,
133 'reserveFraction': config.reserveFraction,
134 'freezeStdAtmosphere': config.freezeStdAtmosphere,
135 'precomputeSuperStarInitialCycle': config.precomputeSuperStarInitialCycle,
136 'superStarSubCCDDict': dict(config.superStarSubCcdDict),
137 'superStarSubCCDChebyshevOrder': config.superStarSubCcdChebyshevOrder,
138 'superStarSubCCDTriangular': config.superStarSubCcdTriangular,
139 'superStarSigmaClip': config.superStarSigmaClip,
140 'focalPlaneSigmaClip': config.focalPlaneSigmaClip,
141 'ccdGraySubCCDDict': dict(config.ccdGraySubCcdDict),
142 'ccdGraySubCCDChebyshevOrder': config.ccdGraySubCcdChebyshevOrder,
143 'ccdGraySubCCDTriangular': config.ccdGraySubCcdTriangular,
144 'ccdGrayFocalPlaneDict': dict(config.ccdGrayFocalPlaneDict),
145 'ccdGrayFocalPlaneChebyshevOrder': config.ccdGrayFocalPlaneChebyshevOrder,
146 'ccdGrayFocalPlaneFitMinCcd': config.ccdGrayFocalPlaneFitMinCcd,
147 'cycleNumber': config.cycleNumber,
149 'deltaMagBkgOffsetPercentile': config.deltaMagBkgOffsetPercentile,
150 'deltaMagBkgPerCcd': config.deltaMagBkgPerCcd,
151 'UTBoundary': config.utBoundary,
152 'washMJDs': config.washMjds,
153 'epochMJDs': config.epochMjds,
154 'coatingMJDs': config.coatingMjds,
155 'minObsPerBand': config.minObsPerBand,
156 'latitude': config.latitude,
157 'defaultCameraOrientation': config.defaultCameraOrientation,
158 'brightObsGrayMax': config.brightObsGrayMax,
159 'minStarPerCCD': config.minStarPerCcd,
160 'minCCDPerExp': config.minCcdPerExp,
161 'maxCCDGrayErr': config.maxCcdGrayErr,
162 'minStarPerExp': config.minStarPerExp,
163 'minExpPerNight': config.minExpPerNight,
164 'expGrayInitialCut': config.expGrayInitialCut,
165 'expGrayPhotometricCutDict': dict(config.expGrayPhotometricCutDict),
166 'expGrayHighCutDict': dict(config.expGrayHighCutDict),
167 'expGrayRecoverCut': config.expGrayRecoverCut,
168 'expVarGrayPhotometricCutDict': dict(config.expVarGrayPhotometricCutDict),
169 'expGrayErrRecoverCut': config.expGrayErrRecoverCut,
170 'refStarSnMin': config.refStarSnMin,
171 'refStarOutlierNSig': config.refStarOutlierNSig,
172 'applyRefStarColorCuts': config.applyRefStarColorCuts,
173 'illegalValue': FGCM_ILLEGAL_VALUE,
174 'starColorCuts': starColorCutList,
175 'aperCorrFitNBins': config.aperCorrFitNBins,
176 'aperCorrInputSlopeDict': dict(config.aperCorrInputSlopeDict),
177 'sedBoundaryTermDict': config.sedboundaryterms.toDict()[
'data'],
178 'sedTermDict': config.sedterms.toDict()[
'data'],
179 'colorSplitBands': list(config.colorSplitBands),
180 'sigFgcmMaxErr': config.sigFgcmMaxErr,
181 'sigFgcmMaxEGrayDict': dict(config.sigFgcmMaxEGrayDict),
182 'ccdGrayMaxStarErr': config.ccdGrayMaxStarErr,
183 'approxThroughputDict': dict(config.approxThroughputDict),
184 'sigmaCalRange': list(config.sigmaCalRange),
185 'sigmaCalFitPercentile': list(config.sigmaCalFitPercentile),
186 'sigmaCalPlotPercentile': list(config.sigmaCalPlotPercentile),
187 'sigma0Phot': config.sigma0Phot,
188 'mapLongitudeRef': config.mapLongitudeRef,
189 'mapNSide': config.mapNSide,
192 'useRetrievedPwv':
False,
193 'useNightlyRetrievedPwv':
False,
194 'pwvRetrievalSmoothBlock': 25,
195 'useQuadraticPwv': config.useQuadraticPwv,
196 'useRetrievedTauInit':
False,
197 'tauRetrievalMinCCDPerNight': 500,
198 'modelMagErrors': config.modelMagErrors,
199 'instrumentParsPerBand': config.instrumentParsPerBand,
200 'instrumentSlopeMinDeltaT': config.instrumentSlopeMinDeltaT,
201 'fitMirrorChromaticity': config.fitMirrorChromaticity,
202 'useRepeatabilityForExpGrayCutsDict': dict(config.useRepeatabilityForExpGrayCutsDict),
203 'autoPhotometricCutNSig': config.autoPhotometricCutNSig,
204 'autoHighCutNSig': config.autoHighCutNSig,
206 'quietMode': config.quietMode,
207 'randomSeed': config.randomSeed,
208 'outputStars':
False,
209 'outputPath': os.path.abspath(
'.'),
212 'resetParameters': resetFitParameters,
213 'doPlots': config.doPlots,
214 'outputFgcmcalZpts':
True,
215 'outputZeropoints': outputZeropoints}
222 Translate the FGCM look-up-table into an fgcm-compatible object
226 lutCat: `lsst.afw.table.BaseCatalog`
227 Catalog describing the FGCM look-up table
228 physicalFilterMap: `dict`
229 Physical filter to band mapping
233 fgcmLut: `lsst.fgcm.FgcmLut`
234 Lookup table for FGCM
235 lutIndexVals: `numpy.ndarray`
236 Numpy array
with LUT index information
for FGCM
237 lutStd: `numpy.ndarray`
238 Numpy array
with LUT standard throughput values
for FGCM
242 After running this code, it
is wise to `del lutCat` to clear the memory.
246 lutFilterNames = np.array(lutCat[0][
'physicalFilters'].split(
','), dtype=
'U')
247 lutStdFilterNames = np.array(lutCat[0][
'stdPhysicalFilters'].split(
','), dtype=
'U')
252 lutIndexVals = np.zeros(1, dtype=[(
'FILTERNAMES', lutFilterNames.dtype.str,
253 lutFilterNames.size),
254 (
'STDFILTERNAMES', lutStdFilterNames.dtype.str,
255 lutStdFilterNames.size),
256 (
'PMB',
'f8', lutCat[0][
'pmb'].size),
257 (
'PMBFACTOR',
'f8', lutCat[0][
'pmbFactor'].size),
258 (
'PMBELEVATION',
'f8'),
259 (
'LAMBDANORM',
'f8'),
260 (
'PWV',
'f8', lutCat[0][
'pwv'].size),
261 (
'O3',
'f8', lutCat[0][
'o3'].size),
262 (
'TAU',
'f8', lutCat[0][
'tau'].size),
263 (
'ALPHA',
'f8', lutCat[0][
'alpha'].size),
264 (
'ZENITH',
'f8', lutCat[0][
'zenith'].size),
267 lutIndexVals[
'FILTERNAMES'][:] = lutFilterNames
268 lutIndexVals[
'STDFILTERNAMES'][:] = lutStdFilterNames
269 lutIndexVals[
'PMB'][:] = lutCat[0][
'pmb']
270 lutIndexVals[
'PMBFACTOR'][:] = lutCat[0][
'pmbFactor']
271 lutIndexVals[
'PMBELEVATION'] = lutCat[0][
'pmbElevation']
272 lutIndexVals[
'LAMBDANORM'] = lutCat[0][
'lambdaNorm']
273 lutIndexVals[
'PWV'][:] = lutCat[0][
'pwv']
274 lutIndexVals[
'O3'][:] = lutCat[0][
'o3']
275 lutIndexVals[
'TAU'][:] = lutCat[0][
'tau']
276 lutIndexVals[
'ALPHA'][:] = lutCat[0][
'alpha']
277 lutIndexVals[
'ZENITH'][:] = lutCat[0][
'zenith']
278 lutIndexVals[
'NCCD'] = lutCat[0][
'nCcd']
281 lutStd = np.zeros(1, dtype=[(
'PMBSTD',
'f8'),
287 (
'LAMBDARANGE',
'f8', 2),
288 (
'LAMBDASTEP',
'f8'),
289 (
'LAMBDASTD',
'f8', lutFilterNames.size),
290 (
'LAMBDASTDFILTER',
'f8', lutStdFilterNames.size),
291 (
'I0STD',
'f8', lutFilterNames.size),
292 (
'I1STD',
'f8', lutFilterNames.size),
293 (
'I10STD',
'f8', lutFilterNames.size),
294 (
'I2STD',
'f8', lutFilterNames.size),
295 (
'LAMBDAB',
'f8', lutFilterNames.size),
296 (
'ATMLAMBDA',
'f8', lutCat[0][
'atmLambda'].size),
297 (
'ATMSTDTRANS',
'f8', lutCat[0][
'atmStdTrans'].size)])
298 lutStd[
'PMBSTD'] = lutCat[0][
'pmbStd']
299 lutStd[
'PWVSTD'] = lutCat[0][
'pwvStd']
300 lutStd[
'O3STD'] = lutCat[0][
'o3Std']
301 lutStd[
'TAUSTD'] = lutCat[0][
'tauStd']
302 lutStd[
'ALPHASTD'] = lutCat[0][
'alphaStd']
303 lutStd[
'ZENITHSTD'] = lutCat[0][
'zenithStd']
304 lutStd[
'LAMBDARANGE'][:] = lutCat[0][
'lambdaRange'][:]
305 lutStd[
'LAMBDASTEP'] = lutCat[0][
'lambdaStep']
306 lutStd[
'LAMBDASTD'][:] = lutCat[0][
'lambdaStd']
307 lutStd[
'LAMBDASTDFILTER'][:] = lutCat[0][
'lambdaStdFilter']
308 lutStd[
'I0STD'][:] = lutCat[0][
'i0Std']
309 lutStd[
'I1STD'][:] = lutCat[0][
'i1Std']
310 lutStd[
'I10STD'][:] = lutCat[0][
'i10Std']
311 lutStd[
'I2STD'][:] = lutCat[0][
'i2Std']
312 lutStd[
'LAMBDAB'][:] = lutCat[0][
'lambdaB']
313 lutStd[
'ATMLAMBDA'][:] = lutCat[0][
'atmLambda'][:]
314 lutStd[
'ATMSTDTRANS'][:] = lutCat[0][
'atmStdTrans'][:]
316 lutTypes = [row[
'luttype']
for row
in lutCat]
319 lutFlat = np.zeros(lutCat[0][
'lut'].size, dtype=[(
'I0',
'f4'),
322 lutFlat[
'I0'][:] = lutCat[lutTypes.index(
'I0')][
'lut'][:]
323 lutFlat[
'I1'][:] = lutCat[lutTypes.index(
'I1')][
'lut'][:]
325 lutDerivFlat = np.zeros(lutCat[0][
'lut'].size, dtype=[(
'D_LNPWV',
'f4'),
329 (
'D_SECZENITH',
'f4'),
330 (
'D_LNPWV_I1',
'f4'),
332 (
'D_LNTAU_I1',
'f4'),
333 (
'D_ALPHA_I1',
'f4'),
334 (
'D_SECZENITH_I1',
'f4')])
336 for name
in lutDerivFlat.dtype.names:
337 lutDerivFlat[name][:] = lutCat[lutTypes.index(name)][
'lut'][:]
344 fgcmLut = fgcm.FgcmLUT(lutIndexVals, lutFlat, lutDerivFlat, lutStd,
345 filterToBand=physicalFilterMap)
347 return fgcmLut, lutIndexVals, lutStd
352 Translate the FGCM visit catalog to an fgcm-compatible object
356 visitCat: `lsst.afw.table.BaseCatalog`
361 fgcmExpInfo: `numpy.ndarray`
362 Numpy array
for visit information
for FGCM
366 After running this code, it
is wise to `del visitCat` to clear the memory.
369 fgcmExpInfo = np.zeros(len(visitCat), dtype=[('VISIT',
'i8'),
373 (
'DELTA_APER',
'f8'),
374 (
'SKYBACKGROUND',
'f8'),
381 (
'FILTERNAME',
'a50')])
382 fgcmExpInfo[
'VISIT'][:] = visitCat[
'visit']
383 fgcmExpInfo[
'MJD'][:] = visitCat[
'mjd']
384 fgcmExpInfo[
'EXPTIME'][:] = visitCat[
'exptime']
385 fgcmExpInfo[
'DEEPFLAG'][:] = visitCat[
'deepFlag']
386 fgcmExpInfo[
'TELHA'][:] = visitCat[
'telha']
387 fgcmExpInfo[
'TELRA'][:] = visitCat[
'telra']
388 fgcmExpInfo[
'TELDEC'][:] = visitCat[
'teldec']
389 fgcmExpInfo[
'TELROT'][:] = visitCat[
'telrot']
390 fgcmExpInfo[
'PMB'][:] = visitCat[
'pmb']
391 fgcmExpInfo[
'PSFSIGMA'][:] = visitCat[
'psfSigma']
392 fgcmExpInfo[
'DELTA_APER'][:] = visitCat[
'deltaAper']
393 fgcmExpInfo[
'SKYBACKGROUND'][:] = visitCat[
'skyBackground']
396 fgcmExpInfo[
'FILTERNAME'][:] = visitCat.asAstropy()[
'physicalFilter']
401@deprecated(reason=
"This method is no longer used in fgcmcal. It will be removed after v23.",
402 version=
"v23.0", category=FutureWarning)
405 Compute the CCD offsets in ra/dec
and x/y space
409 camera: `lsst.afw.cameraGeom.Camera`
410 defaultOrientation: `float`
411 Default camera orientation (degrees)
415 ccdOffsets: `numpy.ndarray`
416 Numpy array
with ccd offset information
for input to FGCM.
417 Angular units are degrees,
and x/y units are pixels.
422 ccdOffsets = np.zeros(len(camera), dtype=[(
'CCDNUM',
'i4'),
432 boresight = geom.SpherePoint(180.0*geom.degrees, 0.0*geom.degrees)
437 if camera.getName() ==
'HSC' and np.isnan(defaultOrientation):
438 orientation = 270*geom.degrees
440 orientation = defaultOrientation*geom.degrees
444 visitInfo = afwImage.VisitInfo(boresightRaDec=boresight,
445 boresightRotAngle=orientation,
446 rotType=afwImage.RotType.SKY)
448 for i, detector
in enumerate(camera):
449 ccdOffsets[
'CCDNUM'][i] = detector.getId()
451 wcs = createInitialSkyWcs(visitInfo, detector, flipX)
453 detCenter = wcs.pixelToSky(detector.getCenter(afwCameraGeom.PIXELS))
454 ccdOffsets[
'DELTA_RA'][i] = (detCenter.getRa() - boresight.getRa()).asDegrees()
455 ccdOffsets[
'DELTA_DEC'][i] = (detCenter.getDec() - boresight.getDec()).asDegrees()
457 bbox = detector.getBBox()
459 detCorner1 = wcs.pixelToSky(geom.Point2D(bbox.getMin()))
460 detCorner2 = wcs.pixelToSky(geom.Point2D(bbox.getMax()))
462 ccdOffsets[
'RA_SIZE'][i] = np.abs((detCorner2.getRa() - detCorner1.getRa()).asDegrees())
463 ccdOffsets[
'DEC_SIZE'][i] = np.abs((detCorner2.getDec() - detCorner1.getDec()).asDegrees())
465 ccdOffsets[
'X_SIZE'][i] = bbox.getMaxX()
466 ccdOffsets[
'Y_SIZE'][i] = bbox.getMaxY()
473 Compute the median pixel scale in the camera
478 Average pixel scale (arcsecond) over the camera
481 boresight = geom.SpherePoint(180.0*geom.degrees, 0.0*geom.degrees)
482 orientation = 0.0*geom.degrees
486 visitInfo = afwImage.VisitInfo(boresightRaDec=boresight,
487 boresightRotAngle=orientation,
488 rotType=afwImage.RotType.SKY)
490 pixelScales = np.zeros(len(camera))
491 for i, detector
in enumerate(camera):
492 wcs = createInitialSkyWcs(visitInfo, detector, flipX)
493 pixelScales[i] = wcs.getPixelScale().asArcseconds()
495 ok, = np.where(pixelScales > 0.0)
496 return np.median(pixelScales[ok])
501 Compute the approximate pixel area bounded fields from the camera
506 camera: `lsst.afw.cameraGeom.Camera`
510 approxPixelAreaFields: `dict`
511 Dictionary of approximate area fields, keyed
with detector ID
518 boresight = geom.SpherePoint(180.0*geom.degrees, 0.0*geom.degrees)
523 visitInfo = afwImage.VisitInfo(boresightRaDec=boresight,
524 boresightRotAngle=0.0*geom.degrees,
525 rotType=afwImage.RotType.SKY)
527 approxPixelAreaFields = {}
529 for i, detector
in enumerate(camera):
530 key = detector.getId()
532 wcs = createInitialSkyWcs(visitInfo, detector, flipX)
533 bbox = detector.getBBox()
535 areaField = afwMath.PixelAreaBoundedField(bbox, wcs,
536 unit=geom.arcseconds, scaling=areaScaling)
537 approxAreaField = afwMath.ChebyshevBoundedField.approximate(areaField)
539 approxPixelAreaFields[key] = approxAreaField
541 return approxPixelAreaFields
546 Make the zeropoint schema
550 superStarChebyshevSize: `int`
551 Length of the superstar chebyshev array
552 zptChebyshevSize: `int`
553 Length of the zeropoint chebyshev array
557 zptSchema: `lsst.afw.table.schema`
560 zptSchema = afwTable.Schema()
562 zptSchema.addField('visit', type=np.int32, doc=
'Visit number')
563 zptSchema.addField(
'detector', type=np.int32, doc=
'Detector ID number')
564 zptSchema.addField(
'fgcmFlag', type=np.int32, doc=(
'FGCM flag value: '
565 '1: Photometric, used in fit; '
566 '2: Photometric, not used in fit; '
567 '4: Non-photometric, on partly photometric night; '
568 '8: Non-photometric, on non-photometric night; '
569 '16: No zeropoint could be determined; '
570 '32: Too few stars for reliable gray computation'))
571 zptSchema.addField(
'fgcmZpt', type=np.float64, doc=
'FGCM zeropoint (center of CCD)')
572 zptSchema.addField(
'fgcmZptErr', type=np.float64,
573 doc=
'Error on zeropoint, estimated from repeatability + number of obs')
574 zptSchema.addField(
'fgcmfZptChebXyMax', type=
'ArrayD', size=2,
575 doc=
'maximum x/maximum y to scale to apply chebyshev parameters')
576 zptSchema.addField(
'fgcmfZptCheb', type=
'ArrayD',
577 size=zptChebyshevSize,
578 doc=
'Chebyshev parameters (flattened) for zeropoint')
579 zptSchema.addField(
'fgcmfZptSstarCheb', type=
'ArrayD',
580 size=superStarChebyshevSize,
581 doc=
'Chebyshev parameters (flattened) for superStarFlat')
582 zptSchema.addField(
'fgcmI0', type=np.float64, doc=
'Integral of the passband')
583 zptSchema.addField(
'fgcmI10', type=np.float64, doc=
'Normalized chromatic integral')
584 zptSchema.addField(
'fgcmR0', type=np.float64,
585 doc=
'Retrieved i0 integral, estimated from stars (only for flag 1)')
586 zptSchema.addField(
'fgcmR10', type=np.float64,
587 doc=
'Retrieved i10 integral, estimated from stars (only for flag 1)')
588 zptSchema.addField(
'fgcmGry', type=np.float64,
589 doc=
'Estimated gray extinction relative to atmospheric solution; '
590 'only for fgcmFlag <= 4 (see fgcmFlag) ')
591 zptSchema.addField(
'fgcmDeltaChrom', type=np.float64,
592 doc=
'Mean chromatic correction for stars in this ccd; '
593 'only for fgcmFlag <= 4 (see fgcmFlag)')
594 zptSchema.addField(
'fgcmZptVar', type=np.float64, doc=
'Variance of zeropoint over ccd')
595 zptSchema.addField(
'fgcmTilings', type=np.float64,
596 doc=
'Number of photometric tilings used for solution for ccd')
597 zptSchema.addField(
'fgcmFpGry', type=np.float64,
598 doc=
'Average gray extinction over the full focal plane '
599 '(same for all ccds in a visit)')
600 zptSchema.addField(
'fgcmFpGryBlue', type=np.float64,
601 doc=
'Average gray extinction over the full focal plane '
602 'for 25% bluest stars')
603 zptSchema.addField(
'fgcmFpGryBlueErr', type=np.float64,
604 doc=
'Error on Average gray extinction over the full focal plane '
605 'for 25% bluest stars')
606 zptSchema.addField(
'fgcmFpGryRed', type=np.float64,
607 doc=
'Average gray extinction over the full focal plane '
608 'for 25% reddest stars')
609 zptSchema.addField(
'fgcmFpGryRedErr', type=np.float64,
610 doc=
'Error on Average gray extinction over the full focal plane '
611 'for 25% reddest stars')
612 zptSchema.addField(
'fgcmFpVar', type=np.float64,
613 doc=
'Variance of gray extinction over the full focal plane '
614 '(same for all ccds in a visit)')
615 zptSchema.addField(
'fgcmDust', type=np.float64,
616 doc=
'Gray dust extinction from the primary/corrector'
617 'at the time of the exposure')
618 zptSchema.addField(
'fgcmFlat', type=np.float64, doc=
'Superstarflat illumination correction')
619 zptSchema.addField(
'fgcmAperCorr', type=np.float64, doc=
'Aperture correction estimated by fgcm')
620 zptSchema.addField(
'fgcmDeltaMagBkg', type=np.float64,
621 doc=(
'Local background correction from brightest percentile '
622 '(value set by deltaMagBkgOffsetPercentile) calibration '
624 zptSchema.addField(
'exptime', type=np.float32, doc=
'Exposure time')
625 zptSchema.addField(
'filtername', type=str, size=10, doc=
'Filter name')
632 Make the zeropoint catalog for persistence
636 zptSchema: `lsst.afw.table.Schema`
637 Zeropoint catalog schema
638 zpStruct: `numpy.ndarray`
639 Zeropoint structure
from fgcm
643 zptCat: `afwTable.BaseCatalog`
644 Zeropoint catalog
for persistence
647 zptCat = afwTable.BaseCatalog(zptSchema)
648 zptCat.reserve(zpStruct.size)
650 for filterName
in zpStruct[
'FILTERNAME']:
651 rec = zptCat.addNew()
652 rec[
'filtername'] = filterName.decode(
'utf-8')
654 zptCat[
'visit'][:] = zpStruct[FGCM_EXP_FIELD]
655 zptCat[
'detector'][:] = zpStruct[FGCM_CCD_FIELD]
656 zptCat[
'fgcmFlag'][:] = zpStruct[
'FGCM_FLAG']
657 zptCat[
'fgcmZpt'][:] = zpStruct[
'FGCM_ZPT']
658 zptCat[
'fgcmZptErr'][:] = zpStruct[
'FGCM_ZPTERR']
659 zptCat[
'fgcmfZptChebXyMax'][:, :] = zpStruct[
'FGCM_FZPT_XYMAX']
660 zptCat[
'fgcmfZptCheb'][:, :] = zpStruct[
'FGCM_FZPT_CHEB']
661 zptCat[
'fgcmfZptSstarCheb'][:, :] = zpStruct[
'FGCM_FZPT_SSTAR_CHEB']
662 zptCat[
'fgcmI0'][:] = zpStruct[
'FGCM_I0']
663 zptCat[
'fgcmI10'][:] = zpStruct[
'FGCM_I10']
664 zptCat[
'fgcmR0'][:] = zpStruct[
'FGCM_R0']
665 zptCat[
'fgcmR10'][:] = zpStruct[
'FGCM_R10']
666 zptCat[
'fgcmGry'][:] = zpStruct[
'FGCM_GRY']
667 zptCat[
'fgcmDeltaChrom'][:] = zpStruct[
'FGCM_DELTACHROM']
668 zptCat[
'fgcmZptVar'][:] = zpStruct[
'FGCM_ZPTVAR']
669 zptCat[
'fgcmTilings'][:] = zpStruct[
'FGCM_TILINGS']
670 zptCat[
'fgcmFpGry'][:] = zpStruct[
'FGCM_FPGRY']
671 zptCat[
'fgcmFpGryBlue'][:] = zpStruct[
'FGCM_FPGRY_CSPLIT'][:, 0]
672 zptCat[
'fgcmFpGryBlueErr'][:] = zpStruct[
'FGCM_FPGRY_CSPLITERR'][:, 0]
673 zptCat[
'fgcmFpGryRed'][:] = zpStruct[
'FGCM_FPGRY_CSPLIT'][:, 2]
674 zptCat[
'fgcmFpGryRedErr'][:] = zpStruct[
'FGCM_FPGRY_CSPLITERR'][:, 2]
675 zptCat[
'fgcmFpVar'][:] = zpStruct[
'FGCM_FPVAR']
676 zptCat[
'fgcmDust'][:] = zpStruct[
'FGCM_DUST']
677 zptCat[
'fgcmFlat'][:] = zpStruct[
'FGCM_FLAT']
678 zptCat[
'fgcmAperCorr'][:] = zpStruct[
'FGCM_APERCORR']
679 zptCat[
'fgcmDeltaMagBkg'][:] = zpStruct[
'FGCM_DELTAMAGBKG']
680 zptCat[
'exptime'][:] = zpStruct[
'EXPTIME']
687 Make the atmosphere schema
691 atmSchema: `lsst.afw.table.Schema`
694 atmSchema = afwTable.Schema()
696 atmSchema.addField('visit', type=np.int32, doc=
'Visit number')
697 atmSchema.addField(
'pmb', type=np.float64, doc=
'Barometric pressure (mb)')
698 atmSchema.addField(
'pwv', type=np.float64, doc=
'Water vapor (mm)')
699 atmSchema.addField(
'tau', type=np.float64, doc=
'Aerosol optical depth')
700 atmSchema.addField(
'alpha', type=np.float64, doc=
'Aerosol slope')
701 atmSchema.addField(
'o3', type=np.float64, doc=
'Ozone (dobson)')
702 atmSchema.addField(
'secZenith', type=np.float64, doc=
'Secant(zenith) (~ airmass)')
703 atmSchema.addField(
'cTrans', type=np.float64, doc=
'Transmission correction factor')
704 atmSchema.addField(
'lamStd', type=np.float64, doc=
'Wavelength for transmission correction')
711 Make the atmosphere catalog for persistence
715 atmSchema: `lsst.afw.table.Schema`
716 Atmosphere catalog schema
717 atmStruct: `numpy.ndarray`
718 Atmosphere structure
from fgcm
722 atmCat: `lsst.afw.table.BaseCatalog`
723 Atmosphere catalog
for persistence
726 atmCat = afwTable.BaseCatalog(atmSchema)
727 atmCat.resize(atmStruct.size)
729 atmCat['visit'][:] = atmStruct[
'VISIT']
730 atmCat[
'pmb'][:] = atmStruct[
'PMB']
731 atmCat[
'pwv'][:] = atmStruct[
'PWV']
732 atmCat[
'tau'][:] = atmStruct[
'TAU']
733 atmCat[
'alpha'][:] = atmStruct[
'ALPHA']
734 atmCat[
'o3'][:] = atmStruct[
'O3']
735 atmCat[
'secZenith'][:] = atmStruct[
'SECZENITH']
736 atmCat[
'cTrans'][:] = atmStruct[
'CTRANS']
737 atmCat[
'lamStd'][:] = atmStruct[
'LAMSTD']
744 Make the standard star schema
749 Number of bands in standard star catalog
753 stdSchema: `lsst.afw.table.Schema`
756 stdSchema = afwTable.SimpleTable.makeMinimalSchema()
757 stdSchema.addField('ngood', type=
'ArrayI', doc=
'Number of good observations',
759 stdSchema.addField(
'ntotal', type=
'ArrayI', doc=
'Number of total observations',
761 stdSchema.addField(
'mag_std_noabs', type=
'ArrayF',
762 doc=
'Standard magnitude (no absolute calibration)',
764 stdSchema.addField(
'magErr_std', type=
'ArrayF',
765 doc=
'Standard magnitude error',
767 stdSchema.addField(
'npsfcand', type=
'ArrayI',
768 doc=
'Number of observations flagged as psf candidates',
776 Make the standard star catalog for persistence
780 stdSchema: `lsst.afw.table.Schema`
781 Standard star catalog schema
782 stdStruct: `numpy.ndarray`
783 Standard star structure
in FGCM format
785 List of good band names used
in stdStruct
789 stdCat: `lsst.afw.table.BaseCatalog`
790 Standard star catalog
for persistence
793 stdCat = afwTable.SimpleCatalog(stdSchema)
794 stdCat.resize(stdStruct.size)
796 stdCat['id'][:] = stdStruct[
'FGCM_ID']
797 stdCat[
'coord_ra'][:] = stdStruct[
'RA'] * geom.degrees
798 stdCat[
'coord_dec'][:] = stdStruct[
'DEC'] * geom.degrees
799 stdCat[
'ngood'][:, :] = stdStruct[
'NGOOD'][:, :]
800 stdCat[
'ntotal'][:, :] = stdStruct[
'NTOTAL'][:, :]
801 stdCat[
'mag_std_noabs'][:, :] = stdStruct[
'MAG_STD'][:, :]
802 stdCat[
'magErr_std'][:, :] = stdStruct[
'MAGERR_STD'][:, :]
803 stdCat[
'npsfcand'][:, :] = stdStruct[
'NPSFCAND'][:, :]
806 md.set(
"BANDS", list(goodBands))
807 stdCat.setMetadata(md)
814 Compute the radius associated with a CircularApertureFlux field
or
819 dataRef : `lsst.daf.persistence.ButlerDataRef`
or
820 `lsst.daf.butler.DeferredDatasetHandle`
822 CircularApertureFlux
or associated slot.
826 apertureRadius : `float`
827 Radius of the aperture field,
in pixels.
831 RuntimeError: Raised
if flux field
is not a CircularApertureFlux, ApFlux,
832 apFlux,
or associated slot.
835 if isinstance(dataRef, dafPersist.ButlerDataRef):
837 datasetType = dataRef.butlerSubset.datasetType
840 datasetType = dataRef.ref.datasetType.name
842 if datasetType ==
'src':
843 schema = dataRef.get(datasetType=
'src_schema').schema
845 fluxFieldName = schema[fluxField].asField().getName()
847 raise RuntimeError(
"Could not find %s or associated slot in schema." % (fluxField))
854 return apertureRadius
859 Compute the radius associated with a CircularApertureFlux
or ApFlux field.
864 CircularApertureFlux
or ApFlux
868 apertureRadius : `float`
869 Radius of the aperture field,
in pixels.
873 RuntimeError: Raised
if flux field
is not a CircularApertureFlux,
877 m = re.search(
r'(CircularApertureFlux|ApFlux|apFlux)_(\d+)_(\d+)_', fluxField)
880 raise RuntimeError(f
"Flux field {fluxField} does not correspond to a CircularApertureFlux or ApFlux")
882 apertureRadius = float(m.groups()[1]) + float(m.groups()[2])/10.
884 return apertureRadius
889 Extract reference magnitudes from refStars
for given bands
and
890 associated filterMap.
894 refStars : `lsst.afw.table.BaseCatalog`
895 FGCM reference star catalog
897 List of bands
for calibration
899 FGCM mapping of filter to band
903 refMag : `np.ndarray`
904 nstar x nband array of reference magnitudes
905 refMagErr : `np.ndarray`
906 nstar x nband array of reference magnitude errors
912 md = refStars.getMetadata()
913 if 'FILTERNAMES' in md:
914 filternames = md.getArray(
'FILTERNAMES')
918 refMag = np.zeros((len(refStars), len(bands)),
919 dtype=refStars[
'refMag'].dtype) + 99.0
920 refMagErr = np.zeros_like(refMag) + 99.0
921 for i, filtername
in enumerate(filternames):
925 band = filterMap[filtername]
929 ind = bands.index(band)
933 refMag[:, ind] = refStars[
'refMag'][:, i]
934 refMagErr[:, ind] = refStars[
'refMagErr'][:, i]
938 refMag = refStars[
'refMag'][:, :]
939 refMagErr = refStars[
'refMagErr'][:, :]
941 return refMag, refMagErr
945 instrument = Instrument.fromName(quantumDataId[
"instrument"], registry)
946 unboundedCollection = instrument.makeUnboundedCalibrationRunName()
948 return registry.queryDatasets(datasetType,
949 dataId=quantumDataId,
950 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)