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.
36from lsst.obs.base
import createInitialSkyWcs
42FGCM_EXP_FIELD =
'VISIT'
43FGCM_CCD_FIELD =
'DETECTOR'
44FGCM_ILLEGAL_VALUE = -9999.0
47def makeConfigDict(config, log, camera, maxIter,
48 resetFitParameters, outputZeropoints,
49 lutFilterNames, tract=None):
51 Make the FGCM fit cycle configuration dict
55 config: `lsst.fgcmcal.FgcmFitCycleConfig`
60 Camera from the butler
62 Maximum number of iterations
63 resetFitParameters: `bool`
64 Reset fit parameters before fitting?
65 outputZeropoints: `bool`
66 Compute zeropoints
for output?
67 lutFilterNames : array-like, `str`
68 Array of physical filter names
in the LUT.
69 tract: `int`, optional
70 Tract number
for extending the output file name
for debugging.
76 Configuration dictionary
for fgcm
79 notFitBands = [b
for b
in config.bands
if b
not in config.fitBands]
83 for ccut
in config.starColorCuts:
87 parts = ccut.split(
',')
88 starColorCutList.append([parts[0], parts[1], float(parts[2]), float(parts[3])])
91 refStarColorCutList = []
92 for ccut
in config.refStarColorCuts:
96 parts = ccut.split(
',')
97 refStarColorCutList.append([parts[0], parts[1], float(parts[2]), float(parts[3])])
102 mirrorArea = np.pi*(camera.telescopeDiameter*100./2.)**2.
105 gains = [amp.getGain()
for detector
in camera
for amp
in detector.getAmplifiers()]
106 cameraGain = float(np.median(gains))
109 filterToBand = {filterName: config.physicalFilterMap[filterName]
for
110 filterName
in lutFilterNames}
113 outfileBase = config.outfileBase
115 outfileBase =
'%s-%06d' % (config.outfileBase, tract)
118 configDict = {
'outfileBase': outfileBase,
120 'exposureFile':
None,
124 'mirrorArea': mirrorArea,
125 'cameraGain': cameraGain,
126 'ccdStartIndex': camera[0].getId(),
127 'expField': FGCM_EXP_FIELD,
128 'ccdField': FGCM_CCD_FIELD,
129 'seeingField':
'DELTA_APER',
130 'fwhmField':
'PSFSIGMA',
131 'skyBrightnessField':
'SKYBACKGROUND',
132 'deepFlag':
'DEEPFLAG',
133 'bands':
list(config.bands),
134 'fitBands':
list(config.fitBands),
135 'notFitBands': notFitBands,
136 'requiredBands':
list(config.requiredBands),
137 'filterToBand': filterToBand,
139 'nCore': config.nCore,
140 'nStarPerRun': config.nStarPerRun,
141 'nExpPerRun': config.nExpPerRun,
142 'reserveFraction': config.reserveFraction,
143 'freezeStdAtmosphere': config.freezeStdAtmosphere,
144 'precomputeSuperStarInitialCycle': config.precomputeSuperStarInitialCycle,
145 'superStarSubCCDDict': dict(config.superStarSubCcdDict),
146 'superStarSubCCDChebyshevOrder': config.superStarSubCcdChebyshevOrder,
147 'superStarSubCCDTriangular': config.superStarSubCcdTriangular,
148 'superStarSigmaClip': config.superStarSigmaClip,
149 'focalPlaneSigmaClip': config.focalPlaneSigmaClip,
150 'ccdGraySubCCDDict': dict(config.ccdGraySubCcdDict),
151 'ccdGraySubCCDChebyshevOrder': config.ccdGraySubCcdChebyshevOrder,
152 'ccdGraySubCCDTriangular': config.ccdGraySubCcdTriangular,
153 'ccdGrayFocalPlaneDict': dict(config.ccdGrayFocalPlaneDict),
154 'ccdGrayFocalPlaneChebyshevOrder': config.ccdGrayFocalPlaneChebyshevOrder,
155 'ccdGrayFocalPlaneFitMinCcd': config.ccdGrayFocalPlaneFitMinCcd,
156 'cycleNumber': config.cycleNumber,
158 'deltaMagBkgOffsetPercentile': config.deltaMagBkgOffsetPercentile,
159 'deltaMagBkgPerCcd': config.deltaMagBkgPerCcd,
160 'UTBoundary': config.utBoundary,
161 'washMJDs': config.washMjds,
162 'epochMJDs': config.epochMjds,
163 'coatingMJDs': config.coatingMjds,
164 'minObsPerBand': config.minObsPerBand,
165 'latitude': config.latitude,
166 'defaultCameraOrientation': config.defaultCameraOrientation,
167 'brightObsGrayMax': config.brightObsGrayMax,
168 'minStarPerCCD': config.minStarPerCcd,
169 'minCCDPerExp': config.minCcdPerExp,
170 'maxCCDGrayErr': config.maxCcdGrayErr,
171 'minStarPerExp': config.minStarPerExp,
172 'minExpPerNight': config.minExpPerNight,
173 'expGrayInitialCut': config.expGrayInitialCut,
174 'expGrayPhotometricCutDict': dict(config.expGrayPhotometricCutDict),
175 'expGrayHighCutDict': dict(config.expGrayHighCutDict),
176 'expGrayRecoverCut': config.expGrayRecoverCut,
177 'expVarGrayPhotometricCutDict': dict(config.expVarGrayPhotometricCutDict),
178 'expGrayErrRecoverCut': config.expGrayErrRecoverCut,
179 'refStarSnMin': config.refStarSnMin,
180 'refStarOutlierNSig': config.refStarOutlierNSig,
181 'applyRefStarColorCuts': config.applyRefStarColorCuts,
182 'useExposureReferenceOffset': config.useExposureReferenceOffset,
183 'illegalValue': FGCM_ILLEGAL_VALUE,
184 'starColorCuts': starColorCutList,
185 'refStarColorCuts': refStarColorCutList,
186 'aperCorrFitNBins': config.aperCorrFitNBins,
187 'aperCorrInputSlopeDict': dict(config.aperCorrInputSlopeDict),
188 'sedBoundaryTermDict': config.sedboundaryterms.toDict()[
'data'],
189 'sedTermDict': config.sedterms.toDict()[
'data'],
190 'colorSplitBands':
list(config.colorSplitBands),
191 'sigFgcmMaxErr': config.sigFgcmMaxErr,
192 'sigFgcmMaxEGrayDict': dict(config.sigFgcmMaxEGrayDict),
193 'ccdGrayMaxStarErr': config.ccdGrayMaxStarErr,
194 'approxThroughputDict': dict(config.approxThroughputDict),
195 'sigmaCalRange':
list(config.sigmaCalRange),
196 'sigmaCalFitPercentile':
list(config.sigmaCalFitPercentile),
197 'sigmaCalPlotPercentile':
list(config.sigmaCalPlotPercentile),
198 'sigma0Phot': config.sigma0Phot,
199 'mapLongitudeRef': config.mapLongitudeRef,
200 'mapNSide': config.mapNSide,
203 'useRetrievedPwv':
False,
204 'useNightlyRetrievedPwv':
False,
205 'pwvRetrievalSmoothBlock': 25,
206 'useQuadraticPwv': config.useQuadraticPwv,
207 'useRetrievedTauInit':
False,
208 'tauRetrievalMinCCDPerNight': 500,
209 'modelMagErrors': config.modelMagErrors,
210 'instrumentParsPerBand': config.instrumentParsPerBand,
211 'instrumentSlopeMinDeltaT': config.instrumentSlopeMinDeltaT,
212 'fitMirrorChromaticity': config.fitMirrorChromaticity,
213 'useRepeatabilityForExpGrayCutsDict': dict(config.useRepeatabilityForExpGrayCutsDict),
214 'autoPhotometricCutNSig': config.autoPhotometricCutNSig,
215 'autoHighCutNSig': config.autoHighCutNSig,
216 'deltaAperInnerRadiusArcsec': config.deltaAperInnerRadiusArcsec,
217 'deltaAperOuterRadiusArcsec': config.deltaAperOuterRadiusArcsec,
218 'deltaAperFitMinNgoodObs': config.deltaAperFitMinNgoodObs,
219 'deltaAperFitPerCcdNx': config.deltaAperFitPerCcdNx,
220 'deltaAperFitPerCcdNy': config.deltaAperFitPerCcdNy,
221 'deltaAperFitSpatialNside': config.deltaAperFitSpatialNside,
222 'doComputeDeltaAperExposures': config.doComputeDeltaAperPerVisit,
223 'doComputeDeltaAperStars': config.doComputeDeltaAperPerStar,
224 'doComputeDeltaAperMap': config.doComputeDeltaAperMap,
225 'doComputeDeltaAperPerCcd': config.doComputeDeltaAperPerCcd,
227 'quietMode': config.quietMode,
228 'randomSeed': config.randomSeed,
229 'outputStars':
False,
230 'outputPath': os.path.abspath(
'.'),
233 'resetParameters': resetFitParameters,
234 'doPlots': config.doPlots,
235 'outputFgcmcalZpts':
True,
236 'outputZeropoints': outputZeropoints}
241def translateFgcmLut(lutCat, physicalFilterMap):
243 Translate the FGCM look-up-table into an fgcm-compatible object
248 Catalog describing the FGCM look-up table
249 physicalFilterMap: `dict`
250 Physical filter to band mapping
254 fgcmLut: `lsst.fgcm.FgcmLut`
255 Lookup table for FGCM
256 lutIndexVals: `numpy.ndarray`
257 Numpy array
with LUT index information
for FGCM
258 lutStd: `numpy.ndarray`
259 Numpy array
with LUT standard throughput values
for FGCM
263 After running this code, it
is wise to `del lutCat` to clear the memory.
267 lutFilterNames = np.array(lutCat[0][
'physicalFilters'].split(
','), dtype=
'U')
268 lutStdFilterNames = np.array(lutCat[0][
'stdPhysicalFilters'].split(
','), dtype=
'U')
273 lutIndexVals = np.zeros(1, dtype=[(
'FILTERNAMES', lutFilterNames.dtype.str,
274 lutFilterNames.size),
275 (
'STDFILTERNAMES', lutStdFilterNames.dtype.str,
276 lutStdFilterNames.size),
277 (
'PMB',
'f8', lutCat[0][
'pmb'].size),
278 (
'PMBFACTOR',
'f8', lutCat[0][
'pmbFactor'].size),
279 (
'PMBELEVATION',
'f8'),
280 (
'LAMBDANORM',
'f8'),
281 (
'PWV',
'f8', lutCat[0][
'pwv'].size),
282 (
'O3',
'f8', lutCat[0][
'o3'].size),
283 (
'TAU',
'f8', lutCat[0][
'tau'].size),
284 (
'ALPHA',
'f8', lutCat[0][
'alpha'].size),
285 (
'ZENITH',
'f8', lutCat[0][
'zenith'].size),
288 lutIndexVals[
'FILTERNAMES'][:] = lutFilterNames
289 lutIndexVals[
'STDFILTERNAMES'][:] = lutStdFilterNames
290 lutIndexVals[
'PMB'][:] = lutCat[0][
'pmb']
291 lutIndexVals[
'PMBFACTOR'][:] = lutCat[0][
'pmbFactor']
292 lutIndexVals[
'PMBELEVATION'] = lutCat[0][
'pmbElevation']
293 lutIndexVals[
'LAMBDANORM'] = lutCat[0][
'lambdaNorm']
294 lutIndexVals[
'PWV'][:] = lutCat[0][
'pwv']
295 lutIndexVals[
'O3'][:] = lutCat[0][
'o3']
296 lutIndexVals[
'TAU'][:] = lutCat[0][
'tau']
297 lutIndexVals[
'ALPHA'][:] = lutCat[0][
'alpha']
298 lutIndexVals[
'ZENITH'][:] = lutCat[0][
'zenith']
299 lutIndexVals[
'NCCD'] = lutCat[0][
'nCcd']
302 lutStd = np.zeros(1, dtype=[(
'PMBSTD',
'f8'),
308 (
'LAMBDARANGE',
'f8', 2),
309 (
'LAMBDASTEP',
'f8'),
310 (
'LAMBDASTD',
'f8', lutFilterNames.size),
311 (
'LAMBDASTDFILTER',
'f8', lutStdFilterNames.size),
312 (
'I0STD',
'f8', lutFilterNames.size),
313 (
'I1STD',
'f8', lutFilterNames.size),
314 (
'I10STD',
'f8', lutFilterNames.size),
315 (
'I2STD',
'f8', lutFilterNames.size),
316 (
'LAMBDAB',
'f8', lutFilterNames.size),
317 (
'ATMLAMBDA',
'f8', lutCat[0][
'atmLambda'].size),
318 (
'ATMSTDTRANS',
'f8', lutCat[0][
'atmStdTrans'].size)])
319 lutStd[
'PMBSTD'] = lutCat[0][
'pmbStd']
320 lutStd[
'PWVSTD'] = lutCat[0][
'pwvStd']
321 lutStd[
'O3STD'] = lutCat[0][
'o3Std']
322 lutStd[
'TAUSTD'] = lutCat[0][
'tauStd']
323 lutStd[
'ALPHASTD'] = lutCat[0][
'alphaStd']
324 lutStd[
'ZENITHSTD'] = lutCat[0][
'zenithStd']
325 lutStd[
'LAMBDARANGE'][:] = lutCat[0][
'lambdaRange'][:]
326 lutStd[
'LAMBDASTEP'] = lutCat[0][
'lambdaStep']
327 lutStd[
'LAMBDASTD'][:] = lutCat[0][
'lambdaStd']
328 lutStd[
'LAMBDASTDFILTER'][:] = lutCat[0][
'lambdaStdFilter']
329 lutStd[
'I0STD'][:] = lutCat[0][
'i0Std']
330 lutStd[
'I1STD'][:] = lutCat[0][
'i1Std']
331 lutStd[
'I10STD'][:] = lutCat[0][
'i10Std']
332 lutStd[
'I2STD'][:] = lutCat[0][
'i2Std']
333 lutStd[
'LAMBDAB'][:] = lutCat[0][
'lambdaB']
334 lutStd[
'ATMLAMBDA'][:] = lutCat[0][
'atmLambda'][:]
335 lutStd[
'ATMSTDTRANS'][:] = lutCat[0][
'atmStdTrans'][:]
337 lutTypes = [row[
'luttype']
for row
in lutCat]
340 lutFlat = np.zeros(lutCat[0][
'lut'].size, dtype=[(
'I0',
'f4'),
343 lutFlat[
'I0'][:] = lutCat[lutTypes.index(
'I0')][
'lut'][:]
344 lutFlat[
'I1'][:] = lutCat[lutTypes.index(
'I1')][
'lut'][:]
346 lutDerivFlat = np.zeros(lutCat[0][
'lut'].size, dtype=[(
'D_LNPWV',
'f4'),
350 (
'D_SECZENITH',
'f4'),
351 (
'D_LNPWV_I1',
'f4'),
353 (
'D_LNTAU_I1',
'f4'),
354 (
'D_ALPHA_I1',
'f4'),
355 (
'D_SECZENITH_I1',
'f4')])
357 for name
in lutDerivFlat.dtype.names:
358 lutDerivFlat[name][:] = lutCat[lutTypes.index(name)][
'lut'][:]
365 fgcmLut = fgcm.FgcmLUT(lutIndexVals, lutFlat, lutDerivFlat, lutStd,
366 filterToBand=physicalFilterMap)
368 return fgcmLut, lutIndexVals, lutStd
371def translateVisitCatalog(visitCat):
373 Translate the FGCM visit catalog to an fgcm-compatible object
378 FGCM visitCat from `lsst.fgcmcal.FgcmBuildStarsTask`
382 fgcmExpInfo: `numpy.ndarray`
383 Numpy array
for visit information
for FGCM
387 After running this code, it
is wise to `del visitCat` to clear the memory.
390 fgcmExpInfo = np.zeros(len(visitCat), dtype=[('VISIT',
'i8'),
394 (
'DELTA_APER',
'f8'),
395 (
'SKYBACKGROUND',
'f8'),
402 (
'FILTERNAME',
'a50')])
403 fgcmExpInfo[
'VISIT'][:] = visitCat[
'visit']
404 fgcmExpInfo[
'MJD'][:] = visitCat[
'mjd']
405 fgcmExpInfo[
'EXPTIME'][:] = visitCat[
'exptime']
406 fgcmExpInfo[
'DEEPFLAG'][:] = visitCat[
'deepFlag']
407 fgcmExpInfo[
'TELHA'][:] = visitCat[
'telha']
408 fgcmExpInfo[
'TELRA'][:] = visitCat[
'telra']
409 fgcmExpInfo[
'TELDEC'][:] = visitCat[
'teldec']
410 fgcmExpInfo[
'TELROT'][:] = visitCat[
'telrot']
411 fgcmExpInfo[
'PMB'][:] = visitCat[
'pmb']
412 fgcmExpInfo[
'PSFSIGMA'][:] = visitCat[
'psfSigma']
413 fgcmExpInfo[
'DELTA_APER'][:] = visitCat[
'deltaAper']
414 fgcmExpInfo[
'SKYBACKGROUND'][:] = visitCat[
'skyBackground']
417 fgcmExpInfo[
'FILTERNAME'][:] = visitCat.asAstropy()[
'physicalFilter']
424 Compute the median pixel scale in the camera
429 Average pixel scale (arcsecond) over the camera
433 orientation = 0.0*geom.degrees
438 boresightRotAngle=orientation,
439 rotType=afwImage.RotType.SKY)
441 pixelScales = np.zeros(len(camera))
442 for i, detector
in enumerate(camera):
443 wcs = createInitialSkyWcs(visitInfo, detector, flipX)
444 pixelScales[i] = wcs.getPixelScale().asArcseconds()
446 ok, = np.where(pixelScales > 0.0)
447 return np.median(pixelScales[ok])
450def computeApproxPixelAreaFields(camera):
452 Compute the approximate pixel area bounded fields from the camera
461 approxPixelAreaFields: `dict`
462 Dictionary of approximate area fields, keyed
with detector ID
475 boresightRotAngle=0.0*geom.degrees,
476 rotType=afwImage.RotType.SKY)
478 approxPixelAreaFields = {}
480 for i, detector
in enumerate(camera):
481 key = detector.getId()
483 wcs = createInitialSkyWcs(visitInfo, detector, flipX)
484 bbox = detector.getBBox()
487 unit=geom.arcseconds, scaling=areaScaling)
488 approxAreaField = afwMath.ChebyshevBoundedField.approximate(areaField)
490 approxPixelAreaFields[key] = approxAreaField
492 return approxPixelAreaFields
495def makeZptSchema(superStarChebyshevSize, zptChebyshevSize):
497 Make the zeropoint schema
501 superStarChebyshevSize: `int`
502 Length of the superstar chebyshev array
503 zptChebyshevSize: `int`
504 Length of the zeropoint chebyshev array
508 zptSchema: `lsst.afw.table.schema`
513 zptSchema.addField('visit', type=np.int64, doc=
'Visit number')
514 zptSchema.addField(
'detector', type=np.int32, doc=
'Detector ID number')
515 zptSchema.addField(
'fgcmFlag', type=np.int32, doc=(
'FGCM flag value: '
516 '1: Photometric, used in fit; '
517 '2: Photometric, not used in fit; '
518 '4: Non-photometric, on partly photometric night; '
519 '8: Non-photometric, on non-photometric night; '
520 '16: No zeropoint could be determined; '
521 '32: Too few stars for reliable gray computation'))
522 zptSchema.addField(
'fgcmZpt', type=np.float64, doc=
'FGCM zeropoint (center of CCD)')
523 zptSchema.addField(
'fgcmZptErr', type=np.float64,
524 doc=
'Error on zeropoint, estimated from repeatability + number of obs')
525 zptSchema.addField(
'fgcmfZptChebXyMax', type=
'ArrayD', size=2,
526 doc=
'maximum x/maximum y to scale to apply chebyshev parameters')
527 zptSchema.addField(
'fgcmfZptCheb', type=
'ArrayD',
528 size=zptChebyshevSize,
529 doc=
'Chebyshev parameters (flattened) for zeropoint')
530 zptSchema.addField(
'fgcmfZptSstarCheb', type=
'ArrayD',
531 size=superStarChebyshevSize,
532 doc=
'Chebyshev parameters (flattened) for superStarFlat')
533 zptSchema.addField(
'fgcmI0', type=np.float64, doc=
'Integral of the passband')
534 zptSchema.addField(
'fgcmI10', type=np.float64, doc=
'Normalized chromatic integral')
535 zptSchema.addField(
'fgcmR0', type=np.float64,
536 doc=
'Retrieved i0 integral, estimated from stars (only for flag 1)')
537 zptSchema.addField(
'fgcmR10', type=np.float64,
538 doc=
'Retrieved i10 integral, estimated from stars (only for flag 1)')
539 zptSchema.addField(
'fgcmGry', type=np.float64,
540 doc=
'Estimated gray extinction relative to atmospheric solution; '
541 'only for fgcmFlag <= 4 (see fgcmFlag) ')
542 zptSchema.addField(
'fgcmDeltaChrom', type=np.float64,
543 doc=
'Mean chromatic correction for stars in this ccd; '
544 'only for fgcmFlag <= 4 (see fgcmFlag)')
545 zptSchema.addField(
'fgcmZptVar', type=np.float64, doc=
'Variance of zeropoint over ccd')
546 zptSchema.addField(
'fgcmTilings', type=np.float64,
547 doc=
'Number of photometric tilings used for solution for ccd')
548 zptSchema.addField(
'fgcmFpGry', type=np.float64,
549 doc=
'Average gray extinction over the full focal plane '
550 '(same for all ccds in a visit)')
551 zptSchema.addField(
'fgcmFpGryBlue', type=np.float64,
552 doc=
'Average gray extinction over the full focal plane '
553 'for 25% bluest stars')
554 zptSchema.addField(
'fgcmFpGryBlueErr', type=np.float64,
555 doc=
'Error on Average gray extinction over the full focal plane '
556 'for 25% bluest stars')
557 zptSchema.addField(
'fgcmFpGryRed', type=np.float64,
558 doc=
'Average gray extinction over the full focal plane '
559 'for 25% reddest stars')
560 zptSchema.addField(
'fgcmFpGryRedErr', type=np.float64,
561 doc=
'Error on Average gray extinction over the full focal plane '
562 'for 25% reddest stars')
563 zptSchema.addField(
'fgcmFpVar', type=np.float64,
564 doc=
'Variance of gray extinction over the full focal plane '
565 '(same for all ccds in a visit)')
566 zptSchema.addField(
'fgcmDust', type=np.float64,
567 doc=
'Gray dust extinction from the primary/corrector'
568 'at the time of the exposure')
569 zptSchema.addField(
'fgcmFlat', type=np.float64, doc=
'Superstarflat illumination correction')
570 zptSchema.addField(
'fgcmAperCorr', type=np.float64, doc=
'Aperture correction estimated by fgcm')
571 zptSchema.addField(
'fgcmDeltaMagBkg', type=np.float64,
572 doc=(
'Local background correction from brightest percentile '
573 '(value set by deltaMagBkgOffsetPercentile) calibration '
575 zptSchema.addField(
'exptime', type=np.float32, doc=
'Exposure time')
576 zptSchema.addField(
'filtername', type=str, size=10, doc=
'Filter name')
581def makeZptCat(zptSchema, zpStruct):
583 Make the zeropoint catalog for persistence
588 Zeropoint catalog schema
589 zpStruct: `numpy.ndarray`
590 Zeropoint structure
from fgcm
595 Zeropoint catalog
for persistence
599 zptCat.reserve(zpStruct.size)
601 for filterName
in zpStruct[
'FILTERNAME']:
602 rec = zptCat.addNew()
603 rec[
'filtername'] = filterName.decode(
'utf-8')
605 zptCat[
'visit'][:] = zpStruct[FGCM_EXP_FIELD]
606 zptCat[
'detector'][:] = zpStruct[FGCM_CCD_FIELD]
607 zptCat[
'fgcmFlag'][:] = zpStruct[
'FGCM_FLAG']
608 zptCat[
'fgcmZpt'][:] = zpStruct[
'FGCM_ZPT']
609 zptCat[
'fgcmZptErr'][:] = zpStruct[
'FGCM_ZPTERR']
610 zptCat[
'fgcmfZptChebXyMax'][:, :] = zpStruct[
'FGCM_FZPT_XYMAX']
611 zptCat[
'fgcmfZptCheb'][:, :] = zpStruct[
'FGCM_FZPT_CHEB']
612 zptCat[
'fgcmfZptSstarCheb'][:, :] = zpStruct[
'FGCM_FZPT_SSTAR_CHEB']
613 zptCat[
'fgcmI0'][:] = zpStruct[
'FGCM_I0']
614 zptCat[
'fgcmI10'][:] = zpStruct[
'FGCM_I10']
615 zptCat[
'fgcmR0'][:] = zpStruct[
'FGCM_R0']
616 zptCat[
'fgcmR10'][:] = zpStruct[
'FGCM_R10']
617 zptCat[
'fgcmGry'][:] = zpStruct[
'FGCM_GRY']
618 zptCat[
'fgcmDeltaChrom'][:] = zpStruct[
'FGCM_DELTACHROM']
619 zptCat[
'fgcmZptVar'][:] = zpStruct[
'FGCM_ZPTVAR']
620 zptCat[
'fgcmTilings'][:] = zpStruct[
'FGCM_TILINGS']
621 zptCat[
'fgcmFpGry'][:] = zpStruct[
'FGCM_FPGRY']
622 zptCat[
'fgcmFpGryBlue'][:] = zpStruct[
'FGCM_FPGRY_CSPLIT'][:, 0]
623 zptCat[
'fgcmFpGryBlueErr'][:] = zpStruct[
'FGCM_FPGRY_CSPLITERR'][:, 0]
624 zptCat[
'fgcmFpGryRed'][:] = zpStruct[
'FGCM_FPGRY_CSPLIT'][:, 2]
625 zptCat[
'fgcmFpGryRedErr'][:] = zpStruct[
'FGCM_FPGRY_CSPLITERR'][:, 2]
626 zptCat[
'fgcmFpVar'][:] = zpStruct[
'FGCM_FPVAR']
627 zptCat[
'fgcmDust'][:] = zpStruct[
'FGCM_DUST']
628 zptCat[
'fgcmFlat'][:] = zpStruct[
'FGCM_FLAT']
629 zptCat[
'fgcmAperCorr'][:] = zpStruct[
'FGCM_APERCORR']
630 zptCat[
'fgcmDeltaMagBkg'][:] = zpStruct[
'FGCM_DELTAMAGBKG']
631 zptCat[
'exptime'][:] = zpStruct[
'EXPTIME']
638 Make the atmosphere schema
647 atmSchema.addField('visit', type=np.int32, doc=
'Visit number')
648 atmSchema.addField(
'pmb', type=np.float64, doc=
'Barometric pressure (mb)')
649 atmSchema.addField(
'pwv', type=np.float64, doc=
'Water vapor (mm)')
650 atmSchema.addField(
'tau', type=np.float64, doc=
'Aerosol optical depth')
651 atmSchema.addField(
'alpha', type=np.float64, doc=
'Aerosol slope')
652 atmSchema.addField(
'o3', type=np.float64, doc=
'Ozone (dobson)')
653 atmSchema.addField(
'secZenith', type=np.float64, doc=
'Secant(zenith) (~ airmass)')
654 atmSchema.addField(
'cTrans', type=np.float64, doc=
'Transmission correction factor')
655 atmSchema.addField(
'lamStd', type=np.float64, doc=
'Wavelength for transmission correction')
660def makeAtmCat(atmSchema, atmStruct):
662 Make the atmosphere catalog for persistence
667 Atmosphere catalog schema
668 atmStruct: `numpy.ndarray`
669 Atmosphere structure
from fgcm
674 Atmosphere catalog
for persistence
678 atmCat.resize(atmStruct.size)
680 atmCat['visit'][:] = atmStruct[
'VISIT']
681 atmCat[
'pmb'][:] = atmStruct[
'PMB']
682 atmCat[
'pwv'][:] = atmStruct[
'PWV']
683 atmCat[
'tau'][:] = atmStruct[
'TAU']
684 atmCat[
'alpha'][:] = atmStruct[
'ALPHA']
685 atmCat[
'o3'][:] = atmStruct[
'O3']
686 atmCat[
'secZenith'][:] = atmStruct[
'SECZENITH']
687 atmCat[
'cTrans'][:] = atmStruct[
'CTRANS']
688 atmCat[
'lamStd'][:] = atmStruct[
'LAMSTD']
693def makeStdSchema(nBands):
695 Make the standard star schema
700 Number of bands in standard star catalog
707 stdSchema = afwTable.SimpleTable.makeMinimalSchema()
708 stdSchema.addField('ngood', type=
'ArrayI', doc=
'Number of good observations',
710 stdSchema.addField(
'ntotal', type=
'ArrayI', doc=
'Number of total observations',
712 stdSchema.addField(
'mag_std_noabs', type=
'ArrayF',
713 doc=
'Standard magnitude (no absolute calibration)',
715 stdSchema.addField(
'magErr_std', type=
'ArrayF',
716 doc=
'Standard magnitude error',
718 stdSchema.addField(
'npsfcand', type=
'ArrayI',
719 doc=
'Number of observations flagged as psf candidates',
721 stdSchema.addField(
'delta_aper', type=
'ArrayF',
722 doc=
'Delta mag (small - large aperture)',
728def makeStdCat(stdSchema, stdStruct, goodBands):
730 Make the standard star catalog for persistence
735 Standard star catalog schema
736 stdStruct: `numpy.ndarray`
737 Standard star structure
in FGCM format
739 List of good band names used
in stdStruct
744 Standard star catalog
for persistence
748 stdCat.resize(stdStruct.size)
750 stdCat['id'][:] = stdStruct[
'FGCM_ID']
751 stdCat[
'coord_ra'][:] = stdStruct[
'RA'] * geom.degrees
752 stdCat[
'coord_dec'][:] = stdStruct[
'DEC'] * geom.degrees
753 stdCat[
'ngood'][:, :] = stdStruct[
'NGOOD'][:, :]
754 stdCat[
'ntotal'][:, :] = stdStruct[
'NTOTAL'][:, :]
755 stdCat[
'mag_std_noabs'][:, :] = stdStruct[
'MAG_STD'][:, :]
756 stdCat[
'magErr_std'][:, :] = stdStruct[
'MAGERR_STD'][:, :]
757 if 'NPSFCAND' in stdStruct.dtype.names:
758 stdCat[
'npsfcand'][:, :] = stdStruct[
'NPSFCAND'][:, :]
759 stdCat[
'delta_aper'][:, :] = stdStruct[
'DELTA_APER'][:, :]
762 md.set(
"BANDS",
list(goodBands))
763 stdCat.setMetadata(md)
768def computeApertureRadiusFromName(fluxField):
770 Compute the radius associated with a CircularApertureFlux
or ApFlux field.
775 CircularApertureFlux
or ApFlux
779 apertureRadius : `float`
780 Radius of the aperture field,
in pixels.
784 RuntimeError: Raised
if flux field
is not a CircularApertureFlux,
788 m = re.search(
r'(CircularApertureFlux|ApFlux|apFlux)_(\d+)_(\d+)_', fluxField)
791 raise RuntimeError(f
"Flux field {fluxField} does not correspond to a CircularApertureFlux or ApFlux")
793 apertureRadius = float(m.groups()[1]) + float(m.groups()[2])/10.
795 return apertureRadius
798def extractReferenceMags(refStars, bands, filterMap):
800 Extract reference magnitudes from refStars
for given bands
and
801 associated filterMap.
806 FGCM reference star catalog.
808 List of bands
for calibration.
810 FGCM mapping of filter to band.
814 refMag : `np.ndarray`
815 nstar x nband array of reference magnitudes.
816 refMagErr : `np.ndarray`
817 nstar x nband array of reference magnitude errors.
819 hasAstropyMeta = False
822 hasAstropyMeta =
True
823 except AttributeError:
824 meta = refStars.getMetadata()
826 if 'FILTERNAMES' in meta:
828 filternames = meta[
'FILTERNAMES']
830 filternames = meta.getArray(
'FILTERNAMES')
834 refMag = np.zeros((len(refStars), len(bands)),
835 dtype=refStars[
'refMag'].dtype) + 99.0
836 refMagErr = np.zeros_like(refMag) + 99.0
837 for i, filtername
in enumerate(filternames):
841 band = filterMap[filtername]
845 ind = bands.index(band)
849 refMag[:, ind] = refStars[
'refMag'][:, i]
850 refMagErr[:, ind] = refStars[
'refMagErr'][:, i]
852 raise RuntimeError(
"FGCM reference stars missing FILTERNAMES metadata.")
854 return refMag, refMagErr
857def lookupStaticCalibrations(datasetType, registry, quantumDataId, collections):
858 instrument = Instrument.fromName(quantumDataId[
"instrument"], registry)
859 unboundedCollection = instrument.makeUnboundedCalibrationRunName()
861 return registry.queryDatasets(datasetType,
862 dataId=quantumDataId,
863 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
computeReferencePixelScale(camera)