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.afw.cameraGeom
as afwCameraGeom
34import lsst.afw.table
as afwTable
35import lsst.afw.image
as afwImage
36import lsst.afw.math
as afwMath
37import lsst.geom
as geom
38from lsst.obs.base
import createInitialSkyWcs
39from lsst.pipe.base
import Instrument
44FGCM_EXP_FIELD =
'VISIT'
45FGCM_CCD_FIELD =
'DETECTOR'
46FGCM_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 'defaultCameraOrientation': config.defaultCameraOrientation,
157 'brightObsGrayMax': config.brightObsGrayMax,
158 'minStarPerCCD': config.minStarPerCcd,
159 'minCCDPerExp': config.minCcdPerExp,
160 'maxCCDGrayErr': config.maxCcdGrayErr,
161 'minStarPerExp': config.minStarPerExp,
162 'minExpPerNight': config.minExpPerNight,
163 'expGrayInitialCut': config.expGrayInitialCut,
164 'expGrayPhotometricCutDict': dict(config.expGrayPhotometricCutDict),
165 'expGrayHighCutDict': dict(config.expGrayHighCutDict),
166 'expGrayRecoverCut': config.expGrayRecoverCut,
167 'expVarGrayPhotometricCutDict': dict(config.expVarGrayPhotometricCutDict),
168 'expGrayErrRecoverCut': config.expGrayErrRecoverCut,
169 'refStarSnMin': config.refStarSnMin,
170 'refStarOutlierNSig': config.refStarOutlierNSig,
171 'applyRefStarColorCuts': config.applyRefStarColorCuts,
172 'illegalValue': FGCM_ILLEGAL_VALUE,
173 'starColorCuts': starColorCutList,
174 'aperCorrFitNBins': config.aperCorrFitNBins,
175 'aperCorrInputSlopeDict': dict(config.aperCorrInputSlopeDict),
176 'sedBoundaryTermDict': config.sedboundaryterms.toDict()[
'data'],
177 'sedTermDict': config.sedterms.toDict()[
'data'],
178 'colorSplitBands': list(config.colorSplitBands),
179 'sigFgcmMaxErr': config.sigFgcmMaxErr,
180 'sigFgcmMaxEGrayDict': dict(config.sigFgcmMaxEGrayDict),
181 'ccdGrayMaxStarErr': config.ccdGrayMaxStarErr,
182 'approxThroughputDict': dict(config.approxThroughputDict),
183 'sigmaCalRange': list(config.sigmaCalRange),
184 'sigmaCalFitPercentile': list(config.sigmaCalFitPercentile),
185 'sigmaCalPlotPercentile': list(config.sigmaCalPlotPercentile),
186 'sigma0Phot': config.sigma0Phot,
187 'mapLongitudeRef': config.mapLongitudeRef,
188 'mapNSide': config.mapNSide,
191 'useRetrievedPwv':
False,
192 'useNightlyRetrievedPwv':
False,
193 'pwvRetrievalSmoothBlock': 25,
194 'useQuadraticPwv': config.useQuadraticPwv,
195 'useRetrievedTauInit':
False,
196 'tauRetrievalMinCCDPerNight': 500,
197 'modelMagErrors': config.modelMagErrors,
198 'instrumentParsPerBand': config.instrumentParsPerBand,
199 'instrumentSlopeMinDeltaT': config.instrumentSlopeMinDeltaT,
200 'fitMirrorChromaticity': config.fitMirrorChromaticity,
201 'useRepeatabilityForExpGrayCutsDict': dict(config.useRepeatabilityForExpGrayCutsDict),
202 'autoPhotometricCutNSig': config.autoPhotometricCutNSig,
203 'autoHighCutNSig': config.autoHighCutNSig,
204 'deltaAperInnerRadiusArcsec': config.deltaAperInnerRadiusArcsec,
205 'deltaAperOuterRadiusArcsec': config.deltaAperOuterRadiusArcsec,
206 'deltaAperFitMinNgoodObs': config.deltaAperFitMinNgoodObs,
207 'deltaAperFitPerCcdNx': config.deltaAperFitPerCcdNx,
208 'deltaAperFitPerCcdNy': config.deltaAperFitPerCcdNy,
209 'deltaAperFitSpatialNside': config.deltaAperFitSpatialNside,
210 'doComputeDeltaAperExposures': config.doComputeDeltaAperPerVisit,
211 'doComputeDeltaAperStars': config.doComputeDeltaAperPerStar,
212 'doComputeDeltaAperMap': config.doComputeDeltaAperMap,
213 'doComputeDeltaAperPerCcd': config.doComputeDeltaAperPerCcd,
215 'quietMode': config.quietMode,
216 'randomSeed': config.randomSeed,
217 'outputStars':
False,
218 'outputPath': os.path.abspath(
'.'),
221 'resetParameters': resetFitParameters,
222 'doPlots': config.doPlots,
223 'outputFgcmcalZpts':
True,
224 'outputZeropoints': outputZeropoints}
231 Translate the FGCM look-up-table into an fgcm-compatible object
235 lutCat: `lsst.afw.table.BaseCatalog`
236 Catalog describing the FGCM look-up table
237 physicalFilterMap: `dict`
238 Physical filter to band mapping
242 fgcmLut: `lsst.fgcm.FgcmLut`
243 Lookup table for FGCM
244 lutIndexVals: `numpy.ndarray`
245 Numpy array
with LUT index information
for FGCM
246 lutStd: `numpy.ndarray`
247 Numpy array
with LUT standard throughput values
for FGCM
251 After running this code, it
is wise to `del lutCat` to clear the memory.
255 lutFilterNames = np.array(lutCat[0][
'physicalFilters'].split(
','), dtype=
'U')
256 lutStdFilterNames = np.array(lutCat[0][
'stdPhysicalFilters'].split(
','), dtype=
'U')
261 lutIndexVals = np.zeros(1, dtype=[(
'FILTERNAMES', lutFilterNames.dtype.str,
262 lutFilterNames.size),
263 (
'STDFILTERNAMES', lutStdFilterNames.dtype.str,
264 lutStdFilterNames.size),
265 (
'PMB',
'f8', lutCat[0][
'pmb'].size),
266 (
'PMBFACTOR',
'f8', lutCat[0][
'pmbFactor'].size),
267 (
'PMBELEVATION',
'f8'),
268 (
'LAMBDANORM',
'f8'),
269 (
'PWV',
'f8', lutCat[0][
'pwv'].size),
270 (
'O3',
'f8', lutCat[0][
'o3'].size),
271 (
'TAU',
'f8', lutCat[0][
'tau'].size),
272 (
'ALPHA',
'f8', lutCat[0][
'alpha'].size),
273 (
'ZENITH',
'f8', lutCat[0][
'zenith'].size),
276 lutIndexVals[
'FILTERNAMES'][:] = lutFilterNames
277 lutIndexVals[
'STDFILTERNAMES'][:] = lutStdFilterNames
278 lutIndexVals[
'PMB'][:] = lutCat[0][
'pmb']
279 lutIndexVals[
'PMBFACTOR'][:] = lutCat[0][
'pmbFactor']
280 lutIndexVals[
'PMBELEVATION'] = lutCat[0][
'pmbElevation']
281 lutIndexVals[
'LAMBDANORM'] = lutCat[0][
'lambdaNorm']
282 lutIndexVals[
'PWV'][:] = lutCat[0][
'pwv']
283 lutIndexVals[
'O3'][:] = lutCat[0][
'o3']
284 lutIndexVals[
'TAU'][:] = lutCat[0][
'tau']
285 lutIndexVals[
'ALPHA'][:] = lutCat[0][
'alpha']
286 lutIndexVals[
'ZENITH'][:] = lutCat[0][
'zenith']
287 lutIndexVals[
'NCCD'] = lutCat[0][
'nCcd']
290 lutStd = np.zeros(1, dtype=[(
'PMBSTD',
'f8'),
296 (
'LAMBDARANGE',
'f8', 2),
297 (
'LAMBDASTEP',
'f8'),
298 (
'LAMBDASTD',
'f8', lutFilterNames.size),
299 (
'LAMBDASTDFILTER',
'f8', lutStdFilterNames.size),
300 (
'I0STD',
'f8', lutFilterNames.size),
301 (
'I1STD',
'f8', lutFilterNames.size),
302 (
'I10STD',
'f8', lutFilterNames.size),
303 (
'I2STD',
'f8', lutFilterNames.size),
304 (
'LAMBDAB',
'f8', lutFilterNames.size),
305 (
'ATMLAMBDA',
'f8', lutCat[0][
'atmLambda'].size),
306 (
'ATMSTDTRANS',
'f8', lutCat[0][
'atmStdTrans'].size)])
307 lutStd[
'PMBSTD'] = lutCat[0][
'pmbStd']
308 lutStd[
'PWVSTD'] = lutCat[0][
'pwvStd']
309 lutStd[
'O3STD'] = lutCat[0][
'o3Std']
310 lutStd[
'TAUSTD'] = lutCat[0][
'tauStd']
311 lutStd[
'ALPHASTD'] = lutCat[0][
'alphaStd']
312 lutStd[
'ZENITHSTD'] = lutCat[0][
'zenithStd']
313 lutStd[
'LAMBDARANGE'][:] = lutCat[0][
'lambdaRange'][:]
314 lutStd[
'LAMBDASTEP'] = lutCat[0][
'lambdaStep']
315 lutStd[
'LAMBDASTD'][:] = lutCat[0][
'lambdaStd']
316 lutStd[
'LAMBDASTDFILTER'][:] = lutCat[0][
'lambdaStdFilter']
317 lutStd[
'I0STD'][:] = lutCat[0][
'i0Std']
318 lutStd[
'I1STD'][:] = lutCat[0][
'i1Std']
319 lutStd[
'I10STD'][:] = lutCat[0][
'i10Std']
320 lutStd[
'I2STD'][:] = lutCat[0][
'i2Std']
321 lutStd[
'LAMBDAB'][:] = lutCat[0][
'lambdaB']
322 lutStd[
'ATMLAMBDA'][:] = lutCat[0][
'atmLambda'][:]
323 lutStd[
'ATMSTDTRANS'][:] = lutCat[0][
'atmStdTrans'][:]
325 lutTypes = [row[
'luttype']
for row
in lutCat]
328 lutFlat = np.zeros(lutCat[0][
'lut'].size, dtype=[(
'I0',
'f4'),
331 lutFlat[
'I0'][:] = lutCat[lutTypes.index(
'I0')][
'lut'][:]
332 lutFlat[
'I1'][:] = lutCat[lutTypes.index(
'I1')][
'lut'][:]
334 lutDerivFlat = np.zeros(lutCat[0][
'lut'].size, dtype=[(
'D_LNPWV',
'f4'),
338 (
'D_SECZENITH',
'f4'),
339 (
'D_LNPWV_I1',
'f4'),
341 (
'D_LNTAU_I1',
'f4'),
342 (
'D_ALPHA_I1',
'f4'),
343 (
'D_SECZENITH_I1',
'f4')])
345 for name
in lutDerivFlat.dtype.names:
346 lutDerivFlat[name][:] = lutCat[lutTypes.index(name)][
'lut'][:]
353 fgcmLut = fgcm.FgcmLUT(lutIndexVals, lutFlat, lutDerivFlat, lutStd,
354 filterToBand=physicalFilterMap)
356 return fgcmLut, lutIndexVals, lutStd
361 Translate the FGCM visit catalog to an fgcm-compatible object
365 visitCat: `lsst.afw.table.BaseCatalog`
366 FGCM visitCat from `lsst.fgcmcal.FgcmBuildStarsTask`
370 fgcmExpInfo: `numpy.ndarray`
371 Numpy array
for visit information
for FGCM
375 After running this code, it
is wise to `del visitCat` to clear the memory.
378 fgcmExpInfo = np.zeros(len(visitCat), dtype=[('VISIT',
'i8'),
382 (
'DELTA_APER',
'f8'),
383 (
'SKYBACKGROUND',
'f8'),
390 (
'FILTERNAME',
'a50')])
391 fgcmExpInfo[
'VISIT'][:] = visitCat[
'visit']
392 fgcmExpInfo[
'MJD'][:] = visitCat[
'mjd']
393 fgcmExpInfo[
'EXPTIME'][:] = visitCat[
'exptime']
394 fgcmExpInfo[
'DEEPFLAG'][:] = visitCat[
'deepFlag']
395 fgcmExpInfo[
'TELHA'][:] = visitCat[
'telha']
396 fgcmExpInfo[
'TELRA'][:] = visitCat[
'telra']
397 fgcmExpInfo[
'TELDEC'][:] = visitCat[
'teldec']
398 fgcmExpInfo[
'TELROT'][:] = visitCat[
'telrot']
399 fgcmExpInfo[
'PMB'][:] = visitCat[
'pmb']
400 fgcmExpInfo[
'PSFSIGMA'][:] = visitCat[
'psfSigma']
401 fgcmExpInfo[
'DELTA_APER'][:] = visitCat[
'deltaAper']
402 fgcmExpInfo[
'SKYBACKGROUND'][:] = visitCat[
'skyBackground']
405 fgcmExpInfo[
'FILTERNAME'][:] = visitCat.asAstropy()[
'physicalFilter']
410@deprecated(reason=
"This method is no longer used in fgcmcal. It will be removed after v23.",
411 version=
"v23.0", category=FutureWarning)
414 Compute the CCD offsets in ra/dec
and x/y space
418 camera: `lsst.afw.cameraGeom.Camera`
419 defaultOrientation: `float`
420 Default camera orientation (degrees)
424 ccdOffsets: `numpy.ndarray`
425 Numpy array
with ccd offset information
for input to FGCM.
426 Angular units are degrees,
and x/y units are pixels.
431 ccdOffsets = np.zeros(len(camera), dtype=[(
'CCDNUM',
'i4'),
441 boresight = geom.SpherePoint(180.0*geom.degrees, 0.0*geom.degrees)
446 if camera.getName() ==
'HSC' and np.isnan(defaultOrientation):
447 orientation = 270*geom.degrees
449 orientation = defaultOrientation*geom.degrees
453 visitInfo = afwImage.VisitInfo(boresightRaDec=boresight,
454 boresightRotAngle=orientation,
455 rotType=afwImage.RotType.SKY)
457 for i, detector
in enumerate(camera):
458 ccdOffsets[
'CCDNUM'][i] = detector.getId()
460 wcs = createInitialSkyWcs(visitInfo, detector, flipX)
462 detCenter = wcs.pixelToSky(detector.getCenter(afwCameraGeom.PIXELS))
463 ccdOffsets[
'DELTA_RA'][i] = (detCenter.getRa() - boresight.getRa()).asDegrees()
464 ccdOffsets[
'DELTA_DEC'][i] = (detCenter.getDec() - boresight.getDec()).asDegrees()
466 bbox = detector.getBBox()
468 detCorner1 = wcs.pixelToSky(geom.Point2D(bbox.getMin()))
469 detCorner2 = wcs.pixelToSky(geom.Point2D(bbox.getMax()))
471 ccdOffsets[
'RA_SIZE'][i] = np.abs((detCorner2.getRa() - detCorner1.getRa()).asDegrees())
472 ccdOffsets[
'DEC_SIZE'][i] = np.abs((detCorner2.getDec() - detCorner1.getDec()).asDegrees())
474 ccdOffsets[
'X_SIZE'][i] = bbox.getMaxX()
475 ccdOffsets[
'Y_SIZE'][i] = bbox.getMaxY()
482 Compute the median pixel scale in the camera
487 Average pixel scale (arcsecond) over the camera
490 boresight = geom.SpherePoint(180.0*geom.degrees, 0.0*geom.degrees)
491 orientation = 0.0*geom.degrees
495 visitInfo = afwImage.VisitInfo(boresightRaDec=boresight,
496 boresightRotAngle=orientation,
497 rotType=afwImage.RotType.SKY)
499 pixelScales = np.zeros(len(camera))
500 for i, detector
in enumerate(camera):
501 wcs = createInitialSkyWcs(visitInfo, detector, flipX)
502 pixelScales[i] = wcs.getPixelScale().asArcseconds()
504 ok, = np.where(pixelScales > 0.0)
505 return np.median(pixelScales[ok])
510 Compute the approximate pixel area bounded fields from the camera
515 camera: `lsst.afw.cameraGeom.Camera`
519 approxPixelAreaFields: `dict`
520 Dictionary of approximate area fields, keyed
with detector ID
527 boresight = geom.SpherePoint(180.0*geom.degrees, 0.0*geom.degrees)
532 visitInfo = afwImage.VisitInfo(boresightRaDec=boresight,
533 boresightRotAngle=0.0*geom.degrees,
534 rotType=afwImage.RotType.SKY)
536 approxPixelAreaFields = {}
538 for i, detector
in enumerate(camera):
539 key = detector.getId()
541 wcs = createInitialSkyWcs(visitInfo, detector, flipX)
542 bbox = detector.getBBox()
544 areaField = afwMath.PixelAreaBoundedField(bbox, wcs,
545 unit=geom.arcseconds, scaling=areaScaling)
546 approxAreaField = afwMath.ChebyshevBoundedField.approximate(areaField)
548 approxPixelAreaFields[key] = approxAreaField
550 return approxPixelAreaFields
555 Make the zeropoint schema
559 superStarChebyshevSize: `int`
560 Length of the superstar chebyshev array
561 zptChebyshevSize: `int`
562 Length of the zeropoint chebyshev array
566 zptSchema: `lsst.afw.table.schema`
569 zptSchema = afwTable.Schema()
571 zptSchema.addField('visit', type=np.int64, doc=
'Visit number')
572 zptSchema.addField(
'detector', type=np.int32, doc=
'Detector ID number')
573 zptSchema.addField(
'fgcmFlag', type=np.int32, doc=(
'FGCM flag value: '
574 '1: Photometric, used in fit; '
575 '2: Photometric, not used in fit; '
576 '4: Non-photometric, on partly photometric night; '
577 '8: Non-photometric, on non-photometric night; '
578 '16: No zeropoint could be determined; '
579 '32: Too few stars for reliable gray computation'))
580 zptSchema.addField(
'fgcmZpt', type=np.float64, doc=
'FGCM zeropoint (center of CCD)')
581 zptSchema.addField(
'fgcmZptErr', type=np.float64,
582 doc=
'Error on zeropoint, estimated from repeatability + number of obs')
583 zptSchema.addField(
'fgcmfZptChebXyMax', type=
'ArrayD', size=2,
584 doc=
'maximum x/maximum y to scale to apply chebyshev parameters')
585 zptSchema.addField(
'fgcmfZptCheb', type=
'ArrayD',
586 size=zptChebyshevSize,
587 doc=
'Chebyshev parameters (flattened) for zeropoint')
588 zptSchema.addField(
'fgcmfZptSstarCheb', type=
'ArrayD',
589 size=superStarChebyshevSize,
590 doc=
'Chebyshev parameters (flattened) for superStarFlat')
591 zptSchema.addField(
'fgcmI0', type=np.float64, doc=
'Integral of the passband')
592 zptSchema.addField(
'fgcmI10', type=np.float64, doc=
'Normalized chromatic integral')
593 zptSchema.addField(
'fgcmR0', type=np.float64,
594 doc=
'Retrieved i0 integral, estimated from stars (only for flag 1)')
595 zptSchema.addField(
'fgcmR10', type=np.float64,
596 doc=
'Retrieved i10 integral, estimated from stars (only for flag 1)')
597 zptSchema.addField(
'fgcmGry', type=np.float64,
598 doc=
'Estimated gray extinction relative to atmospheric solution; '
599 'only for fgcmFlag <= 4 (see fgcmFlag) ')
600 zptSchema.addField(
'fgcmDeltaChrom', type=np.float64,
601 doc=
'Mean chromatic correction for stars in this ccd; '
602 'only for fgcmFlag <= 4 (see fgcmFlag)')
603 zptSchema.addField(
'fgcmZptVar', type=np.float64, doc=
'Variance of zeropoint over ccd')
604 zptSchema.addField(
'fgcmTilings', type=np.float64,
605 doc=
'Number of photometric tilings used for solution for ccd')
606 zptSchema.addField(
'fgcmFpGry', type=np.float64,
607 doc=
'Average gray extinction over the full focal plane '
608 '(same for all ccds in a visit)')
609 zptSchema.addField(
'fgcmFpGryBlue', type=np.float64,
610 doc=
'Average gray extinction over the full focal plane '
611 'for 25% bluest stars')
612 zptSchema.addField(
'fgcmFpGryBlueErr', type=np.float64,
613 doc=
'Error on Average gray extinction over the full focal plane '
614 'for 25% bluest stars')
615 zptSchema.addField(
'fgcmFpGryRed', type=np.float64,
616 doc=
'Average gray extinction over the full focal plane '
617 'for 25% reddest stars')
618 zptSchema.addField(
'fgcmFpGryRedErr', type=np.float64,
619 doc=
'Error on Average gray extinction over the full focal plane '
620 'for 25% reddest stars')
621 zptSchema.addField(
'fgcmFpVar', type=np.float64,
622 doc=
'Variance of gray extinction over the full focal plane '
623 '(same for all ccds in a visit)')
624 zptSchema.addField(
'fgcmDust', type=np.float64,
625 doc=
'Gray dust extinction from the primary/corrector'
626 'at the time of the exposure')
627 zptSchema.addField(
'fgcmFlat', type=np.float64, doc=
'Superstarflat illumination correction')
628 zptSchema.addField(
'fgcmAperCorr', type=np.float64, doc=
'Aperture correction estimated by fgcm')
629 zptSchema.addField(
'fgcmDeltaMagBkg', type=np.float64,
630 doc=(
'Local background correction from brightest percentile '
631 '(value set by deltaMagBkgOffsetPercentile) calibration '
633 zptSchema.addField(
'exptime', type=np.float32, doc=
'Exposure time')
634 zptSchema.addField(
'filtername', type=str, size=10, doc=
'Filter name')
641 Make the zeropoint catalog for persistence
645 zptSchema: `lsst.afw.table.Schema`
646 Zeropoint catalog schema
647 zpStruct: `numpy.ndarray`
648 Zeropoint structure
from fgcm
652 zptCat: `afwTable.BaseCatalog`
653 Zeropoint catalog
for persistence
656 zptCat = afwTable.BaseCatalog(zptSchema)
657 zptCat.reserve(zpStruct.size)
659 for filterName
in zpStruct[
'FILTERNAME']:
660 rec = zptCat.addNew()
661 rec[
'filtername'] = filterName.decode(
'utf-8')
663 zptCat[
'visit'][:] = zpStruct[FGCM_EXP_FIELD]
664 zptCat[
'detector'][:] = zpStruct[FGCM_CCD_FIELD]
665 zptCat[
'fgcmFlag'][:] = zpStruct[
'FGCM_FLAG']
666 zptCat[
'fgcmZpt'][:] = zpStruct[
'FGCM_ZPT']
667 zptCat[
'fgcmZptErr'][:] = zpStruct[
'FGCM_ZPTERR']
668 zptCat[
'fgcmfZptChebXyMax'][:, :] = zpStruct[
'FGCM_FZPT_XYMAX']
669 zptCat[
'fgcmfZptCheb'][:, :] = zpStruct[
'FGCM_FZPT_CHEB']
670 zptCat[
'fgcmfZptSstarCheb'][:, :] = zpStruct[
'FGCM_FZPT_SSTAR_CHEB']
671 zptCat[
'fgcmI0'][:] = zpStruct[
'FGCM_I0']
672 zptCat[
'fgcmI10'][:] = zpStruct[
'FGCM_I10']
673 zptCat[
'fgcmR0'][:] = zpStruct[
'FGCM_R0']
674 zptCat[
'fgcmR10'][:] = zpStruct[
'FGCM_R10']
675 zptCat[
'fgcmGry'][:] = zpStruct[
'FGCM_GRY']
676 zptCat[
'fgcmDeltaChrom'][:] = zpStruct[
'FGCM_DELTACHROM']
677 zptCat[
'fgcmZptVar'][:] = zpStruct[
'FGCM_ZPTVAR']
678 zptCat[
'fgcmTilings'][:] = zpStruct[
'FGCM_TILINGS']
679 zptCat[
'fgcmFpGry'][:] = zpStruct[
'FGCM_FPGRY']
680 zptCat[
'fgcmFpGryBlue'][:] = zpStruct[
'FGCM_FPGRY_CSPLIT'][:, 0]
681 zptCat[
'fgcmFpGryBlueErr'][:] = zpStruct[
'FGCM_FPGRY_CSPLITERR'][:, 0]
682 zptCat[
'fgcmFpGryRed'][:] = zpStruct[
'FGCM_FPGRY_CSPLIT'][:, 2]
683 zptCat[
'fgcmFpGryRedErr'][:] = zpStruct[
'FGCM_FPGRY_CSPLITERR'][:, 2]
684 zptCat[
'fgcmFpVar'][:] = zpStruct[
'FGCM_FPVAR']
685 zptCat[
'fgcmDust'][:] = zpStruct[
'FGCM_DUST']
686 zptCat[
'fgcmFlat'][:] = zpStruct[
'FGCM_FLAT']
687 zptCat[
'fgcmAperCorr'][:] = zpStruct[
'FGCM_APERCORR']
688 zptCat[
'fgcmDeltaMagBkg'][:] = zpStruct[
'FGCM_DELTAMAGBKG']
689 zptCat[
'exptime'][:] = zpStruct[
'EXPTIME']
696 Make the atmosphere schema
700 atmSchema: `lsst.afw.table.Schema`
703 atmSchema = afwTable.Schema()
705 atmSchema.addField('visit', type=np.int32, doc=
'Visit number')
706 atmSchema.addField(
'pmb', type=np.float64, doc=
'Barometric pressure (mb)')
707 atmSchema.addField(
'pwv', type=np.float64, doc=
'Water vapor (mm)')
708 atmSchema.addField(
'tau', type=np.float64, doc=
'Aerosol optical depth')
709 atmSchema.addField(
'alpha', type=np.float64, doc=
'Aerosol slope')
710 atmSchema.addField(
'o3', type=np.float64, doc=
'Ozone (dobson)')
711 atmSchema.addField(
'secZenith', type=np.float64, doc=
'Secant(zenith) (~ airmass)')
712 atmSchema.addField(
'cTrans', type=np.float64, doc=
'Transmission correction factor')
713 atmSchema.addField(
'lamStd', type=np.float64, doc=
'Wavelength for transmission correction')
720 Make the atmosphere catalog for persistence
724 atmSchema: `lsst.afw.table.Schema`
725 Atmosphere catalog schema
726 atmStruct: `numpy.ndarray`
727 Atmosphere structure
from fgcm
731 atmCat: `lsst.afw.table.BaseCatalog`
732 Atmosphere catalog
for persistence
735 atmCat = afwTable.BaseCatalog(atmSchema)
736 atmCat.resize(atmStruct.size)
738 atmCat['visit'][:] = atmStruct[
'VISIT']
739 atmCat[
'pmb'][:] = atmStruct[
'PMB']
740 atmCat[
'pwv'][:] = atmStruct[
'PWV']
741 atmCat[
'tau'][:] = atmStruct[
'TAU']
742 atmCat[
'alpha'][:] = atmStruct[
'ALPHA']
743 atmCat[
'o3'][:] = atmStruct[
'O3']
744 atmCat[
'secZenith'][:] = atmStruct[
'SECZENITH']
745 atmCat[
'cTrans'][:] = atmStruct[
'CTRANS']
746 atmCat[
'lamStd'][:] = atmStruct[
'LAMSTD']
753 Make the standard star schema
758 Number of bands in standard star catalog
762 stdSchema: `lsst.afw.table.Schema`
765 stdSchema = afwTable.SimpleTable.makeMinimalSchema()
766 stdSchema.addField('ngood', type=
'ArrayI', doc=
'Number of good observations',
768 stdSchema.addField(
'ntotal', type=
'ArrayI', doc=
'Number of total observations',
770 stdSchema.addField(
'mag_std_noabs', type=
'ArrayF',
771 doc=
'Standard magnitude (no absolute calibration)',
773 stdSchema.addField(
'magErr_std', type=
'ArrayF',
774 doc=
'Standard magnitude error',
776 stdSchema.addField(
'npsfcand', type=
'ArrayI',
777 doc=
'Number of observations flagged as psf candidates',
779 stdSchema.addField(
'delta_aper', type=
'ArrayF',
780 doc=
'Delta mag (small - large aperture)',
788 Make the standard star catalog for persistence
792 stdSchema: `lsst.afw.table.Schema`
793 Standard star catalog schema
794 stdStruct: `numpy.ndarray`
795 Standard star structure
in FGCM format
797 List of good band names used
in stdStruct
801 stdCat: `lsst.afw.table.BaseCatalog`
802 Standard star catalog
for persistence
805 stdCat = afwTable.SimpleCatalog(stdSchema)
806 stdCat.resize(stdStruct.size)
808 stdCat['id'][:] = stdStruct[
'FGCM_ID']
809 stdCat[
'coord_ra'][:] = stdStruct[
'RA'] * geom.degrees
810 stdCat[
'coord_dec'][:] = stdStruct[
'DEC'] * geom.degrees
811 stdCat[
'ngood'][:, :] = stdStruct[
'NGOOD'][:, :]
812 stdCat[
'ntotal'][:, :] = stdStruct[
'NTOTAL'][:, :]
813 stdCat[
'mag_std_noabs'][:, :] = stdStruct[
'MAG_STD'][:, :]
814 stdCat[
'magErr_std'][:, :] = stdStruct[
'MAGERR_STD'][:, :]
815 stdCat[
'npsfcand'][:, :] = stdStruct[
'NPSFCAND'][:, :]
816 stdCat[
'delta_aper'][:, :] = stdStruct[
'DELTA_APER'][:, :]
819 md.set(
"BANDS", list(goodBands))
820 stdCat.setMetadata(md)
827 Compute the radius associated with a CircularApertureFlux
or ApFlux field.
832 CircularApertureFlux
or ApFlux
836 apertureRadius : `float`
837 Radius of the aperture field,
in pixels.
841 RuntimeError: Raised
if flux field
is not a CircularApertureFlux,
845 m = re.search(
r'(CircularApertureFlux|ApFlux|apFlux)_(\d+)_(\d+)_', fluxField)
848 raise RuntimeError(f
"Flux field {fluxField} does not correspond to a CircularApertureFlux or ApFlux")
850 apertureRadius = float(m.groups()[1]) + float(m.groups()[2])/10.
852 return apertureRadius
857 Extract reference magnitudes from refStars
for given bands
and
858 associated filterMap.
862 refStars : `lsst.afw.table.BaseCatalog`
863 FGCM reference star catalog
865 List of bands
for calibration
867 FGCM mapping of filter to band
871 refMag : `np.ndarray`
872 nstar x nband array of reference magnitudes
873 refMagErr : `np.ndarray`
874 nstar x nband array of reference magnitude errors
880 md = refStars.getMetadata()
881 if 'FILTERNAMES' in md:
882 filternames = md.getArray(
'FILTERNAMES')
886 refMag = np.zeros((len(refStars), len(bands)),
887 dtype=refStars[
'refMag'].dtype) + 99.0
888 refMagErr = np.zeros_like(refMag) + 99.0
889 for i, filtername
in enumerate(filternames):
893 band = filterMap[filtername]
897 ind = bands.index(band)
901 refMag[:, ind] = refStars[
'refMag'][:, i]
902 refMagErr[:, ind] = refStars[
'refMagErr'][:, i]
906 refMag = refStars[
'refMag'][:, :]
907 refMagErr = refStars[
'refMagErr'][:, :]
909 return refMag, refMagErr
913 instrument = Instrument.fromName(quantumDataId[
"instrument"], registry)
914 unboundedCollection = instrument.makeUnboundedCalibrationRunName()
916 return registry.queryDatasets(datasetType,
917 dataId=quantumDataId,
918 collections=[unboundedCollection])
def extractReferenceMags(refStars, bands, filterMap)
def lookupStaticCalibrations(datasetType, registry, quantumDataId, collections)
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)