23 """Utility functions for fgcmcal. 
   25 This file contains utility functions that are used by more than one task, 
   26 and do not need to be part of a task. 
   44                    resetFitParameters, outputZeropoints, tract=None):
 
   46     Make the FGCM fit cycle configuration dict 
   50     config: `lsst.fgcmcal.FgcmFitCycleConfig` 
   54     camera: `lsst.afw.cameraGeom.Camera` 
   55         Camera from the butler 
   57         Maximum number of iterations 
   58     resetFitParameters: `bool` 
   59         Reset fit parameters before fitting? 
   60     outputZeropoints: `bool` 
   61         Compute zeropoints for output? 
   62     tract: `int`, optional 
   63         Tract number for extending the output file name for debugging. 
   69         Configuration dictionary for fgcm 
   72     notFitBands = [b 
for b 
in config.bands 
if b 
not in config.fitBands]
 
   76     for ccut 
in config.starColorCuts:
 
   77         parts = ccut.split(
',')
 
   78         starColorCutList.append([parts[0], parts[1], float(parts[2]), float(parts[3])])
 
   83     mirrorArea = np.pi*(camera.telescopeDiameter*100./2.)**2.
 
   86     gains = [amp.getGain() 
for detector 
in camera 
for amp 
in detector.getAmplifiers()]
 
   87     cameraGain = float(np.median(gains))
 
   90         outfileBase = config.outfileBase
 
   92         outfileBase = 
'%s-%06d' % (config.outfileBase, tract)
 
   95     configDict = {
'outfileBase': outfileBase,
 
  101                   'mirrorArea': mirrorArea,
 
  102                   'cameraGain': cameraGain,
 
  103                   'ccdStartIndex': camera[0].getId(),
 
  106                   'seeingField': 
'DELTA_APER',
 
  107                   'fwhmField': 
'PSFSIGMA',
 
  108                   'skyBrightnessField': 
'SKYBACKGROUND',
 
  109                   'deepFlag': 
'DEEPFLAG',  
 
  110                   'bands': 
list(config.bands),
 
  111                   'fitBands': 
list(config.fitBands),
 
  112                   'notFitBands': notFitBands,
 
  113                   'requiredBands': 
list(config.requiredBands),
 
  114                   'filterToBand': dict(config.filterMap),
 
  116                   'nCore': config.nCore,
 
  117                   'nStarPerRun': config.nStarPerRun,
 
  118                   'nExpPerRun': config.nExpPerRun,
 
  119                   'reserveFraction': config.reserveFraction,
 
  120                   'freezeStdAtmosphere': config.freezeStdAtmosphere,
 
  121                   'precomputeSuperStarInitialCycle': config.precomputeSuperStarInitialCycle,
 
  122                   'superStarSubCCDDict': dict(config.superStarSubCcdDict),
 
  123                   'superStarSubCCDChebyshevOrder': config.superStarSubCcdChebyshevOrder,
 
  124                   'superStarSubCCDTriangular': config.superStarSubCcdTriangular,
 
  125                   'superStarSigmaClip': config.superStarSigmaClip,
 
  126                   'ccdGraySubCCDDict': dict(config.ccdGraySubCcdDict),
 
  127                   'ccdGraySubCCDChebyshevOrder': config.ccdGraySubCcdChebyshevOrder,
 
  128                   'ccdGraySubCCDTriangular': config.ccdGraySubCcdTriangular,
 
  129                   'cycleNumber': config.cycleNumber,
 
  131                   'UTBoundary': config.utBoundary,
 
  132                   'washMJDs': config.washMjds,
 
  133                   'epochMJDs': config.epochMjds,
 
  134                   'coatingMJDs': config.coatingMjds,
 
  135                   'minObsPerBand': config.minObsPerBand,
 
  136                   'latitude': config.latitude,
 
  137                   'brightObsGrayMax': config.brightObsGrayMax,
 
  138                   'minStarPerCCD': config.minStarPerCcd,
 
  139                   'minCCDPerExp': config.minCcdPerExp,
 
  140                   'maxCCDGrayErr': config.maxCcdGrayErr,
 
  141                   'minStarPerExp': config.minStarPerExp,
 
  142                   'minExpPerNight': config.minExpPerNight,
 
  143                   'expGrayInitialCut': config.expGrayInitialCut,
 
  144                   'expGrayPhotometricCutDict': dict(config.expGrayPhotometricCutDict),
 
  145                   'expGrayHighCutDict': dict(config.expGrayHighCutDict),
 
  146                   'expGrayRecoverCut': config.expGrayRecoverCut,
 
  147                   'expVarGrayPhotometricCutDict': dict(config.expVarGrayPhotometricCutDict),
 
  148                   'expGrayErrRecoverCut': config.expGrayErrRecoverCut,
 
  149                   'refStarSnMin': config.refStarSnMin,
 
  150                   'refStarOutlierNSig': config.refStarOutlierNSig,
 
  151                   'applyRefStarColorCuts': config.applyRefStarColorCuts,
 
  152                   'illegalValue': -9999.0,  
 
  153                   'starColorCuts': starColorCutList,
 
  154                   'aperCorrFitNBins': config.aperCorrFitNBins,
 
  155                   'aperCorrInputSlopeDict': dict(config.aperCorrInputSlopeDict),
 
  156                   'sedBoundaryTermDict': config.sedboundaryterms.toDict()[
'data'],
 
  157                   'sedTermDict': config.sedterms.toDict()[
'data'],
 
  158                   'colorSplitBands': 
list(config.colorSplitBands),
 
  159                   'sigFgcmMaxErr': config.sigFgcmMaxErr,
 
  160                   'sigFgcmMaxEGrayDict': dict(config.sigFgcmMaxEGrayDict),
 
  161                   'ccdGrayMaxStarErr': config.ccdGrayMaxStarErr,
 
  162                   'approxThroughputDict': dict(config.approxThroughputDict),
 
  163                   'sigmaCalRange': 
list(config.sigmaCalRange),
 
  164                   'sigmaCalFitPercentile': 
list(config.sigmaCalFitPercentile),
 
  165                   'sigmaCalPlotPercentile': 
list(config.sigmaCalPlotPercentile),
 
  166                   'sigma0Phot': config.sigma0Phot,
 
  167                   'mapLongitudeRef': config.mapLongitudeRef,
 
  168                   'mapNSide': config.mapNSide,
 
  171                   'useRetrievedPwv': 
False,
 
  172                   'useNightlyRetrievedPwv': 
False,
 
  173                   'pwvRetrievalSmoothBlock': 25,
 
  174                   'useQuadraticPwv': config.useQuadraticPwv,
 
  175                   'useRetrievedTauInit': 
False,
 
  176                   'tauRetrievalMinCCDPerNight': 500,
 
  177                   'modelMagErrors': config.modelMagErrors,
 
  178                   'instrumentParsPerBand': config.instrumentParsPerBand,
 
  179                   'instrumentSlopeMinDeltaT': config.instrumentSlopeMinDeltaT,
 
  180                   'fitMirrorChromaticity': config.fitMirrorChromaticity,
 
  181                   'useRepeatabilityForExpGrayCutsDict': dict(config.useRepeatabilityForExpGrayCutsDict),
 
  182                   'autoPhotometricCutNSig': config.autoPhotometricCutNSig,
 
  183                   'autoHighCutNSig': config.autoHighCutNSig,
 
  185                   'quietMode': config.quietMode,
 
  186                   'outputStars': 
False,
 
  189                   'resetParameters': resetFitParameters,
 
  190                   'outputFgcmcalZpts': 
True,  
 
  191                   'outputZeropoints': outputZeropoints}
 
  198     Translate the FGCM look-up-table into an fgcm-compatible object 
  202     lutCat: `lsst.afw.table.BaseCatalog` 
  203        Catalog describing the FGCM look-up table 
  205        Filter to band mapping 
  209     fgcmLut: `lsst.fgcm.FgcmLut` 
  210        Lookup table for FGCM 
  211     lutIndexVals: `numpy.ndarray` 
  212        Numpy array with LUT index information for FGCM 
  213     lutStd: `numpy.ndarray` 
  214        Numpy array with LUT standard throughput values for FGCM 
  218     After running this code, it is wise to `del lutCat` to clear the memory. 
  223     lutFilterNames = np.array(lutCat[0][
'filterNames'].split(
','), dtype=
'a')
 
  224     lutStdFilterNames = np.array(lutCat[0][
'stdFilterNames'].split(
','), dtype=
'a')
 
  229     lutIndexVals = np.zeros(1, dtype=[(
'FILTERNAMES', lutFilterNames.dtype.str,
 
  230                                        lutFilterNames.size),
 
  231                                       (
'STDFILTERNAMES', lutStdFilterNames.dtype.str,
 
  232                                        lutStdFilterNames.size),
 
  233                                       (
'PMB', 
'f8', lutCat[0][
'pmb'].size),
 
  234                                       (
'PMBFACTOR', 
'f8', lutCat[0][
'pmbFactor'].size),
 
  235                                       (
'PMBELEVATION', 
'f8'),
 
  236                                       (
'LAMBDANORM', 
'f8'),
 
  237                                       (
'PWV', 
'f8', lutCat[0][
'pwv'].size),
 
  238                                       (
'O3', 
'f8', lutCat[0][
'o3'].size),
 
  239                                       (
'TAU', 
'f8', lutCat[0][
'tau'].size),
 
  240                                       (
'ALPHA', 
'f8', lutCat[0][
'alpha'].size),
 
  241                                       (
'ZENITH', 
'f8', lutCat[0][
'zenith'].size),
 
  244     lutIndexVals[
'FILTERNAMES'][:] = lutFilterNames
 
  245     lutIndexVals[
'STDFILTERNAMES'][:] = lutStdFilterNames
 
  246     lutIndexVals[
'PMB'][:] = lutCat[0][
'pmb']
 
  247     lutIndexVals[
'PMBFACTOR'][:] = lutCat[0][
'pmbFactor']
 
  248     lutIndexVals[
'PMBELEVATION'] = lutCat[0][
'pmbElevation']
 
  249     lutIndexVals[
'LAMBDANORM'] = lutCat[0][
'lambdaNorm']
 
  250     lutIndexVals[
'PWV'][:] = lutCat[0][
'pwv']
 
  251     lutIndexVals[
'O3'][:] = lutCat[0][
'o3']
 
  252     lutIndexVals[
'TAU'][:] = lutCat[0][
'tau']
 
  253     lutIndexVals[
'ALPHA'][:] = lutCat[0][
'alpha']
 
  254     lutIndexVals[
'ZENITH'][:] = lutCat[0][
'zenith']
 
  255     lutIndexVals[
'NCCD'] = lutCat[0][
'nCcd']
 
  258     lutStd = np.zeros(1, dtype=[(
'PMBSTD', 
'f8'),
 
  264                                 (
'LAMBDARANGE', 
'f8', 2),
 
  265                                 (
'LAMBDASTEP', 
'f8'),
 
  266                                 (
'LAMBDASTD', 
'f8', lutFilterNames.size),
 
  267                                 (
'LAMBDASTDFILTER', 
'f8', lutStdFilterNames.size),
 
  268                                 (
'I0STD', 
'f8', lutFilterNames.size),
 
  269                                 (
'I1STD', 
'f8', lutFilterNames.size),
 
  270                                 (
'I10STD', 
'f8', lutFilterNames.size),
 
  271                                 (
'I2STD', 
'f8', lutFilterNames.size),
 
  272                                 (
'LAMBDAB', 
'f8', lutFilterNames.size),
 
  273                                 (
'ATMLAMBDA', 
'f8', lutCat[0][
'atmLambda'].size),
 
  274                                 (
'ATMSTDTRANS', 
'f8', lutCat[0][
'atmStdTrans'].size)])
 
  275     lutStd[
'PMBSTD'] = lutCat[0][
'pmbStd']
 
  276     lutStd[
'PWVSTD'] = lutCat[0][
'pwvStd']
 
  277     lutStd[
'O3STD'] = lutCat[0][
'o3Std']
 
  278     lutStd[
'TAUSTD'] = lutCat[0][
'tauStd']
 
  279     lutStd[
'ALPHASTD'] = lutCat[0][
'alphaStd']
 
  280     lutStd[
'ZENITHSTD'] = lutCat[0][
'zenithStd']
 
  281     lutStd[
'LAMBDARANGE'][:] = lutCat[0][
'lambdaRange'][:]
 
  282     lutStd[
'LAMBDASTEP'] = lutCat[0][
'lambdaStep']
 
  283     lutStd[
'LAMBDASTD'][:] = lutCat[0][
'lambdaStd']
 
  284     lutStd[
'LAMBDASTDFILTER'][:] = lutCat[0][
'lambdaStdFilter']
 
  285     lutStd[
'I0STD'][:] = lutCat[0][
'i0Std']
 
  286     lutStd[
'I1STD'][:] = lutCat[0][
'i1Std']
 
  287     lutStd[
'I10STD'][:] = lutCat[0][
'i10Std']
 
  288     lutStd[
'I2STD'][:] = lutCat[0][
'i2Std']
 
  289     lutStd[
'LAMBDAB'][:] = lutCat[0][
'lambdaB']
 
  290     lutStd[
'ATMLAMBDA'][:] = lutCat[0][
'atmLambda'][:]
 
  291     lutStd[
'ATMSTDTRANS'][:] = lutCat[0][
'atmStdTrans'][:]
 
  293     lutTypes = [row[
'luttype'] 
for row 
in lutCat]
 
  296     lutFlat = np.zeros(lutCat[0][
'lut'].size, dtype=[(
'I0', 
'f4'),
 
  299     lutFlat[
'I0'][:] = lutCat[lutTypes.index(
'I0')][
'lut'][:]
 
  300     lutFlat[
'I1'][:] = lutCat[lutTypes.index(
'I1')][
'lut'][:]
 
  302     lutDerivFlat = np.zeros(lutCat[0][
'lut'].size, dtype=[(
'D_LNPWV', 
'f4'),
 
  306                                                           (
'D_SECZENITH', 
'f4'),
 
  307                                                           (
'D_LNPWV_I1', 
'f4'),
 
  309                                                           (
'D_LNTAU_I1', 
'f4'),
 
  310                                                           (
'D_ALPHA_I1', 
'f4'),
 
  311                                                           (
'D_SECZENITH_I1', 
'f4')])
 
  313     for name 
in lutDerivFlat.dtype.names:
 
  314         lutDerivFlat[name][:] = lutCat[lutTypes.index(name)][
'lut'][:]
 
  321     fgcmLut = fgcm.FgcmLUT(lutIndexVals, lutFlat, lutDerivFlat, lutStd,
 
  322                            filterToBand=filterMap)
 
  324     return fgcmLut, lutIndexVals, lutStd
 
  329     Translate the FGCM visit catalog to an fgcm-compatible object 
  333     visitCat: `lsst.afw.table.BaseCatalog` 
  334        FGCM visitCat from `lsst.fgcmcal.FgcmBuildStarsTask` 
  338     fgcmExpInfo: `numpy.ndarray` 
  339        Numpy array for visit information for FGCM 
  343     After running this code, it is wise to `del visitCat` to clear the memory. 
  346     fgcmExpInfo = np.zeros(len(visitCat), dtype=[(
'VISIT', 
'i8'),
 
  350                                                  (
'DELTA_APER', 
'f8'),
 
  351                                                  (
'SKYBACKGROUND', 
'f8'),
 
  358                                                  (
'FILTERNAME', 
'a10')])
 
  359     fgcmExpInfo[
'VISIT'][:] = visitCat[
'visit']
 
  360     fgcmExpInfo[
'MJD'][:] = visitCat[
'mjd']
 
  361     fgcmExpInfo[
'EXPTIME'][:] = visitCat[
'exptime']
 
  362     fgcmExpInfo[
'DEEPFLAG'][:] = visitCat[
'deepFlag']
 
  363     fgcmExpInfo[
'TELHA'][:] = visitCat[
'telha']
 
  364     fgcmExpInfo[
'TELRA'][:] = visitCat[
'telra']
 
  365     fgcmExpInfo[
'TELDEC'][:] = visitCat[
'teldec']
 
  366     fgcmExpInfo[
'TELROT'][:] = visitCat[
'telrot']
 
  367     fgcmExpInfo[
'PMB'][:] = visitCat[
'pmb']
 
  368     fgcmExpInfo[
'PSFSIGMA'][:] = visitCat[
'psfSigma']
 
  369     fgcmExpInfo[
'DELTA_APER'][:] = visitCat[
'deltaAper']
 
  370     fgcmExpInfo[
'SKYBACKGROUND'][:] = visitCat[
'skyBackground']
 
  373     fgcmExpInfo[
'FILTERNAME'][:] = visitCat.asAstropy()[
'filtername']
 
  380     Compute the CCD offsets in ra/dec and x/y space 
  384     camera: `lsst.afw.cameraGeom.Camera` 
  385     defaultOrientation: `float` 
  386        Default camera orientation (degrees) 
  390     ccdOffsets: `numpy.ndarray` 
  391        Numpy array with ccd offset information for input to FGCM. 
  392        Angular units are degrees, and x/y units are pixels. 
  397     ccdOffsets = np.zeros(len(camera), dtype=[(
'CCDNUM', 
'i4'),
 
  412     if camera.getName() == 
'HSC' and np.isnan(defaultOrientation):
 
  413         orientation = 270*geom.degrees
 
  415         orientation = defaultOrientation*geom.degrees
 
  420                                    boresightRotAngle=orientation,
 
  421                                    rotType=afwImage.visitInfo.RotType.SKY)
 
  423     for i, detector 
in enumerate(camera):
 
  424         ccdOffsets[
'CCDNUM'][i] = detector.getId()
 
  428         detCenter = wcs.pixelToSky(detector.getCenter(afwCameraGeom.PIXELS))
 
  429         ccdOffsets[
'DELTA_RA'][i] = (detCenter.getRa() - boresight.getRa()).asDegrees()
 
  430         ccdOffsets[
'DELTA_DEC'][i] = (detCenter.getDec() - boresight.getDec()).asDegrees()
 
  432         bbox = detector.getBBox()
 
  434         detCorner1 = wcs.pixelToSky(
geom.Point2D(bbox.getMin()))
 
  435         detCorner2 = wcs.pixelToSky(
geom.Point2D(bbox.getMax()))
 
  437         ccdOffsets[
'RA_SIZE'][i] = np.abs((detCorner2.getRa() - detCorner1.getRa()).asDegrees())
 
  438         ccdOffsets[
'DEC_SIZE'][i] = np.abs((detCorner2.getDec() - detCorner1.getDec()).asDegrees())
 
  440         ccdOffsets[
'X_SIZE'][i] = bbox.getMaxX()
 
  441         ccdOffsets[
'Y_SIZE'][i] = bbox.getMaxY()
 
  448     Compute the median pixel scale in the camera 
  453        Average pixel scale (arcsecond) over the camera 
  457     orientation = 0.0*geom.degrees
 
  462                                    boresightRotAngle=orientation,
 
  463                                    rotType=afwImage.visitInfo.RotType.SKY)
 
  465     pixelScales = np.zeros(len(camera))
 
  466     for i, detector 
in enumerate(camera):
 
  468         pixelScales[i] = wcs.getPixelScale().asArcseconds()
 
  470     ok, = np.where(pixelScales > 0.0)
 
  471     return np.median(pixelScales[ok])
 
  476     Compute the approximate pixel area bounded fields from the camera 
  481     camera: `lsst.afw.cameraGeom.Camera` 
  485     approxPixelAreaFields: `dict` 
  486        Dictionary of approximate area fields, keyed with detector ID 
  499                                    boresightRotAngle=0.0*geom.degrees,
 
  500                                    rotType=afwImage.visitInfo.RotType.SKY)
 
  502     approxPixelAreaFields = {}
 
  504     for i, detector 
in enumerate(camera):
 
  505         key = detector.getId()
 
  508         bbox = detector.getBBox()
 
  511                                                   unit=geom.arcseconds, scaling=areaScaling)
 
  512         approxAreaField = afwMath.ChebyshevBoundedField.approximate(areaField)
 
  514         approxPixelAreaFields[key] = approxAreaField
 
  516     return approxPixelAreaFields
 
  521     Make the zeropoint schema 
  525     superStarChebyshevSize: `int` 
  526        Length of the superstar chebyshev array 
  527     zptChebyshevSize: `int` 
  528        Length of the zeropoint chebyshev array 
  532     zptSchema: `lsst.afw.table.schema` 
  537     zptSchema.addField(
'visit', type=np.int32, doc=
'Visit number')
 
  538     zptSchema.addField(
'ccd', type=np.int32, doc=
'CCD number')
 
  539     zptSchema.addField(
'fgcmFlag', type=np.int32, doc=(
'FGCM flag value: ' 
  540                                                        '1: Photometric, used in fit; ' 
  541                                                        '2: Photometric, not used in fit; ' 
  542                                                        '4: Non-photometric, on partly photometric night; ' 
  543                                                        '8: Non-photometric, on non-photometric night; ' 
  544                                                        '16: No zeropoint could be determined; ' 
  545                                                        '32: Too few stars for reliable gray computation'))
 
  546     zptSchema.addField(
'fgcmZpt', type=np.float64, doc=
'FGCM zeropoint (center of CCD)')
 
  547     zptSchema.addField(
'fgcmZptErr', type=np.float64,
 
  548                        doc=
'Error on zeropoint, estimated from repeatability + number of obs')
 
  549     zptSchema.addField(
'fgcmfZptChebXyMax', type=
'ArrayD', size=2,
 
  550                        doc=
'maximum x/maximum y to scale to apply chebyshev parameters')
 
  551     zptSchema.addField(
'fgcmfZptCheb', type=
'ArrayD',
 
  552                        size=zptChebyshevSize,
 
  553                        doc=
'Chebyshev parameters (flattened) for zeropoint')
 
  554     zptSchema.addField(
'fgcmfZptSstarCheb', type=
'ArrayD',
 
  555                        size=superStarChebyshevSize,
 
  556                        doc=
'Chebyshev parameters (flattened) for superStarFlat')
 
  557     zptSchema.addField(
'fgcmI0', type=np.float64, doc=
'Integral of the passband')
 
  558     zptSchema.addField(
'fgcmI10', type=np.float64, doc=
'Normalized chromatic integral')
 
  559     zptSchema.addField(
'fgcmR0', type=np.float64,
 
  560                        doc=
'Retrieved i0 integral, estimated from stars (only for flag 1)')
 
  561     zptSchema.addField(
'fgcmR10', type=np.float64,
 
  562                        doc=
'Retrieved i10 integral, estimated from stars (only for flag 1)')
 
  563     zptSchema.addField(
'fgcmGry', type=np.float64,
 
  564                        doc=
'Estimated gray extinction relative to atmospheric solution; ' 
  565                        'only for flag <= 4')
 
  566     zptSchema.addField(
'fgcmZptVar', type=np.float64, doc=
'Variance of zeropoint over ccd')
 
  567     zptSchema.addField(
'fgcmTilings', type=np.float64,
 
  568                        doc=
'Number of photometric tilings used for solution for ccd')
 
  569     zptSchema.addField(
'fgcmFpGry', type=np.float64,
 
  570                        doc=
'Average gray extinction over the full focal plane ' 
  571                        '(same for all ccds in a visit)')
 
  572     zptSchema.addField(
'fgcmFpGryBlue', type=np.float64,
 
  573                        doc=
'Average gray extinction over the full focal plane ' 
  574                        'for 25% bluest stars')
 
  575     zptSchema.addField(
'fgcmFpGryBlueErr', type=np.float64,
 
  576                        doc=
'Error on Average gray extinction over the full focal plane ' 
  577                        'for 25% bluest stars')
 
  578     zptSchema.addField(
'fgcmFpGryRed', type=np.float64,
 
  579                        doc=
'Average gray extinction over the full focal plane ' 
  580                        'for 25% reddest stars')
 
  581     zptSchema.addField(
'fgcmFpGryRedErr', type=np.float64,
 
  582                        doc=
'Error on Average gray extinction over the full focal plane ' 
  583                        'for 25% reddest stars')
 
  584     zptSchema.addField(
'fgcmFpVar', type=np.float64,
 
  585                        doc=
'Variance of gray extinction over the full focal plane ' 
  586                        '(same for all ccds in a visit)')
 
  587     zptSchema.addField(
'fgcmDust', type=np.float64,
 
  588                        doc=
'Gray dust extinction from the primary/corrector' 
  589                        'at the time of the exposure')
 
  590     zptSchema.addField(
'fgcmFlat', type=np.float64, doc=
'Superstarflat illumination correction')
 
  591     zptSchema.addField(
'fgcmAperCorr', type=np.float64, doc=
'Aperture correction estimated by fgcm')
 
  592     zptSchema.addField(
'exptime', type=np.float32, doc=
'Exposure time')
 
  593     zptSchema.addField(
'filtername', type=str, size=10, doc=
'Filter name')
 
  600     Make the zeropoint catalog for persistence 
  604     zptSchema: `lsst.afw.table.Schema` 
  605        Zeropoint catalog schema 
  606     zpStruct: `numpy.ndarray` 
  607        Zeropoint structure from fgcm 
  611     zptCat: `afwTable.BaseCatalog` 
  612        Zeropoint catalog for persistence 
  616     zptCat.reserve(zpStruct.size)
 
  618     for filterName 
in zpStruct[
'FILTERNAME']:
 
  619         rec = zptCat.addNew()
 
  620         rec[
'filtername'] = filterName.decode(
'utf-8')
 
  622     zptCat[
'visit'][:] = zpStruct[
'VISIT']
 
  623     zptCat[
'ccd'][:] = zpStruct[
'CCD']
 
  624     zptCat[
'fgcmFlag'][:] = zpStruct[
'FGCM_FLAG']
 
  625     zptCat[
'fgcmZpt'][:] = zpStruct[
'FGCM_ZPT']
 
  626     zptCat[
'fgcmZptErr'][:] = zpStruct[
'FGCM_ZPTERR']
 
  627     zptCat[
'fgcmfZptChebXyMax'][:, :] = zpStruct[
'FGCM_FZPT_XYMAX']
 
  628     zptCat[
'fgcmfZptCheb'][:, :] = zpStruct[
'FGCM_FZPT_CHEB']
 
  629     zptCat[
'fgcmfZptSstarCheb'][:, :] = zpStruct[
'FGCM_FZPT_SSTAR_CHEB']
 
  630     zptCat[
'fgcmI0'][:] = zpStruct[
'FGCM_I0']
 
  631     zptCat[
'fgcmI10'][:] = zpStruct[
'FGCM_I10']
 
  632     zptCat[
'fgcmR0'][:] = zpStruct[
'FGCM_R0']
 
  633     zptCat[
'fgcmR10'][:] = zpStruct[
'FGCM_R10']
 
  634     zptCat[
'fgcmGry'][:] = zpStruct[
'FGCM_GRY']
 
  635     zptCat[
'fgcmZptVar'][:] = zpStruct[
'FGCM_ZPTVAR']
 
  636     zptCat[
'fgcmTilings'][:] = zpStruct[
'FGCM_TILINGS']
 
  637     zptCat[
'fgcmFpGry'][:] = zpStruct[
'FGCM_FPGRY']
 
  638     zptCat[
'fgcmFpGryBlue'][:] = zpStruct[
'FGCM_FPGRY_CSPLIT'][:, 0]
 
  639     zptCat[
'fgcmFpGryBlueErr'][:] = zpStruct[
'FGCM_FPGRY_CSPLITERR'][:, 0]
 
  640     zptCat[
'fgcmFpGryRed'][:] = zpStruct[
'FGCM_FPGRY_CSPLIT'][:, 2]
 
  641     zptCat[
'fgcmFpGryRedErr'][:] = zpStruct[
'FGCM_FPGRY_CSPLITERR'][:, 2]
 
  642     zptCat[
'fgcmFpVar'][:] = zpStruct[
'FGCM_FPVAR']
 
  643     zptCat[
'fgcmDust'][:] = zpStruct[
'FGCM_DUST']
 
  644     zptCat[
'fgcmFlat'][:] = zpStruct[
'FGCM_FLAT']
 
  645     zptCat[
'fgcmAperCorr'][:] = zpStruct[
'FGCM_APERCORR']
 
  646     zptCat[
'exptime'][:] = zpStruct[
'EXPTIME']
 
  653     Make the atmosphere schema 
  657     atmSchema: `lsst.afw.table.Schema` 
  662     atmSchema.addField(
'visit', type=np.int32, doc=
'Visit number')
 
  663     atmSchema.addField(
'pmb', type=np.float64, doc=
'Barometric pressure (mb)')
 
  664     atmSchema.addField(
'pwv', type=np.float64, doc=
'Water vapor (mm)')
 
  665     atmSchema.addField(
'tau', type=np.float64, doc=
'Aerosol optical depth')
 
  666     atmSchema.addField(
'alpha', type=np.float64, doc=
'Aerosol slope')
 
  667     atmSchema.addField(
'o3', type=np.float64, doc=
'Ozone (dobson)')
 
  668     atmSchema.addField(
'secZenith', type=np.float64, doc=
'Secant(zenith) (~ airmass)')
 
  669     atmSchema.addField(
'cTrans', type=np.float64, doc=
'Transmission correction factor')
 
  670     atmSchema.addField(
'lamStd', type=np.float64, doc=
'Wavelength for transmission correction')
 
  677     Make the atmosphere catalog for persistence 
  681     atmSchema: `lsst.afw.table.Schema` 
  682        Atmosphere catalog schema 
  683     atmStruct: `numpy.ndarray` 
  684        Atmosphere structure from fgcm 
  688     atmCat: `lsst.afw.table.BaseCatalog` 
  689        Atmosphere catalog for persistence 
  693     atmCat.reserve(atmStruct.size)
 
  694     for i 
in range(atmStruct.size):
 
  697     atmCat[
'visit'][:] = atmStruct[
'VISIT']
 
  698     atmCat[
'pmb'][:] = atmStruct[
'PMB']
 
  699     atmCat[
'pwv'][:] = atmStruct[
'PWV']
 
  700     atmCat[
'tau'][:] = atmStruct[
'TAU']
 
  701     atmCat[
'alpha'][:] = atmStruct[
'ALPHA']
 
  702     atmCat[
'o3'][:] = atmStruct[
'O3']
 
  703     atmCat[
'secZenith'][:] = atmStruct[
'SECZENITH']
 
  704     atmCat[
'cTrans'][:] = atmStruct[
'CTRANS']
 
  705     atmCat[
'lamStd'][:] = atmStruct[
'LAMSTD']
 
  712     Make the standard star schema 
  717        Number of bands in standard star catalog 
  721     stdSchema: `lsst.afw.table.Schema` 
  724     stdSchema = afwTable.SimpleTable.makeMinimalSchema()
 
  725     stdSchema.addField(
'ngood', type=
'ArrayI', doc=
'Number of good observations',
 
  727     stdSchema.addField(
'ntotal', type=
'ArrayI', doc=
'Number of total observations',
 
  729     stdSchema.addField(
'mag_std_noabs', type=
'ArrayF',
 
  730                        doc=
'Standard magnitude (no absolute calibration)',
 
  732     stdSchema.addField(
'magErr_std', type=
'ArrayF',
 
  733                        doc=
'Standard magnitude error',
 
  735     stdSchema.addField(
'npsfcand', type=
'ArrayI',
 
  736                        doc=
'Number of observations flagged as psf candidates',
 
  744     Make the standard star catalog for persistence 
  748     stdSchema: `lsst.afw.table.Schema` 
  749        Standard star catalog schema 
  750     stdStruct: `numpy.ndarray` 
  751        Standard star structure in FGCM format 
  753        List of good band names used in stdStruct 
  757     stdCat: `lsst.afw.table.BaseCatalog` 
  758        Standard star catalog for persistence 
  763     stdCat.reserve(stdStruct.size)
 
  764     for i 
in range(stdStruct.size):
 
  767     stdCat[
'id'][:] = stdStruct[
'FGCM_ID']
 
  768     stdCat[
'coord_ra'][:] = stdStruct[
'RA'] * geom.degrees
 
  769     stdCat[
'coord_dec'][:] = stdStruct[
'DEC'] * geom.degrees
 
  770     stdCat[
'ngood'][:, :] = stdStruct[
'NGOOD'][:, :]
 
  771     stdCat[
'ntotal'][:, :] = stdStruct[
'NTOTAL'][:, :]
 
  772     stdCat[
'mag_std_noabs'][:, :] = stdStruct[
'MAG_STD'][:, :]
 
  773     stdCat[
'magErr_std'][:, :] = stdStruct[
'MAGERR_STD'][:, :]
 
  774     stdCat[
'npsfcand'][:, :] = stdStruct[
'NPSFCAND'][:, :]
 
  777     md.set(
"BANDS", 
list(goodBands))
 
  778     stdCat.setMetadata(md)
 
  785     Compute the radius associated with a CircularApertureFlux field or 
  790     schema : `lsst.afw.table.schema` 
  792        CircularApertureFlux field or associated slot. 
  796     apertureRadius: `float` 
  797        Radius of the aperture field, in pixels. 
  801     RuntimeError: Raised if flux field is not a CircularApertureFlux 
  804     fluxFieldName = schema[fluxField].asField().getName()
 
  806     m = re.search(
r'CircularApertureFlux_(\d+)_(\d+)_', fluxFieldName)
 
  809         raise RuntimeError(
"Flux field %s does not correspond to a circular aperture" 
  812     apertureRadius = float(m.groups()[0]) + float(m.groups()[1])/10.
 
  814     return apertureRadius
 
  819     Extract reference magnitudes from refStars for given bands and 
  820     associated filterMap. 
  824     refStars : `lsst.afw.table.BaseCatalog` 
  825        FGCM reference star catalog 
  827        List of bands for calibration 
  829        FGCM mapping of filter to band 
  833     refMag : `np.ndarray` 
  834        nstar x nband array of reference magnitudes 
  835     refMagErr : `np.ndarray` 
  836        nstar x nband array of reference magnitude errors 
  842     md = refStars.getMetadata()
 
  843     if 'FILTERNAMES' in md:
 
  844         filternames = md.getArray(
'FILTERNAMES')
 
  848         refMag = np.zeros((len(refStars), len(bands)),
 
  849                           dtype=refStars[
'refMag'].dtype) + 99.0
 
  850         refMagErr = np.zeros_like(refMag) + 99.0
 
  851         for i, filtername 
in enumerate(filternames):
 
  855                 band = filterMap[filtername]
 
  859                 ind = bands.index(band)
 
  863             refMag[:, ind] = refStars[
'refMag'][:, i]
 
  864             refMagErr[:, ind] = refStars[
'refMagErr'][:, i]
 
  868         refMag = refStars[
'refMag'][:, :]
 
  869         refMagErr = refStars[
'refMagErr'][:, :]
 
  871     return refMag, refMagErr