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
38from lsst.obs.base
import createInitialSkyWcs
44FGCM_EXP_FIELD =
'VISIT'
45FGCM_CCD_FIELD =
'DETECTOR'
46FGCM_ILLEGAL_VALUE = -9999.0
49def makeConfigDict(config, log, camera, maxIter,
50 resetFitParameters, outputZeropoints,
51 lutFilterNames, tract=None):
53 Make the FGCM fit cycle configuration dict
57 config: `lsst.fgcmcal.FgcmFitCycleConfig`
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:
89 parts = ccut.split(
',')
90 starColorCutList.append([parts[0], parts[1], float(parts[2]), float(parts[3])])
93 refStarColorCutList = []
94 for ccut
in config.refStarColorCuts:
98 parts = ccut.split(
',')
99 refStarColorCutList.append([parts[0], parts[1], float(parts[2]), float(parts[3])])
104 mirrorArea = np.pi*(camera.telescopeDiameter*100./2.)**2.
107 gains = [amp.getGain()
for detector
in camera
for amp
in detector.getAmplifiers()]
108 cameraGain = float(np.median(gains))
111 filterToBand = {filterName: config.physicalFilterMap[filterName]
for
112 filterName
in lutFilterNames}
115 outfileBase = config.outfileBase
117 outfileBase =
'%s-%06d' % (config.outfileBase, tract)
120 configDict = {
'outfileBase': outfileBase,
122 'exposureFile':
None,
126 'mirrorArea': mirrorArea,
127 'cameraGain': cameraGain,
128 'ccdStartIndex': camera[0].getId(),
129 'expField': FGCM_EXP_FIELD,
130 'ccdField': FGCM_CCD_FIELD,
131 'seeingField':
'DELTA_APER',
132 'fwhmField':
'PSFSIGMA',
133 'skyBrightnessField':
'SKYBACKGROUND',
134 'deepFlag':
'DEEPFLAG',
135 'bands':
list(config.bands),
136 'fitBands':
list(config.fitBands),
137 'notFitBands': notFitBands,
138 'requiredBands':
list(config.requiredBands),
139 'filterToBand': filterToBand,
141 'nCore': config.nCore,
142 'nStarPerRun': config.nStarPerRun,
143 'nExpPerRun': config.nExpPerRun,
144 'reserveFraction': config.reserveFraction,
145 'freezeStdAtmosphere': config.freezeStdAtmosphere,
146 'precomputeSuperStarInitialCycle': config.precomputeSuperStarInitialCycle,
147 'superStarSubCCDDict': dict(config.superStarSubCcdDict),
148 'superStarSubCCDChebyshevOrder': config.superStarSubCcdChebyshevOrder,
149 'superStarSubCCDTriangular': config.superStarSubCcdTriangular,
150 'superStarSigmaClip': config.superStarSigmaClip,
151 'focalPlaneSigmaClip': config.focalPlaneSigmaClip,
152 'ccdGraySubCCDDict': dict(config.ccdGraySubCcdDict),
153 'ccdGraySubCCDChebyshevOrder': config.ccdGraySubCcdChebyshevOrder,
154 'ccdGraySubCCDTriangular': config.ccdGraySubCcdTriangular,
155 'ccdGrayFocalPlaneDict': dict(config.ccdGrayFocalPlaneDict),
156 'ccdGrayFocalPlaneChebyshevOrder': config.ccdGrayFocalPlaneChebyshevOrder,
157 'ccdGrayFocalPlaneFitMinCcd': config.ccdGrayFocalPlaneFitMinCcd,
158 'cycleNumber': config.cycleNumber,
160 'deltaMagBkgOffsetPercentile': config.deltaMagBkgOffsetPercentile,
161 'deltaMagBkgPerCcd': config.deltaMagBkgPerCcd,
162 'UTBoundary': config.utBoundary,
163 'washMJDs': config.washMjds,
164 'epochMJDs': config.epochMjds,
165 'coatingMJDs': config.coatingMjds,
166 'minObsPerBand': config.minObsPerBand,
167 'latitude': config.latitude,
168 'defaultCameraOrientation': config.defaultCameraOrientation,
169 'brightObsGrayMax': config.brightObsGrayMax,
170 'minStarPerCCD': config.minStarPerCcd,
171 'minCCDPerExp': config.minCcdPerExp,
172 'maxCCDGrayErr': config.maxCcdGrayErr,
173 'minStarPerExp': config.minStarPerExp,
174 'minExpPerNight': config.minExpPerNight,
175 'expGrayInitialCut': config.expGrayInitialCut,
176 'expGrayPhotometricCutDict': dict(config.expGrayPhotometricCutDict),
177 'expGrayHighCutDict': dict(config.expGrayHighCutDict),
178 'expGrayRecoverCut': config.expGrayRecoverCut,
179 'expVarGrayPhotometricCutDict': dict(config.expVarGrayPhotometricCutDict),
180 'expGrayErrRecoverCut': config.expGrayErrRecoverCut,
181 'refStarSnMin': config.refStarSnMin,
182 'refStarOutlierNSig': config.refStarOutlierNSig,
183 'applyRefStarColorCuts': config.applyRefStarColorCuts,
184 'useExposureReferenceOffset': config.useExposureReferenceOffset,
185 'illegalValue': FGCM_ILLEGAL_VALUE,
186 'starColorCuts': starColorCutList,
187 'refStarColorCuts': refStarColorCutList,
188 'aperCorrFitNBins': config.aperCorrFitNBins,
189 'aperCorrInputSlopeDict': dict(config.aperCorrInputSlopeDict),
190 'sedBoundaryTermDict': config.sedboundaryterms.toDict()[
'data'],
191 'sedTermDict': config.sedterms.toDict()[
'data'],
192 'colorSplitBands':
list(config.colorSplitBands),
193 'sigFgcmMaxErr': config.sigFgcmMaxErr,
194 'sigFgcmMaxEGrayDict': dict(config.sigFgcmMaxEGrayDict),
195 'ccdGrayMaxStarErr': config.ccdGrayMaxStarErr,
196 'approxThroughputDict': dict(config.approxThroughputDict),
197 'sigmaCalRange':
list(config.sigmaCalRange),
198 'sigmaCalFitPercentile':
list(config.sigmaCalFitPercentile),
199 'sigmaCalPlotPercentile':
list(config.sigmaCalPlotPercentile),
200 'sigma0Phot': config.sigma0Phot,
201 'mapLongitudeRef': config.mapLongitudeRef,
202 'mapNSide': config.mapNSide,
205 'useRetrievedPwv':
False,
206 'useNightlyRetrievedPwv':
False,
207 'pwvRetrievalSmoothBlock': 25,
208 'useQuadraticPwv': config.useQuadraticPwv,
209 'useRetrievedTauInit':
False,
210 'tauRetrievalMinCCDPerNight': 500,
211 'modelMagErrors': config.modelMagErrors,
212 'instrumentParsPerBand': config.instrumentParsPerBand,
213 'instrumentSlopeMinDeltaT': config.instrumentSlopeMinDeltaT,
214 'fitMirrorChromaticity': config.fitMirrorChromaticity,
215 'useRepeatabilityForExpGrayCutsDict': dict(config.useRepeatabilityForExpGrayCutsDict),
216 'autoPhotometricCutNSig': config.autoPhotometricCutNSig,
217 'autoHighCutNSig': config.autoHighCutNSig,
218 'deltaAperInnerRadiusArcsec': config.deltaAperInnerRadiusArcsec,
219 'deltaAperOuterRadiusArcsec': config.deltaAperOuterRadiusArcsec,
220 'deltaAperFitMinNgoodObs': config.deltaAperFitMinNgoodObs,
221 'deltaAperFitPerCcdNx': config.deltaAperFitPerCcdNx,
222 'deltaAperFitPerCcdNy': config.deltaAperFitPerCcdNy,
223 'deltaAperFitSpatialNside': config.deltaAperFitSpatialNside,
224 'doComputeDeltaAperExposures': config.doComputeDeltaAperPerVisit,
225 'doComputeDeltaAperStars': config.doComputeDeltaAperPerStar,
226 'doComputeDeltaAperMap': config.doComputeDeltaAperMap,
227 'doComputeDeltaAperPerCcd': config.doComputeDeltaAperPerCcd,
229 'quietMode': config.quietMode,
230 'randomSeed': config.randomSeed,
231 'outputStars':
False,
232 'outputPath': os.path.abspath(
'.'),
235 'resetParameters': resetFitParameters,
236 'doPlots': config.doPlots,
237 'outputFgcmcalZpts':
True,
238 'outputZeropoints': outputZeropoints}
243def translateFgcmLut(lutCat, physicalFilterMap):
245 Translate the FGCM look-up-table into an fgcm-compatible object
250 Catalog describing the FGCM look-up table
251 physicalFilterMap: `dict`
252 Physical filter to band mapping
256 fgcmLut: `lsst.fgcm.FgcmLut`
257 Lookup table for FGCM
258 lutIndexVals: `numpy.ndarray`
259 Numpy array
with LUT index information
for FGCM
260 lutStd: `numpy.ndarray`
261 Numpy array
with LUT standard throughput values
for FGCM
265 After running this code, it
is wise to `del lutCat` to clear the memory.
269 lutFilterNames = np.array(lutCat[0][
'physicalFilters'].split(
','), dtype=
'U')
270 lutStdFilterNames = np.array(lutCat[0][
'stdPhysicalFilters'].split(
','), dtype=
'U')
275 lutIndexVals = np.zeros(1, dtype=[(
'FILTERNAMES', lutFilterNames.dtype.str,
276 lutFilterNames.size),
277 (
'STDFILTERNAMES', lutStdFilterNames.dtype.str,
278 lutStdFilterNames.size),
279 (
'PMB',
'f8', lutCat[0][
'pmb'].size),
280 (
'PMBFACTOR',
'f8', lutCat[0][
'pmbFactor'].size),
281 (
'PMBELEVATION',
'f8'),
282 (
'LAMBDANORM',
'f8'),
283 (
'PWV',
'f8', lutCat[0][
'pwv'].size),
284 (
'O3',
'f8', lutCat[0][
'o3'].size),
285 (
'TAU',
'f8', lutCat[0][
'tau'].size),
286 (
'ALPHA',
'f8', lutCat[0][
'alpha'].size),
287 (
'ZENITH',
'f8', lutCat[0][
'zenith'].size),
290 lutIndexVals[
'FILTERNAMES'][:] = lutFilterNames
291 lutIndexVals[
'STDFILTERNAMES'][:] = lutStdFilterNames
292 lutIndexVals[
'PMB'][:] = lutCat[0][
'pmb']
293 lutIndexVals[
'PMBFACTOR'][:] = lutCat[0][
'pmbFactor']
294 lutIndexVals[
'PMBELEVATION'] = lutCat[0][
'pmbElevation']
295 lutIndexVals[
'LAMBDANORM'] = lutCat[0][
'lambdaNorm']
296 lutIndexVals[
'PWV'][:] = lutCat[0][
'pwv']
297 lutIndexVals[
'O3'][:] = lutCat[0][
'o3']
298 lutIndexVals[
'TAU'][:] = lutCat[0][
'tau']
299 lutIndexVals[
'ALPHA'][:] = lutCat[0][
'alpha']
300 lutIndexVals[
'ZENITH'][:] = lutCat[0][
'zenith']
301 lutIndexVals[
'NCCD'] = lutCat[0][
'nCcd']
304 lutStd = np.zeros(1, dtype=[(
'PMBSTD',
'f8'),
310 (
'LAMBDARANGE',
'f8', 2),
311 (
'LAMBDASTEP',
'f8'),
312 (
'LAMBDASTD',
'f8', lutFilterNames.size),
313 (
'LAMBDASTDFILTER',
'f8', lutStdFilterNames.size),
314 (
'I0STD',
'f8', lutFilterNames.size),
315 (
'I1STD',
'f8', lutFilterNames.size),
316 (
'I10STD',
'f8', lutFilterNames.size),
317 (
'I2STD',
'f8', lutFilterNames.size),
318 (
'LAMBDAB',
'f8', lutFilterNames.size),
319 (
'ATMLAMBDA',
'f8', lutCat[0][
'atmLambda'].size),
320 (
'ATMSTDTRANS',
'f8', lutCat[0][
'atmStdTrans'].size)])
321 lutStd[
'PMBSTD'] = lutCat[0][
'pmbStd']
322 lutStd[
'PWVSTD'] = lutCat[0][
'pwvStd']
323 lutStd[
'O3STD'] = lutCat[0][
'o3Std']
324 lutStd[
'TAUSTD'] = lutCat[0][
'tauStd']
325 lutStd[
'ALPHASTD'] = lutCat[0][
'alphaStd']
326 lutStd[
'ZENITHSTD'] = lutCat[0][
'zenithStd']
327 lutStd[
'LAMBDARANGE'][:] = lutCat[0][
'lambdaRange'][:]
328 lutStd[
'LAMBDASTEP'] = lutCat[0][
'lambdaStep']
329 lutStd[
'LAMBDASTD'][:] = lutCat[0][
'lambdaStd']
330 lutStd[
'LAMBDASTDFILTER'][:] = lutCat[0][
'lambdaStdFilter']
331 lutStd[
'I0STD'][:] = lutCat[0][
'i0Std']
332 lutStd[
'I1STD'][:] = lutCat[0][
'i1Std']
333 lutStd[
'I10STD'][:] = lutCat[0][
'i10Std']
334 lutStd[
'I2STD'][:] = lutCat[0][
'i2Std']
335 lutStd[
'LAMBDAB'][:] = lutCat[0][
'lambdaB']
336 lutStd[
'ATMLAMBDA'][:] = lutCat[0][
'atmLambda'][:]
337 lutStd[
'ATMSTDTRANS'][:] = lutCat[0][
'atmStdTrans'][:]
339 lutTypes = [row[
'luttype']
for row
in lutCat]
342 lutFlat = np.zeros(lutCat[0][
'lut'].size, dtype=[(
'I0',
'f4'),
345 lutFlat[
'I0'][:] = lutCat[lutTypes.index(
'I0')][
'lut'][:]
346 lutFlat[
'I1'][:] = lutCat[lutTypes.index(
'I1')][
'lut'][:]
348 lutDerivFlat = np.zeros(lutCat[0][
'lut'].size, dtype=[(
'D_LNPWV',
'f4'),
352 (
'D_SECZENITH',
'f4'),
353 (
'D_LNPWV_I1',
'f4'),
355 (
'D_LNTAU_I1',
'f4'),
356 (
'D_ALPHA_I1',
'f4'),
357 (
'D_SECZENITH_I1',
'f4')])
359 for name
in lutDerivFlat.dtype.names:
360 lutDerivFlat[name][:] = lutCat[lutTypes.index(name)][
'lut'][:]
367 fgcmLut = fgcm.FgcmLUT(lutIndexVals, lutFlat, lutDerivFlat, lutStd,
368 filterToBand=physicalFilterMap)
370 return fgcmLut, lutIndexVals, lutStd
373def translateVisitCatalog(visitCat):
375 Translate the FGCM visit catalog to an fgcm-compatible object
380 FGCM visitCat from `lsst.fgcmcal.FgcmBuildStarsTask`
384 fgcmExpInfo: `numpy.ndarray`
385 Numpy array
for visit information
for FGCM
389 After running this code, it
is wise to `del visitCat` to clear the memory.
392 fgcmExpInfo = np.zeros(len(visitCat), dtype=[('VISIT',
'i8'),
396 (
'DELTA_APER',
'f8'),
397 (
'SKYBACKGROUND',
'f8'),
404 (
'FILTERNAME',
'a50')])
405 fgcmExpInfo[
'VISIT'][:] = visitCat[
'visit']
406 fgcmExpInfo[
'MJD'][:] = visitCat[
'mjd']
407 fgcmExpInfo[
'EXPTIME'][:] = visitCat[
'exptime']
408 fgcmExpInfo[
'DEEPFLAG'][:] = visitCat[
'deepFlag']
409 fgcmExpInfo[
'TELHA'][:] = visitCat[
'telha']
410 fgcmExpInfo[
'TELRA'][:] = visitCat[
'telra']
411 fgcmExpInfo[
'TELDEC'][:] = visitCat[
'teldec']
412 fgcmExpInfo[
'TELROT'][:] = visitCat[
'telrot']
413 fgcmExpInfo[
'PMB'][:] = visitCat[
'pmb']
414 fgcmExpInfo[
'PSFSIGMA'][:] = visitCat[
'psfSigma']
415 fgcmExpInfo[
'DELTA_APER'][:] = visitCat[
'deltaAper']
416 fgcmExpInfo[
'SKYBACKGROUND'][:] = visitCat[
'skyBackground']
419 fgcmExpInfo[
'FILTERNAME'][:] = visitCat.asAstropy()[
'physicalFilter']
424@deprecated(reason=
"This method is no longer used in fgcmcal. It will be removed after v23.",
425 version=
"v23.0", category=FutureWarning)
428 Compute the CCD offsets in ra/dec
and x/y space
433 defaultOrientation: `float`
434 Default camera orientation (degrees)
438 ccdOffsets: `numpy.ndarray`
439 Numpy array
with ccd offset information
for input to FGCM.
440 Angular units are degrees,
and x/y units are pixels.
445 ccdOffsets = np.zeros(len(camera), dtype=[(
'CCDNUM',
'i4'),
460 if camera.getName() ==
'HSC' and np.isnan(defaultOrientation):
461 orientation = 270*geom.degrees
463 orientation = defaultOrientation*geom.degrees
468 boresightRotAngle=orientation,
469 rotType=afwImage.RotType.SKY)
471 for i, detector
in enumerate(camera):
472 ccdOffsets[
'CCDNUM'][i] = detector.getId()
474 wcs = createInitialSkyWcs(visitInfo, detector, flipX)
476 detCenter = wcs.pixelToSky(detector.getCenter(afwCameraGeom.PIXELS))
477 ccdOffsets[
'DELTA_RA'][i] = (detCenter.getRa() - boresight.getRa()).asDegrees()
478 ccdOffsets[
'DELTA_DEC'][i] = (detCenter.getDec() - boresight.getDec()).asDegrees()
480 bbox = detector.getBBox()
482 detCorner1 = wcs.pixelToSky(
geom.Point2D(bbox.getMin()))
483 detCorner2 = wcs.pixelToSky(
geom.Point2D(bbox.getMax()))
485 ccdOffsets[
'RA_SIZE'][i] = np.abs((detCorner2.getRa() - detCorner1.getRa()).asDegrees())
486 ccdOffsets[
'DEC_SIZE'][i] = np.abs((detCorner2.getDec() - detCorner1.getDec()).asDegrees())
488 ccdOffsets[
'X_SIZE'][i] = bbox.getMaxX()
489 ccdOffsets[
'Y_SIZE'][i] = bbox.getMaxY()
496 Compute the median pixel scale in the camera
501 Average pixel scale (arcsecond) over the camera
505 orientation = 0.0*geom.degrees
510 boresightRotAngle=orientation,
511 rotType=afwImage.RotType.SKY)
513 pixelScales = np.zeros(len(camera))
514 for i, detector
in enumerate(camera):
515 wcs = createInitialSkyWcs(visitInfo, detector, flipX)
516 pixelScales[i] = wcs.getPixelScale().asArcseconds()
518 ok, = np.where(pixelScales > 0.0)
519 return np.median(pixelScales[ok])
522def computeApproxPixelAreaFields(camera):
524 Compute the approximate pixel area bounded fields from the camera
533 approxPixelAreaFields: `dict`
534 Dictionary of approximate area fields, keyed
with detector ID
547 boresightRotAngle=0.0*geom.degrees,
548 rotType=afwImage.RotType.SKY)
550 approxPixelAreaFields = {}
552 for i, detector
in enumerate(camera):
553 key = detector.getId()
555 wcs = createInitialSkyWcs(visitInfo, detector, flipX)
556 bbox = detector.getBBox()
559 unit=geom.arcseconds, scaling=areaScaling)
560 approxAreaField = afwMath.ChebyshevBoundedField.approximate(areaField)
562 approxPixelAreaFields[key] = approxAreaField
564 return approxPixelAreaFields
567def makeZptSchema(superStarChebyshevSize, zptChebyshevSize):
569 Make the zeropoint schema
573 superStarChebyshevSize: `int`
574 Length of the superstar chebyshev array
575 zptChebyshevSize: `int`
576 Length of the zeropoint chebyshev array
580 zptSchema: `lsst.afw.table.schema`
585 zptSchema.addField('visit', type=np.int64, doc=
'Visit number')
586 zptSchema.addField(
'detector', type=np.int32, doc=
'Detector ID number')
587 zptSchema.addField(
'fgcmFlag', type=np.int32, doc=(
'FGCM flag value: '
588 '1: Photometric, used in fit; '
589 '2: Photometric, not used in fit; '
590 '4: Non-photometric, on partly photometric night; '
591 '8: Non-photometric, on non-photometric night; '
592 '16: No zeropoint could be determined; '
593 '32: Too few stars for reliable gray computation'))
594 zptSchema.addField(
'fgcmZpt', type=np.float64, doc=
'FGCM zeropoint (center of CCD)')
595 zptSchema.addField(
'fgcmZptErr', type=np.float64,
596 doc=
'Error on zeropoint, estimated from repeatability + number of obs')
597 zptSchema.addField(
'fgcmfZptChebXyMax', type=
'ArrayD', size=2,
598 doc=
'maximum x/maximum y to scale to apply chebyshev parameters')
599 zptSchema.addField(
'fgcmfZptCheb', type=
'ArrayD',
600 size=zptChebyshevSize,
601 doc=
'Chebyshev parameters (flattened) for zeropoint')
602 zptSchema.addField(
'fgcmfZptSstarCheb', type=
'ArrayD',
603 size=superStarChebyshevSize,
604 doc=
'Chebyshev parameters (flattened) for superStarFlat')
605 zptSchema.addField(
'fgcmI0', type=np.float64, doc=
'Integral of the passband')
606 zptSchema.addField(
'fgcmI10', type=np.float64, doc=
'Normalized chromatic integral')
607 zptSchema.addField(
'fgcmR0', type=np.float64,
608 doc=
'Retrieved i0 integral, estimated from stars (only for flag 1)')
609 zptSchema.addField(
'fgcmR10', type=np.float64,
610 doc=
'Retrieved i10 integral, estimated from stars (only for flag 1)')
611 zptSchema.addField(
'fgcmGry', type=np.float64,
612 doc=
'Estimated gray extinction relative to atmospheric solution; '
613 'only for fgcmFlag <= 4 (see fgcmFlag) ')
614 zptSchema.addField(
'fgcmDeltaChrom', type=np.float64,
615 doc=
'Mean chromatic correction for stars in this ccd; '
616 'only for fgcmFlag <= 4 (see fgcmFlag)')
617 zptSchema.addField(
'fgcmZptVar', type=np.float64, doc=
'Variance of zeropoint over ccd')
618 zptSchema.addField(
'fgcmTilings', type=np.float64,
619 doc=
'Number of photometric tilings used for solution for ccd')
620 zptSchema.addField(
'fgcmFpGry', type=np.float64,
621 doc=
'Average gray extinction over the full focal plane '
622 '(same for all ccds in a visit)')
623 zptSchema.addField(
'fgcmFpGryBlue', type=np.float64,
624 doc=
'Average gray extinction over the full focal plane '
625 'for 25% bluest stars')
626 zptSchema.addField(
'fgcmFpGryBlueErr', type=np.float64,
627 doc=
'Error on Average gray extinction over the full focal plane '
628 'for 25% bluest stars')
629 zptSchema.addField(
'fgcmFpGryRed', type=np.float64,
630 doc=
'Average gray extinction over the full focal plane '
631 'for 25% reddest stars')
632 zptSchema.addField(
'fgcmFpGryRedErr', type=np.float64,
633 doc=
'Error on Average gray extinction over the full focal plane '
634 'for 25% reddest stars')
635 zptSchema.addField(
'fgcmFpVar', type=np.float64,
636 doc=
'Variance of gray extinction over the full focal plane '
637 '(same for all ccds in a visit)')
638 zptSchema.addField(
'fgcmDust', type=np.float64,
639 doc=
'Gray dust extinction from the primary/corrector'
640 'at the time of the exposure')
641 zptSchema.addField(
'fgcmFlat', type=np.float64, doc=
'Superstarflat illumination correction')
642 zptSchema.addField(
'fgcmAperCorr', type=np.float64, doc=
'Aperture correction estimated by fgcm')
643 zptSchema.addField(
'fgcmDeltaMagBkg', type=np.float64,
644 doc=(
'Local background correction from brightest percentile '
645 '(value set by deltaMagBkgOffsetPercentile) calibration '
647 zptSchema.addField(
'exptime', type=np.float32, doc=
'Exposure time')
648 zptSchema.addField(
'filtername', type=str, size=10, doc=
'Filter name')
653def makeZptCat(zptSchema, zpStruct):
655 Make the zeropoint catalog for persistence
660 Zeropoint catalog schema
661 zpStruct: `numpy.ndarray`
662 Zeropoint structure
from fgcm
667 Zeropoint catalog
for persistence
671 zptCat.reserve(zpStruct.size)
673 for filterName
in zpStruct[
'FILTERNAME']:
674 rec = zptCat.addNew()
675 rec[
'filtername'] = filterName.decode(
'utf-8')
677 zptCat[
'visit'][:] = zpStruct[FGCM_EXP_FIELD]
678 zptCat[
'detector'][:] = zpStruct[FGCM_CCD_FIELD]
679 zptCat[
'fgcmFlag'][:] = zpStruct[
'FGCM_FLAG']
680 zptCat[
'fgcmZpt'][:] = zpStruct[
'FGCM_ZPT']
681 zptCat[
'fgcmZptErr'][:] = zpStruct[
'FGCM_ZPTERR']
682 zptCat[
'fgcmfZptChebXyMax'][:, :] = zpStruct[
'FGCM_FZPT_XYMAX']
683 zptCat[
'fgcmfZptCheb'][:, :] = zpStruct[
'FGCM_FZPT_CHEB']
684 zptCat[
'fgcmfZptSstarCheb'][:, :] = zpStruct[
'FGCM_FZPT_SSTAR_CHEB']
685 zptCat[
'fgcmI0'][:] = zpStruct[
'FGCM_I0']
686 zptCat[
'fgcmI10'][:] = zpStruct[
'FGCM_I10']
687 zptCat[
'fgcmR0'][:] = zpStruct[
'FGCM_R0']
688 zptCat[
'fgcmR10'][:] = zpStruct[
'FGCM_R10']
689 zptCat[
'fgcmGry'][:] = zpStruct[
'FGCM_GRY']
690 zptCat[
'fgcmDeltaChrom'][:] = zpStruct[
'FGCM_DELTACHROM']
691 zptCat[
'fgcmZptVar'][:] = zpStruct[
'FGCM_ZPTVAR']
692 zptCat[
'fgcmTilings'][:] = zpStruct[
'FGCM_TILINGS']
693 zptCat[
'fgcmFpGry'][:] = zpStruct[
'FGCM_FPGRY']
694 zptCat[
'fgcmFpGryBlue'][:] = zpStruct[
'FGCM_FPGRY_CSPLIT'][:, 0]
695 zptCat[
'fgcmFpGryBlueErr'][:] = zpStruct[
'FGCM_FPGRY_CSPLITERR'][:, 0]
696 zptCat[
'fgcmFpGryRed'][:] = zpStruct[
'FGCM_FPGRY_CSPLIT'][:, 2]
697 zptCat[
'fgcmFpGryRedErr'][:] = zpStruct[
'FGCM_FPGRY_CSPLITERR'][:, 2]
698 zptCat[
'fgcmFpVar'][:] = zpStruct[
'FGCM_FPVAR']
699 zptCat[
'fgcmDust'][:] = zpStruct[
'FGCM_DUST']
700 zptCat[
'fgcmFlat'][:] = zpStruct[
'FGCM_FLAT']
701 zptCat[
'fgcmAperCorr'][:] = zpStruct[
'FGCM_APERCORR']
702 zptCat[
'fgcmDeltaMagBkg'][:] = zpStruct[
'FGCM_DELTAMAGBKG']
703 zptCat[
'exptime'][:] = zpStruct[
'EXPTIME']
710 Make the atmosphere schema
719 atmSchema.addField('visit', type=np.int32, doc=
'Visit number')
720 atmSchema.addField(
'pmb', type=np.float64, doc=
'Barometric pressure (mb)')
721 atmSchema.addField(
'pwv', type=np.float64, doc=
'Water vapor (mm)')
722 atmSchema.addField(
'tau', type=np.float64, doc=
'Aerosol optical depth')
723 atmSchema.addField(
'alpha', type=np.float64, doc=
'Aerosol slope')
724 atmSchema.addField(
'o3', type=np.float64, doc=
'Ozone (dobson)')
725 atmSchema.addField(
'secZenith', type=np.float64, doc=
'Secant(zenith) (~ airmass)')
726 atmSchema.addField(
'cTrans', type=np.float64, doc=
'Transmission correction factor')
727 atmSchema.addField(
'lamStd', type=np.float64, doc=
'Wavelength for transmission correction')
732def makeAtmCat(atmSchema, atmStruct):
734 Make the atmosphere catalog for persistence
739 Atmosphere catalog schema
740 atmStruct: `numpy.ndarray`
741 Atmosphere structure
from fgcm
746 Atmosphere catalog
for persistence
750 atmCat.resize(atmStruct.size)
752 atmCat['visit'][:] = atmStruct[
'VISIT']
753 atmCat[
'pmb'][:] = atmStruct[
'PMB']
754 atmCat[
'pwv'][:] = atmStruct[
'PWV']
755 atmCat[
'tau'][:] = atmStruct[
'TAU']
756 atmCat[
'alpha'][:] = atmStruct[
'ALPHA']
757 atmCat[
'o3'][:] = atmStruct[
'O3']
758 atmCat[
'secZenith'][:] = atmStruct[
'SECZENITH']
759 atmCat[
'cTrans'][:] = atmStruct[
'CTRANS']
760 atmCat[
'lamStd'][:] = atmStruct[
'LAMSTD']
765def makeStdSchema(nBands):
767 Make the standard star schema
772 Number of bands in standard star catalog
779 stdSchema = afwTable.SimpleTable.makeMinimalSchema()
780 stdSchema.addField('ngood', type=
'ArrayI', doc=
'Number of good observations',
782 stdSchema.addField(
'ntotal', type=
'ArrayI', doc=
'Number of total observations',
784 stdSchema.addField(
'mag_std_noabs', type=
'ArrayF',
785 doc=
'Standard magnitude (no absolute calibration)',
787 stdSchema.addField(
'magErr_std', type=
'ArrayF',
788 doc=
'Standard magnitude error',
790 stdSchema.addField(
'npsfcand', type=
'ArrayI',
791 doc=
'Number of observations flagged as psf candidates',
793 stdSchema.addField(
'delta_aper', type=
'ArrayF',
794 doc=
'Delta mag (small - large aperture)',
800def makeStdCat(stdSchema, stdStruct, goodBands):
802 Make the standard star catalog for persistence
807 Standard star catalog schema
808 stdStruct: `numpy.ndarray`
809 Standard star structure
in FGCM format
811 List of good band names used
in stdStruct
816 Standard star catalog
for persistence
820 stdCat.resize(stdStruct.size)
822 stdCat['id'][:] = stdStruct[
'FGCM_ID']
823 stdCat[
'coord_ra'][:] = stdStruct[
'RA'] * geom.degrees
824 stdCat[
'coord_dec'][:] = stdStruct[
'DEC'] * geom.degrees
825 stdCat[
'ngood'][:, :] = stdStruct[
'NGOOD'][:, :]
826 stdCat[
'ntotal'][:, :] = stdStruct[
'NTOTAL'][:, :]
827 stdCat[
'mag_std_noabs'][:, :] = stdStruct[
'MAG_STD'][:, :]
828 stdCat[
'magErr_std'][:, :] = stdStruct[
'MAGERR_STD'][:, :]
829 stdCat[
'npsfcand'][:, :] = stdStruct[
'NPSFCAND'][:, :]
830 stdCat[
'delta_aper'][:, :] = stdStruct[
'DELTA_APER'][:, :]
833 md.set(
"BANDS",
list(goodBands))
834 stdCat.setMetadata(md)
839def computeApertureRadiusFromName(fluxField):
841 Compute the radius associated with a CircularApertureFlux
or ApFlux field.
846 CircularApertureFlux
or ApFlux
850 apertureRadius : `float`
851 Radius of the aperture field,
in pixels.
855 RuntimeError: Raised
if flux field
is not a CircularApertureFlux,
859 m = re.search(
r'(CircularApertureFlux|ApFlux|apFlux)_(\d+)_(\d+)_', fluxField)
862 raise RuntimeError(f
"Flux field {fluxField} does not correspond to a CircularApertureFlux or ApFlux")
864 apertureRadius = float(m.groups()[1]) + float(m.groups()[2])/10.
866 return apertureRadius
869def extractReferenceMags(refStars, bands, filterMap):
871 Extract reference magnitudes from refStars
for given bands
and
872 associated filterMap.
877 FGCM reference star catalog
879 List of bands
for calibration
881 FGCM mapping of filter to band
885 refMag : `np.ndarray`
886 nstar x nband array of reference magnitudes
887 refMagErr : `np.ndarray`
888 nstar x nband array of reference magnitude errors
894 md = refStars.getMetadata()
895 if 'FILTERNAMES' in md:
896 filternames = md.getArray(
'FILTERNAMES')
900 refMag = np.zeros((len(refStars), len(bands)),
901 dtype=refStars[
'refMag'].dtype) + 99.0
902 refMagErr = np.zeros_like(refMag) + 99.0
903 for i, filtername
in enumerate(filternames):
907 band = filterMap[filtername]
911 ind = bands.index(band)
915 refMag[:, ind] = refStars[
'refMag'][:, i]
916 refMagErr[:, ind] = refStars[
'refMagErr'][:, i]
920 refMag = refStars[
'refMag'][:, :]
921 refMagErr = refStars[
'refMagErr'][:, :]
923 return refMag, refMagErr
926def lookupStaticCalibrations(datasetType, registry, quantumDataId, collections):
927 instrument = Instrument.fromName(quantumDataId[
"instrument"], registry)
928 unboundedCollection = instrument.makeUnboundedCalibrationRunName()
930 return registry.queryDatasets(datasetType,
931 dataId=quantumDataId,
932 collections=[unboundedCollection])
An immutable representation of a camera.
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.
This static class includes a variety of methods for interacting with the the logging module.
daf::base::PropertyList * list
def computeReferencePixelScale(camera)
def computeCcdOffsets(camera, defaultOrientation)