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.
30 from deprecated.sphinx
import deprecated
45 FGCM_EXP_FIELD =
'VISIT'
46 FGCM_CCD_FIELD =
'DETECTOR'
47 FGCM_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`
357 FGCM visitCat from `lsst.fgcmcal.FgcmBuildStarsTask`
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.",
version="v23.0", category=FutureWarning)
404 Compute the CCD offsets in ra/dec and x/y space
408 camera: `lsst.afw.cameraGeom.Camera`
409 defaultOrientation: `float`
410 Default camera orientation (degrees)
414 ccdOffsets: `numpy.ndarray`
415 Numpy array with ccd offset information for input to FGCM.
416 Angular units are degrees, and x/y units are pixels.
421 ccdOffsets = np.zeros(len(camera), dtype=[(
'CCDNUM',
'i4'),
436 if camera.getName() ==
'HSC' and np.isnan(defaultOrientation):
437 orientation = 270*geom.degrees
439 orientation = defaultOrientation*geom.degrees
444 boresightRotAngle=orientation,
445 rotType=afwImage.RotType.SKY)
447 for i, detector
in enumerate(camera):
448 ccdOffsets[
'CCDNUM'][i] = detector.getId()
450 wcs = createInitialSkyWcs(visitInfo, detector, flipX)
452 detCenter = wcs.pixelToSky(detector.getCenter(afwCameraGeom.PIXELS))
453 ccdOffsets[
'DELTA_RA'][i] = (detCenter.getRa() - boresight.getRa()).asDegrees()
454 ccdOffsets[
'DELTA_DEC'][i] = (detCenter.getDec() - boresight.getDec()).asDegrees()
456 bbox = detector.getBBox()
458 detCorner1 = wcs.pixelToSky(
geom.Point2D(bbox.getMin()))
459 detCorner2 = wcs.pixelToSky(
geom.Point2D(bbox.getMax()))
461 ccdOffsets[
'RA_SIZE'][i] = np.abs((detCorner2.getRa() - detCorner1.getRa()).asDegrees())
462 ccdOffsets[
'DEC_SIZE'][i] = np.abs((detCorner2.getDec() - detCorner1.getDec()).asDegrees())
464 ccdOffsets[
'X_SIZE'][i] = bbox.getMaxX()
465 ccdOffsets[
'Y_SIZE'][i] = bbox.getMaxY()
472 Compute the median pixel scale in the camera
477 Average pixel scale (arcsecond) over the camera
481 orientation = 0.0*geom.degrees
486 boresightRotAngle=orientation,
487 rotType=afwImage.RotType.SKY)
489 pixelScales = np.zeros(len(camera))
490 for i, detector
in enumerate(camera):
491 wcs = createInitialSkyWcs(visitInfo, detector, flipX)
492 pixelScales[i] = wcs.getPixelScale().asArcseconds()
494 ok, = np.where(pixelScales > 0.0)
495 return np.median(pixelScales[ok])
500 Compute the approximate pixel area bounded fields from the camera
505 camera: `lsst.afw.cameraGeom.Camera`
509 approxPixelAreaFields: `dict`
510 Dictionary of approximate area fields, keyed with detector ID
523 boresightRotAngle=0.0*geom.degrees,
524 rotType=afwImage.RotType.SKY)
526 approxPixelAreaFields = {}
528 for i, detector
in enumerate(camera):
529 key = detector.getId()
531 wcs = createInitialSkyWcs(visitInfo, detector, flipX)
532 bbox = detector.getBBox()
535 unit=geom.arcseconds, scaling=areaScaling)
536 approxAreaField = afwMath.ChebyshevBoundedField.approximate(areaField)
538 approxPixelAreaFields[key] = approxAreaField
540 return approxPixelAreaFields
545 Make the zeropoint schema
549 superStarChebyshevSize: `int`
550 Length of the superstar chebyshev array
551 zptChebyshevSize: `int`
552 Length of the zeropoint chebyshev array
556 zptSchema: `lsst.afw.table.schema`
561 zptSchema.addField(
'visit', type=np.int32, doc=
'Visit number')
562 zptSchema.addField(
'detector', type=np.int32, doc=
'Detector ID number')
563 zptSchema.addField(
'fgcmFlag', type=np.int32, doc=(
'FGCM flag value: '
564 '1: Photometric, used in fit; '
565 '2: Photometric, not used in fit; '
566 '4: Non-photometric, on partly photometric night; '
567 '8: Non-photometric, on non-photometric night; '
568 '16: No zeropoint could be determined; '
569 '32: Too few stars for reliable gray computation'))
570 zptSchema.addField(
'fgcmZpt', type=np.float64, doc=
'FGCM zeropoint (center of CCD)')
571 zptSchema.addField(
'fgcmZptErr', type=np.float64,
572 doc=
'Error on zeropoint, estimated from repeatability + number of obs')
573 zptSchema.addField(
'fgcmfZptChebXyMax', type=
'ArrayD', size=2,
574 doc=
'maximum x/maximum y to scale to apply chebyshev parameters')
575 zptSchema.addField(
'fgcmfZptCheb', type=
'ArrayD',
576 size=zptChebyshevSize,
577 doc=
'Chebyshev parameters (flattened) for zeropoint')
578 zptSchema.addField(
'fgcmfZptSstarCheb', type=
'ArrayD',
579 size=superStarChebyshevSize,
580 doc=
'Chebyshev parameters (flattened) for superStarFlat')
581 zptSchema.addField(
'fgcmI0', type=np.float64, doc=
'Integral of the passband')
582 zptSchema.addField(
'fgcmI10', type=np.float64, doc=
'Normalized chromatic integral')
583 zptSchema.addField(
'fgcmR0', type=np.float64,
584 doc=
'Retrieved i0 integral, estimated from stars (only for flag 1)')
585 zptSchema.addField(
'fgcmR10', type=np.float64,
586 doc=
'Retrieved i10 integral, estimated from stars (only for flag 1)')
587 zptSchema.addField(
'fgcmGry', type=np.float64,
588 doc=
'Estimated gray extinction relative to atmospheric solution; '
589 'only for fgcmFlag <= 4 (see fgcmFlag) ')
590 zptSchema.addField(
'fgcmDeltaChrom', type=np.float64,
591 doc=
'Mean chromatic correction for stars in this ccd; '
592 'only for fgcmFlag <= 4 (see fgcmFlag)')
593 zptSchema.addField(
'fgcmZptVar', type=np.float64, doc=
'Variance of zeropoint over ccd')
594 zptSchema.addField(
'fgcmTilings', type=np.float64,
595 doc=
'Number of photometric tilings used for solution for ccd')
596 zptSchema.addField(
'fgcmFpGry', type=np.float64,
597 doc=
'Average gray extinction over the full focal plane '
598 '(same for all ccds in a visit)')
599 zptSchema.addField(
'fgcmFpGryBlue', type=np.float64,
600 doc=
'Average gray extinction over the full focal plane '
601 'for 25% bluest stars')
602 zptSchema.addField(
'fgcmFpGryBlueErr', type=np.float64,
603 doc=
'Error on Average gray extinction over the full focal plane '
604 'for 25% bluest stars')
605 zptSchema.addField(
'fgcmFpGryRed', type=np.float64,
606 doc=
'Average gray extinction over the full focal plane '
607 'for 25% reddest stars')
608 zptSchema.addField(
'fgcmFpGryRedErr', type=np.float64,
609 doc=
'Error on Average gray extinction over the full focal plane '
610 'for 25% reddest stars')
611 zptSchema.addField(
'fgcmFpVar', type=np.float64,
612 doc=
'Variance of gray extinction over the full focal plane '
613 '(same for all ccds in a visit)')
614 zptSchema.addField(
'fgcmDust', type=np.float64,
615 doc=
'Gray dust extinction from the primary/corrector'
616 'at the time of the exposure')
617 zptSchema.addField(
'fgcmFlat', type=np.float64, doc=
'Superstarflat illumination correction')
618 zptSchema.addField(
'fgcmAperCorr', type=np.float64, doc=
'Aperture correction estimated by fgcm')
619 zptSchema.addField(
'fgcmDeltaMagBkg', type=np.float64,
620 doc=(
'Local background correction from brightest percentile '
621 '(value set by deltaMagBkgOffsetPercentile) calibration '
623 zptSchema.addField(
'exptime', type=np.float32, doc=
'Exposure time')
624 zptSchema.addField(
'filtername', type=str, size=10, doc=
'Filter name')
631 Make the zeropoint catalog for persistence
635 zptSchema: `lsst.afw.table.Schema`
636 Zeropoint catalog schema
637 zpStruct: `numpy.ndarray`
638 Zeropoint structure from fgcm
642 zptCat: `afwTable.BaseCatalog`
643 Zeropoint catalog for persistence
647 zptCat.reserve(zpStruct.size)
649 for filterName
in zpStruct[
'FILTERNAME']:
650 rec = zptCat.addNew()
651 rec[
'filtername'] = filterName.decode(
'utf-8')
653 zptCat[
'visit'][:] = zpStruct[FGCM_EXP_FIELD]
654 zptCat[
'detector'][:] = zpStruct[FGCM_CCD_FIELD]
655 zptCat[
'fgcmFlag'][:] = zpStruct[
'FGCM_FLAG']
656 zptCat[
'fgcmZpt'][:] = zpStruct[
'FGCM_ZPT']
657 zptCat[
'fgcmZptErr'][:] = zpStruct[
'FGCM_ZPTERR']
658 zptCat[
'fgcmfZptChebXyMax'][:, :] = zpStruct[
'FGCM_FZPT_XYMAX']
659 zptCat[
'fgcmfZptCheb'][:, :] = zpStruct[
'FGCM_FZPT_CHEB']
660 zptCat[
'fgcmfZptSstarCheb'][:, :] = zpStruct[
'FGCM_FZPT_SSTAR_CHEB']
661 zptCat[
'fgcmI0'][:] = zpStruct[
'FGCM_I0']
662 zptCat[
'fgcmI10'][:] = zpStruct[
'FGCM_I10']
663 zptCat[
'fgcmR0'][:] = zpStruct[
'FGCM_R0']
664 zptCat[
'fgcmR10'][:] = zpStruct[
'FGCM_R10']
665 zptCat[
'fgcmGry'][:] = zpStruct[
'FGCM_GRY']
666 zptCat[
'fgcmDeltaChrom'][:] = zpStruct[
'FGCM_DELTACHROM']
667 zptCat[
'fgcmZptVar'][:] = zpStruct[
'FGCM_ZPTVAR']
668 zptCat[
'fgcmTilings'][:] = zpStruct[
'FGCM_TILINGS']
669 zptCat[
'fgcmFpGry'][:] = zpStruct[
'FGCM_FPGRY']
670 zptCat[
'fgcmFpGryBlue'][:] = zpStruct[
'FGCM_FPGRY_CSPLIT'][:, 0]
671 zptCat[
'fgcmFpGryBlueErr'][:] = zpStruct[
'FGCM_FPGRY_CSPLITERR'][:, 0]
672 zptCat[
'fgcmFpGryRed'][:] = zpStruct[
'FGCM_FPGRY_CSPLIT'][:, 2]
673 zptCat[
'fgcmFpGryRedErr'][:] = zpStruct[
'FGCM_FPGRY_CSPLITERR'][:, 2]
674 zptCat[
'fgcmFpVar'][:] = zpStruct[
'FGCM_FPVAR']
675 zptCat[
'fgcmDust'][:] = zpStruct[
'FGCM_DUST']
676 zptCat[
'fgcmFlat'][:] = zpStruct[
'FGCM_FLAT']
677 zptCat[
'fgcmAperCorr'][:] = zpStruct[
'FGCM_APERCORR']
678 zptCat[
'fgcmDeltaMagBkg'][:] = zpStruct[
'FGCM_DELTAMAGBKG']
679 zptCat[
'exptime'][:] = zpStruct[
'EXPTIME']
686 Make the atmosphere schema
690 atmSchema: `lsst.afw.table.Schema`
695 atmSchema.addField(
'visit', type=np.int32, doc=
'Visit number')
696 atmSchema.addField(
'pmb', type=np.float64, doc=
'Barometric pressure (mb)')
697 atmSchema.addField(
'pwv', type=np.float64, doc=
'Water vapor (mm)')
698 atmSchema.addField(
'tau', type=np.float64, doc=
'Aerosol optical depth')
699 atmSchema.addField(
'alpha', type=np.float64, doc=
'Aerosol slope')
700 atmSchema.addField(
'o3', type=np.float64, doc=
'Ozone (dobson)')
701 atmSchema.addField(
'secZenith', type=np.float64, doc=
'Secant(zenith) (~ airmass)')
702 atmSchema.addField(
'cTrans', type=np.float64, doc=
'Transmission correction factor')
703 atmSchema.addField(
'lamStd', type=np.float64, doc=
'Wavelength for transmission correction')
710 Make the atmosphere catalog for persistence
714 atmSchema: `lsst.afw.table.Schema`
715 Atmosphere catalog schema
716 atmStruct: `numpy.ndarray`
717 Atmosphere structure from fgcm
721 atmCat: `lsst.afw.table.BaseCatalog`
722 Atmosphere catalog for persistence
726 atmCat.resize(atmStruct.size)
728 atmCat[
'visit'][:] = atmStruct[
'VISIT']
729 atmCat[
'pmb'][:] = atmStruct[
'PMB']
730 atmCat[
'pwv'][:] = atmStruct[
'PWV']
731 atmCat[
'tau'][:] = atmStruct[
'TAU']
732 atmCat[
'alpha'][:] = atmStruct[
'ALPHA']
733 atmCat[
'o3'][:] = atmStruct[
'O3']
734 atmCat[
'secZenith'][:] = atmStruct[
'SECZENITH']
735 atmCat[
'cTrans'][:] = atmStruct[
'CTRANS']
736 atmCat[
'lamStd'][:] = atmStruct[
'LAMSTD']
743 Make the standard star schema
748 Number of bands in standard star catalog
752 stdSchema: `lsst.afw.table.Schema`
755 stdSchema = afwTable.SimpleTable.makeMinimalSchema()
756 stdSchema.addField(
'ngood', type=
'ArrayI', doc=
'Number of good observations',
758 stdSchema.addField(
'ntotal', type=
'ArrayI', doc=
'Number of total observations',
760 stdSchema.addField(
'mag_std_noabs', type=
'ArrayF',
761 doc=
'Standard magnitude (no absolute calibration)',
763 stdSchema.addField(
'magErr_std', type=
'ArrayF',
764 doc=
'Standard magnitude error',
766 stdSchema.addField(
'npsfcand', type=
'ArrayI',
767 doc=
'Number of observations flagged as psf candidates',
773 def makeStdCat(stdSchema, stdStruct, goodBands):
775 Make the standard star catalog for persistence
779 stdSchema: `lsst.afw.table.Schema`
780 Standard star catalog schema
781 stdStruct: `numpy.ndarray`
782 Standard star structure in FGCM format
784 List of good band names used in stdStruct
788 stdCat: `lsst.afw.table.BaseCatalog`
789 Standard star catalog for persistence
793 stdCat.resize(stdStruct.size)
795 stdCat[
'id'][:] = stdStruct[
'FGCM_ID']
796 stdCat[
'coord_ra'][:] = stdStruct[
'RA'] * geom.degrees
797 stdCat[
'coord_dec'][:] = stdStruct[
'DEC'] * geom.degrees
798 stdCat[
'ngood'][:, :] = stdStruct[
'NGOOD'][:, :]
799 stdCat[
'ntotal'][:, :] = stdStruct[
'NTOTAL'][:, :]
800 stdCat[
'mag_std_noabs'][:, :] = stdStruct[
'MAG_STD'][:, :]
801 stdCat[
'magErr_std'][:, :] = stdStruct[
'MAGERR_STD'][:, :]
802 stdCat[
'npsfcand'][:, :] = stdStruct[
'NPSFCAND'][:, :]
805 md.set(
"BANDS",
list(goodBands))
806 stdCat.setMetadata(md)
813 Compute the radius associated with a CircularApertureFlux field or
818 dataRef : `lsst.daf.persistence.ButlerDataRef` or
819 `lsst.daf.butler.DeferredDatasetHandle`
821 CircularApertureFlux or associated slot.
825 apertureRadius : `float`
826 Radius of the aperture field, in pixels.
830 RuntimeError: Raised if flux field is not a CircularApertureFlux, ApFlux,
831 apFlux, or associated slot.
836 datasetType = dataRef.butlerSubset.datasetType
839 datasetType = dataRef.ref.datasetType.name
841 if datasetType ==
'src':
842 schema = dataRef.get(datasetType=
'src_schema').schema
844 fluxFieldName = schema[fluxField].asField().
getName()
846 raise RuntimeError(
"Could not find %s or associated slot in schema." % (fluxField))
853 return apertureRadius
858 Compute the radius associated with a CircularApertureFlux or ApFlux field.
863 CircularApertureFlux or ApFlux
867 apertureRadius : `float`
868 Radius of the aperture field, in pixels.
872 RuntimeError: Raised if flux field is not a CircularApertureFlux,
876 m = re.search(
r'(CircularApertureFlux|ApFlux|apFlux)_(\d+)_(\d+)_', fluxField)
879 raise RuntimeError(f
"Flux field {fluxField} does not correspond to a CircularApertureFlux or ApFlux")
881 apertureRadius = float(m.groups()[1]) + float(m.groups()[2])/10.
883 return apertureRadius
888 Extract reference magnitudes from refStars for given bands and
889 associated filterMap.
893 refStars : `lsst.afw.table.BaseCatalog`
894 FGCM reference star catalog
896 List of bands for calibration
898 FGCM mapping of filter to band
902 refMag : `np.ndarray`
903 nstar x nband array of reference magnitudes
904 refMagErr : `np.ndarray`
905 nstar x nband array of reference magnitude errors
911 md = refStars.getMetadata()
912 if 'FILTERNAMES' in md:
913 filternames = md.getArray(
'FILTERNAMES')
917 refMag = np.zeros((len(refStars), len(bands)),
918 dtype=refStars[
'refMag'].dtype) + 99.0
919 refMagErr = np.zeros_like(refMag) + 99.0
920 for i, filtername
in enumerate(filternames):
924 band = filterMap[filtername]
928 ind = bands.index(band)
932 refMag[:, ind] = refStars[
'refMag'][:, i]
933 refMagErr[:, ind] = refStars[
'refMagErr'][:, i]
937 refMag = refStars[
'refMag'][:, :]
938 refMagErr = refStars[
'refMagErr'][:, :]
940 return refMag, refMagErr
944 instrument = Instrument.fromName(quantumDataId[
"instrument"], registry)
945 unboundedCollection = instrument.makeUnboundedCalibrationRunName()
947 return registry.queryDatasets(datasetType,
948 dataId=quantumDataId,
949 collections=[unboundedCollection])
950 Information about a single exposure of an imaging camera.
A BoundedField that evaluate the pixel area of a SkyWcs in angular units.
Defines the fields and offsets for a table.
Custom catalog class for record/table subclasses that are guaranteed to have an ID,...
Class for storing ordered metadata with comments.
Point in an unspecified spherical coordinate system.
daf::base::PropertyList * list
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
std::string const & getName() const noexcept
Return a filter's name.
def extractReferenceMags(refStars, bands, filterMap)
def lookupStaticCalibrations(datasetType, registry, quantumDataId, collections)
def computeApertureRadiusFromDataRef(dataRef, fluxField)
def makeStdSchema(nBands)
def makeAtmCat(atmSchema, atmStruct)
def makeConfigDict(config, log, camera, maxIter, resetFitParameters, outputZeropoints, lutFilterNames, tract=None)
def translateFgcmLut(lutCat, physicalFilterMap)
def computeReferencePixelScale(camera)
def makeZptCat(zptSchema, zpStruct)
def makeStdCat(stdSchema, stdStruct, goodBands)
def computeApertureRadiusFromName(fluxField)
def computeApproxPixelAreaFields(camera)
def makeZptSchema(superStarChebyshevSize, zptChebyshevSize)
def computeCcdOffsets(camera, defaultOrientation)
def translateVisitCatalog(visitCat)