23 """Perform a single fit cycle of FGCM. 
   25 This task runs a single "fit cycle" of fgcm.  Prior to running this task 
   26 one must run both fgcmMakeLut (to construct the atmosphere and instrumental 
   27 look-up-table) and fgcmBuildStars (to extract visits and star observations 
   30 The fgcmFitCycle is meant to be run multiple times, and is tracked by the 
   31 'cycleNumber'.  After each run of the fit cycle, diagnostic plots should 
   32 be inspected to set parameters for outlier rejection on the following 
   33 cycle.  Please see the fgcmcal Cookbook for details. 
   42 import lsst.pex.config 
as pexConfig
 
   46 from .utilities 
import makeConfigDict, translateFgcmLut, translateVisitCatalog
 
   47 from .utilities 
import extractReferenceMags
 
   48 from .utilities 
import computeCcdOffsets, makeZptSchema, makeZptCat
 
   49 from .utilities 
import makeAtmSchema, makeAtmCat, makeStdSchema, makeStdCat
 
   50 from .sedterms 
import SedboundarytermDict, SedtermDict
 
   54 __all__ = [
'FgcmFitCycleConfig', 
'FgcmFitCycleTask', 
'FgcmFitCycleRunner']
 
   58     """Config for FgcmFitCycle""" 
   60     bands = pexConfig.ListField(
 
   61         doc=
"Bands to run calibration",
 
   65     fitFlag = pexConfig.ListField(
 
   66         doc=(
"Flag for which bands are directly constrained in the FGCM fit. " 
   67              "Bands set to 0 will have the atmosphere constrained from observations " 
   68              "in other bands on the same night.  Must be same length as config.bands, " 
   69              "and matched band-by-band."),
 
   73         deprecated=(
"This field is no longer used, and has been deprecated by DM-23699. " 
   74                     "It will be removed after v20.  Use fitBands instead."),
 
   76     fitBands = pexConfig.ListField(
 
   77         doc=(
"Bands to use in atmospheric fit. The bands not listed here will have " 
   78              "the atmosphere constrained from the 'fitBands' on the same night. " 
   79              "Must be a subset of `config.bands`"),
 
   83     requiredFlag = pexConfig.ListField(
 
   84         doc=(
"Flag for which bands are required for a star to be considered a calibration " 
   85              "star in the FGCM fit.  Typically this should be the same as fitFlag.  Must " 
   86              "be same length as config.bands, and matched band-by-band."),
 
   90         deprecated=(
"This field is no longer used, and has been deprecated by DM-23699. " 
   91                     "It will be removed after v20.  Use requiredBands instead."),
 
   93     requiredBands = pexConfig.ListField(
 
   94         doc=(
"Bands that are required for a star to be considered a calibration star. " 
   95              "Must be a subset of `config.bands`"),
 
   99     filterMap = pexConfig.DictField(
 
  100         doc=
"Mapping from 'filterName' to band.",
 
  105     doReferenceCalibration = pexConfig.Field(
 
  106         doc=
"Use reference catalog as additional constraint on calibration",
 
  110     refStarSnMin = pexConfig.Field(
 
  111         doc=
"Reference star signal-to-noise minimum to use in calibration.  Set to <=0 for no cut.",
 
  115     refStarOutlierNSig = pexConfig.Field(
 
  116         doc=(
"Number of sigma compared to average mag for reference star to be considered an outlier. " 
  117              "Computed per-band, and if it is an outlier in any band it is rejected from fits."),
 
  121     applyRefStarColorCuts = pexConfig.Field(
 
  122         doc=
"Apply color cuts to reference stars?",
 
  126     nCore = pexConfig.Field(
 
  127         doc=
"Number of cores to use",
 
  131     nStarPerRun = pexConfig.Field(
 
  132         doc=
"Number of stars to run in each chunk",
 
  136     nExpPerRun = pexConfig.Field(
 
  137         doc=
"Number of exposures to run in each chunk",
 
  141     reserveFraction = pexConfig.Field(
 
  142         doc=
"Fraction of stars to reserve for testing",
 
  146     freezeStdAtmosphere = pexConfig.Field(
 
  147         doc=
"Freeze atmosphere parameters to standard (for testing)",
 
  151     precomputeSuperStarInitialCycle = pexConfig.Field(
 
  152         doc=
"Precompute superstar flat for initial cycle",
 
  156     superStarSubCcd = pexConfig.Field(
 
  157         doc=
"Compute superstar flat on sub-ccd scale",
 
  161         deprecated=(
"This field is no longer used, and has been deprecated by DM-23699. " 
  162                     "It will be removed after v20.  Use superStarSubCcdDict instead."),
 
  164     superStarSubCcdDict = pexConfig.DictField(
 
  165         doc=(
"Per-band specification on whether to compute superstar flat on sub-ccd scale. " 
  166              "Must have one entry per band."),
 
  171     superStarSubCcdChebyshevOrder = pexConfig.Field(
 
  172         doc=(
"Order of the 2D chebyshev polynomials for sub-ccd superstar fit. " 
  173              "Global default is first-order polynomials, and should be overridden " 
  174              "on a camera-by-camera basis depending on the ISR."),
 
  178     superStarSubCcdTriangular = pexConfig.Field(
 
  179         doc=(
"Should the sub-ccd superstar chebyshev matrix be triangular to " 
  180              "suppress high-order cross terms?"),
 
  184     superStarSigmaClip = pexConfig.Field(
 
  185         doc=
"Number of sigma to clip outliers when selecting for superstar flats",
 
  189     ccdGraySubCcd = pexConfig.Field(
 
  190         doc=
"Compute CCD gray terms on sub-ccd scale",
 
  194         deprecated=(
"This field is no longer used, and has been deprecated by DM-23699. " 
  195                     "It will be removed after v20.  Use ccdGraySubCcdDict instead."),
 
  197     ccdGraySubCcdDict = pexConfig.DictField(
 
  198         doc=(
"Per-band specification on whether to compute achromatic per-ccd residual " 
  199              "('ccd gray') on a sub-ccd scale."),
 
  204     ccdGraySubCcdChebyshevOrder = pexConfig.Field(
 
  205         doc=
"Order of the 2D chebyshev polynomials for sub-ccd gray fit.",
 
  209     ccdGraySubCcdTriangular = pexConfig.Field(
 
  210         doc=(
"Should the sub-ccd gray chebyshev matrix be triangular to " 
  211              "suppress high-order cross terms?"),
 
  215     cycleNumber = pexConfig.Field(
 
  216         doc=(
"FGCM fit cycle number.  This is automatically incremented after each run " 
  217              "and stage of outlier rejection.  See cookbook for details."),
 
  221     isFinalCycle = pexConfig.Field(
 
  222         doc=(
"Is this the final cycle of the fitting?  Will automatically compute final " 
  223              "selection of stars and photometric exposures, and will output zeropoints " 
  224              "and standard stars for use in fgcmOutputProducts"),
 
  228     maxIterBeforeFinalCycle = pexConfig.Field(
 
  229         doc=(
"Maximum fit iterations, prior to final cycle.  The number of iterations " 
  230              "will always be 0 in the final cycle for cleanup and final selection."),
 
  234     utBoundary = pexConfig.Field(
 
  235         doc=
"Boundary (in UTC) from day-to-day",
 
  239     washMjds = pexConfig.ListField(
 
  240         doc=
"Mirror wash MJDs",
 
  244     epochMjds = pexConfig.ListField(
 
  245         doc=
"Epoch boundaries in MJD",
 
  249     minObsPerBand = pexConfig.Field(
 
  250         doc=
"Minimum good observations per band",
 
  256     latitude = pexConfig.Field(
 
  257         doc=
"Observatory latitude",
 
  261     brightObsGrayMax = pexConfig.Field(
 
  262         doc=
"Maximum gray extinction to be considered bright observation",
 
  266     minStarPerCcd = pexConfig.Field(
 
  267         doc=(
"Minimum number of good stars per CCD to be used in calibration fit. " 
  268              "CCDs with fewer stars will have their calibration estimated from other " 
  269              "CCDs in the same visit, with zeropoint error increased accordingly."),
 
  273     minCcdPerExp = pexConfig.Field(
 
  274         doc=(
"Minimum number of good CCDs per exposure/visit to be used in calibration fit. " 
  275              "Visits with fewer good CCDs will have CCD zeropoints estimated where possible."),
 
  279     maxCcdGrayErr = pexConfig.Field(
 
  280         doc=
"Maximum error on CCD gray offset to be considered photometric",
 
  284     minStarPerExp = pexConfig.Field(
 
  285         doc=(
"Minimum number of good stars per exposure/visit to be used in calibration fit. " 
  286              "Visits with fewer good stars will have CCD zeropoints estimated where possible."),
 
  290     minExpPerNight = pexConfig.Field(
 
  291         doc=
"Minimum number of good exposures/visits to consider a partly photometric night",
 
  295     expGrayInitialCut = pexConfig.Field(
 
  296         doc=(
"Maximum exposure/visit gray value for initial selection of possible photometric " 
  301     expGrayPhotometricCut = pexConfig.ListField(
 
  302         doc=(
"Maximum (negative) exposure gray for a visit to be considered photometric. " 
  303              "Must be same length as config.bands, and matched band-by-band."),
 
  307         deprecated=(
"This field is no longer used, and has been deprecated by DM-23699. " 
  308                     "It will be removed after v20.  Use expGrayPhotometricCutDict instead."),
 
  310     expGrayPhotometricCutDict = pexConfig.DictField(
 
  311         doc=(
"Per-band specification on maximum (negative) achromatic exposure residual " 
  312              "('gray term') for a visit to be considered photometric.  Must have one " 
  313              "entry per band. Broad-band filters should be -0.05."),
 
  318     expGrayHighCut = pexConfig.ListField(
 
  319         doc=(
"Maximum (positive) exposure gray for a visit to be considered photometric. " 
  320              "Must be same length as config.bands, and matched band-by-band."),
 
  324         deprecated=(
"This field is no longer used, and has been deprecated by DM-23699. " 
  325                     "It will be removed after v20.  Use expGrayHighCutDict instead."),
 
  327     expGrayHighCutDict = pexConfig.DictField(
 
  328         doc=(
"Per-band specification on maximum (positive) achromatic exposure residual " 
  329              "('gray term') for a visit to be considered photometric.  Must have one " 
  330              "entry per band.  Broad-band filters should be 0.2."),
 
  335     expGrayRecoverCut = pexConfig.Field(
 
  336         doc=(
"Maximum (negative) exposure gray to be able to recover bad ccds via interpolation. " 
  337              "Visits with more gray extinction will only get CCD zeropoints if there are " 
  338              "sufficient star observations (minStarPerCcd) on that CCD."),
 
  342     expVarGrayPhotometricCut = pexConfig.Field(
 
  343         doc=
"Maximum exposure variance to be considered possibly photometric",
 
  347         deprecated=(
"This field is no longer used, and has been deprecated by DM-23699. " 
  348                     "It will be removed after v20.  Use expVarGrayPhotometricCutDict instead."),
 
  350     expVarGrayPhotometricCutDict = pexConfig.DictField(
 
  351         doc=(
"Per-band specification on maximum exposure variance to be considered possibly " 
  352              "photometric.  Must have one entry per band.  Broad-band filters should be " 
  358     expGrayErrRecoverCut = pexConfig.Field(
 
  359         doc=(
"Maximum exposure gray error to be able to recover bad ccds via interpolation. " 
  360              "Visits with more gray variance will only get CCD zeropoints if there are " 
  361              "sufficient star observations (minStarPerCcd) on that CCD."),
 
  365     aperCorrFitNBins = pexConfig.Field(
 
  366         doc=(
"Number of aperture bins used in aperture correction fit.  When set to 0" 
  367              "no fit will be performed, and the config.aperCorrInputSlopes will be " 
  368              "used if available."),
 
  372     aperCorrInputSlopes = pexConfig.ListField(
 
  373         doc=(
"Aperture correction input slope parameters.  These are used on the first " 
  374              "fit iteration, and aperture correction parameters will be updated from " 
  375              "the data if config.aperCorrFitNBins > 0.  It is recommended to set this" 
  376              "when there is insufficient data to fit the parameters (e.g. tract mode). " 
  377              "If set, must be same length as config.bands, and matched band-by-band."),
 
  381         deprecated=(
"This field is no longer used, and has been deprecated by DM-23699. " 
  382                     "It will be removed after v20.  Use aperCorrInputSlopeDict instead."),
 
  384     aperCorrInputSlopeDict = pexConfig.DictField(
 
  385         doc=(
"Per-band specification of aperture correction input slope parameters.  These " 
  386              "are used on the first fit iteration, and aperture correction parameters will " 
  387              "be updated from the data if config.aperCorrFitNBins > 0.  It is recommended " 
  388              "to set this when there is insufficient data to fit the parameters (e.g. " 
  394     sedFudgeFactors = pexConfig.ListField(
 
  395         doc=(
"Fudge factors for computing linear SED from colors.  Must be same length as " 
  396              "config.bands, and matched band-by-band."),
 
  400         deprecated=(
"This field has been deprecated and will be removed after v20. " 
  401                     "Please use sedSlopeTermMap and sedSlopeMap."),
 
  403     sedboundaryterms = pexConfig.ConfigField(
 
  404         doc=
"Mapping from bands to SED boundary term names used is sedterms.",
 
  405         dtype=SedboundarytermDict,
 
  407     sedterms = pexConfig.ConfigField(
 
  408         doc=
"Mapping from terms to bands for fgcm linear SED approximations.",
 
  411     sigFgcmMaxErr = pexConfig.Field(
 
  412         doc=
"Maximum mag error for fitting sigma_FGCM",
 
  416     sigFgcmMaxEGray = pexConfig.ListField(
 
  417         doc=(
"Maximum (absolute) gray value for observation in sigma_FGCM. " 
  418              "May be 1 element (same for all bands) or the same length as config.bands."),
 
  422         deprecated=(
"This field is no longer used, and has been deprecated by DM-23699. " 
  423                     "It will be removed after v20.  Use sigFgcmMaxEGrayDict instead."),
 
  425     sigFgcmMaxEGrayDict = pexConfig.DictField(
 
  426         doc=(
"Per-band specification for maximum (absolute) achromatic residual (gray value) " 
  427              "for observations in sigma_fgcm (raw repeatability).  Broad-band filters " 
  433     ccdGrayMaxStarErr = pexConfig.Field(
 
  434         doc=(
"Maximum error on a star observation to use in ccd gray (achromatic residual) " 
  439     approxThroughput = pexConfig.ListField(
 
  440         doc=(
"Approximate overall throughput at start of calibration observations. " 
  441              "May be 1 element (same for all bands) or the same length as config.bands."),
 
  445         deprecated=(
"This field is no longer used, and has been deprecated by DM-23699. " 
  446                     "It will be removed after v20.  Use approxThroughputDict instead."),
 
  448     approxThroughputDict = pexConfig.DictField(
 
  449         doc=(
"Per-band specification of the approximate overall throughput at the start of " 
  450              "calibration observations.  Must have one entry per band.  Typically should " 
  456     sigmaCalRange = pexConfig.ListField(
 
  457         doc=
"Allowed range for systematic error floor estimation",
 
  459         default=(0.001, 0.003),
 
  461     sigmaCalFitPercentile = pexConfig.ListField(
 
  462         doc=
"Magnitude percentile range to fit systematic error floor",
 
  464         default=(0.05, 0.15),
 
  466     sigmaCalPlotPercentile = pexConfig.ListField(
 
  467         doc=
"Magnitude percentile range to plot systematic error floor",
 
  469         default=(0.05, 0.95),
 
  471     sigma0Phot = pexConfig.Field(
 
  472         doc=
"Systematic error floor for all zeropoints",
 
  476     mapLongitudeRef = pexConfig.Field(
 
  477         doc=
"Reference longitude for plotting maps",
 
  481     mapNSide = pexConfig.Field(
 
  482         doc=
"Healpix nside for plotting maps",
 
  486     outfileBase = pexConfig.Field(
 
  487         doc=
"Filename start for plot output files",
 
  491     starColorCuts = pexConfig.ListField(
 
  492         doc=
"Encoded star-color cuts (to be cleaned up)",
 
  494         default=(
"NO_DATA",),
 
  496     colorSplitIndices = pexConfig.ListField(
 
  497         doc=
"Band indices to use to split stars by color",
 
  501         deprecated=(
"This field is no longer used, and has been deprecated by DM-23699. " 
  502                     "It will be removed after v20.  Use colorSplitBands instead."),
 
  504     colorSplitBands = pexConfig.ListField(
 
  505         doc=
"Band names to use to split stars by color.  Must have 2 entries.",
 
  510     modelMagErrors = pexConfig.Field(
 
  511         doc=
"Should FGCM model the magnitude errors from sky/fwhm? (False means trust inputs)",
 
  515     useQuadraticPwv = pexConfig.Field(
 
  516         doc=
"Model PWV with a quadratic term for variation through the night?",
 
  520     instrumentParsPerBand = pexConfig.Field(
 
  521         doc=(
"Model instrumental parameters per band? " 
  522              "Otherwise, instrumental parameters (QE changes with time) are " 
  523              "shared among all bands."),
 
  527     instrumentSlopeMinDeltaT = pexConfig.Field(
 
  528         doc=(
"Minimum time change (in days) between observations to use in constraining " 
  529              "instrument slope."),
 
  533     fitMirrorChromaticity = pexConfig.Field(
 
  534         doc=
"Fit (intraband) mirror chromatic term?",
 
  538     coatingMjds = pexConfig.ListField(
 
  539         doc=
"Mirror coating dates in MJD",
 
  543     outputStandardsBeforeFinalCycle = pexConfig.Field(
 
  544         doc=
"Output standard stars prior to final cycle?  Used in debugging.",
 
  548     outputZeropointsBeforeFinalCycle = pexConfig.Field(
 
  549         doc=
"Output standard stars prior to final cycle?  Used in debugging.",
 
  553     useRepeatabilityForExpGrayCuts = pexConfig.ListField(
 
  554         doc=(
"Use star repeatability (instead of exposures) for computing photometric " 
  555              "cuts? Recommended for tract mode or bands with few exposures. " 
  556              "May be 1 element (same for all bands) or the same length as config.bands."),
 
  560         deprecated=(
"This field is no longer used, and has been deprecated by DM-23699. " 
  561                     "It will be removed after v20.  Use useRepeatabilityForExpGrayCutsDict instead."),
 
  563     useRepeatabilityForExpGrayCutsDict = pexConfig.DictField(
 
  564         doc=(
"Per-band specification on whether to use star repeatability (instead of exposures) " 
  565              "for computing photometric cuts. Recommended for tract mode or bands with few visits."),
 
  570     autoPhotometricCutNSig = pexConfig.Field(
 
  571         doc=(
"Number of sigma for automatic computation of (low) photometric cut. " 
  572              "Cut is based on exposure gray width (per band), unless " 
  573              "useRepeatabilityForExpGrayCuts is set, in which case the star " 
  574              "repeatability is used (also per band)."),
 
  578     autoHighCutNSig = pexConfig.Field(
 
  579         doc=(
"Number of sigma for automatic computation of (high) outlier cut. " 
  580              "Cut is based on exposure gray width (per band), unless " 
  581              "useRepeatabilityForExpGrayCuts is set, in which case the star " 
  582              "repeatability is used (also per band)."),
 
  586     quietMode = pexConfig.Field(
 
  587         doc=
"Be less verbose with logging.",
 
  598         for band 
in self.fitBands:
 
  599             if band 
not in self.bands:
 
  600                 msg = 
'fitBand %s not in bands' % (band)
 
  601                 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.fitBands, self, msg)
 
  602         for band 
in self.requiredBands:
 
  603             if band 
not in self.bands:
 
  604                 msg = 
'requiredBand %s not in bands' % (band)
 
  605                 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.requiredBands, self, msg)
 
  606         for band 
in self.colorSplitBands:
 
  607             if band 
not in self.bands:
 
  608                 msg = 
'colorSplitBand %s not in bands' % (band)
 
  609                 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.colorSplitBands, self, msg)
 
  610         for band 
in self.bands:
 
  611             if band 
not in self.superStarSubCcdDict:
 
  612                 msg = 
'band %s not in superStarSubCcdDict' % (band)
 
  613                 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.superStarSubCcdDict,
 
  615             if band 
not in self.ccdGraySubCcdDict:
 
  616                 msg = 
'band %s not in ccdGraySubCcdDict' % (band)
 
  617                 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.ccdGraySubCcdDict,
 
  619             if band 
not in self.expGrayPhotometricCutDict:
 
  620                 msg = 
'band %s not in expGrayPhotometricCutDict' % (band)
 
  621                 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.expGrayPhotometricCutDict,
 
  623             if band 
not in self.expGrayHighCutDict:
 
  624                 msg = 
'band %s not in expGrayHighCutDict' % (band)
 
  625                 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.expGrayHighCutDict,
 
  627             if band 
not in self.expVarGrayPhotometricCutDict:
 
  628                 msg = 
'band %s not in expVarGrayPhotometricCutDict' % (band)
 
  629                 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.expVarGrayPhotometricCutDict,
 
  631             if band 
not in self.sigFgcmMaxEGrayDict:
 
  632                 msg = 
'band %s not in sigFgcmMaxEGrayDict' % (band)
 
  633                 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.sigFgcmMaxEGrayDict,
 
  635             if band 
not in self.approxThroughputDict:
 
  636                 msg = 
'band %s not in approxThroughputDict' % (band)
 
  637                 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.approxThroughputDict,
 
  639             if band 
not in self.useRepeatabilityForExpGrayCutsDict:
 
  640                 msg = 
'band %s not in useRepeatabilityForExpGrayCutsDict' % (band)
 
  641                 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.useRepeatabilityForExpGrayCutsDict,
 
  646     """Subclass of TaskRunner for fgcmFitCycleTask 
  648     fgcmFitCycleTask.run() takes one argument, the butler, and uses 
  649     stars and visits previously extracted from dataRefs by 
  651     This Runner does not perform any dataRef parallelization, but the FGCM 
  652     code called by the Task uses python multiprocessing (see the "ncores" 
  659         Return a list with one element, the butler. 
  661         return [parsedCmd.butler]
 
  667         butler: `lsst.daf.persistence.Butler` 
  671         exitStatus: `list` with `pipeBase.Struct` 
  672            exitStatus (0: success; 1: failure) 
  675         task = self.TaskClass(config=self.config, log=self.log)
 
  679             task.runDataRef(butler)
 
  682                 task.runDataRef(butler)
 
  683             except Exception 
as e:
 
  685                 task.log.fatal(
"Failed: %s" % e)
 
  686                 if not isinstance(e, pipeBase.TaskError):
 
  687                     traceback.print_exc(file=sys.stderr)
 
  689         task.writeMetadata(butler)
 
  692         return [pipeBase.Struct(exitStatus=exitStatus)]
 
  696         Run the task, with no multiprocessing 
  700         parsedCmd: ArgumentParser parsed command line 
  705         if self.precall(parsedCmd):
 
  708             resultList = self(targetList[0])
 
  715     Run Single fit cycle for FGCM global calibration 
  718     ConfigClass = FgcmFitCycleConfig
 
  719     RunnerClass = FgcmFitCycleRunner
 
  720     _DefaultName = 
"fgcmFitCycle" 
  724         Instantiate an fgcmFitCycle. 
  728         butler : `lsst.daf.persistence.Butler` 
  731         pipeBase.CmdLineTask.__init__(self, **kwargs)
 
  734     def _getMetadataName(self):
 
  740         Run a single fit cycle for FGCM 
  744         butler:  `lsst.daf.persistence.Butler` 
  750         """Write the configuration used for processing the data, or check that an existing 
  751         one is equal to the new one if present.  This is an override of the regular 
  752         version from pipe_base that knows about fgcmcycle. 
  756         butler : `lsst.daf.persistence.Butler` 
  757             Data butler used to write the config. The config is written to dataset type 
  758             `CmdLineTask._getConfigName`. 
  759         clobber : `bool`, optional 
  760             A boolean flag that controls what happens if a config already has been saved: 
  761             - `True`: overwrite or rename the existing config, depending on ``doBackup``. 
  762             - `False`: raise `TaskError` if this config does not match the existing config. 
  763         doBackup : `bool`, optional 
  764             Set to `True` to backup the config files if clobbering. 
  766         configName = self._getConfigName()
 
  767         if configName 
is None:
 
  770             butler.put(self.config, configName, doBackup=doBackup, fgcmcycle=self.config.cycleNumber)
 
  771         elif butler.datasetExists(configName, write=
True, fgcmcycle=self.config.cycleNumber):
 
  774                 oldConfig = butler.get(configName, immediate=
True, fgcmcycle=self.config.cycleNumber)
 
  775             except Exception 
as exc:
 
  776                 raise type(exc)(
"Unable to read stored config file %s (%s); consider using --clobber-config" %
 
  779             def logConfigMismatch(msg):
 
  780                 self.log.
fatal(
"Comparing configuration: %s", msg)
 
  782             if not self.config.compare(oldConfig, shortcut=
False, output=logConfigMismatch):
 
  783                 raise pipeBase.TaskError(
 
  784                     (
"Config does not match existing task config %r on disk; tasks configurations " +
 
  785                      "must be consistent within the same output repo (override with --clobber-config)") %
 
  788             butler.put(self.config, configName, fgcmcycle=self.config.cycleNumber)
 
  790     def _fgcmFitCycle(self, butler):
 
  796         butler: `lsst.daf.persistence.Butler` 
  802         self.
maxIter = self.config.maxIterBeforeFinalCycle
 
  807         if self.config.isFinalCycle:
 
  816         camera = butler.get(
'camera')
 
  821         lutCat = butler.get(
'fgcmLookUpTable')
 
  822         fgcmLut, lutIndexVals, lutStd = 
translateFgcmLut(lutCat, dict(self.config.filterMap))
 
  828         visitCat = butler.get(
'fgcmVisitCatalog')
 
  836         noFitsDict = {
'lutIndex': lutIndexVals,
 
  838                       'expInfo': fgcmExpInfo,
 
  839                       'ccdOffsets': ccdOffsets}
 
  842         fgcmFitCycle = fgcm.FgcmFitCycle(configDict, useFits=
False,
 
  843                                          noFitsDict=noFitsDict, noOutput=
True)
 
  846         if (fgcmFitCycle.initialCycle):
 
  848             fgcmPars = fgcm.FgcmParameters.newParsWithArrays(fgcmFitCycle.fgcmConfig,
 
  853             fgcmPars = fgcm.FgcmParameters.loadParsWithArrays(fgcmFitCycle.fgcmConfig,
 
  859         lastCycle = configDict[
'cycleNumber'] - 1
 
  862         fgcmStars = fgcm.FgcmStars(fgcmFitCycle.fgcmConfig)
 
  864         starObs = butler.get(
'fgcmStarObservations')
 
  865         starIds = butler.get(
'fgcmStarIds')
 
  866         starIndices = butler.get(
'fgcmStarIndices')
 
  869         if butler.datasetExists(
'fgcmFlaggedStars', fgcmcycle=lastCycle):
 
  870             flaggedStars = butler.get(
'fgcmFlaggedStars', fgcmcycle=lastCycle)
 
  871             flagId = flaggedStars[
'objId'][:]
 
  872             flagFlag = flaggedStars[
'objFlag'][:]
 
  877         if self.config.doReferenceCalibration:
 
  878             refStars = butler.get(
'fgcmReferenceStars')
 
  882                                                      self.config.filterMap)
 
  883             refId = refStars[
'fgcm_id'][:]
 
  892         visitIndex = np.searchsorted(fgcmExpInfo[
'VISIT'], starObs[
'visit'][starIndices[
'obsIndex']])
 
  904         conv = starObs[0][
'ra'].asDegrees() / float(starObs[0][
'ra'])
 
  906         fgcmStars.loadStars(fgcmPars,
 
  907                             starObs[
'visit'][starIndices[
'obsIndex']],
 
  908                             starObs[
'ccd'][starIndices[
'obsIndex']],
 
  909                             starObs[
'ra'][starIndices[
'obsIndex']] * conv,
 
  910                             starObs[
'dec'][starIndices[
'obsIndex']] * conv,
 
  911                             starObs[
'instMag'][starIndices[
'obsIndex']],
 
  912                             starObs[
'instMagErr'][starIndices[
'obsIndex']],
 
  913                             fgcmExpInfo[
'FILTERNAME'][visitIndex],
 
  914                             starIds[
'fgcm_id'][:],
 
  917                             starIds[
'obsArrIndex'][:],
 
  919                             obsX=starObs[
'x'][starIndices[
'obsIndex']],
 
  920                             obsY=starObs[
'y'][starIndices[
'obsIndex']],
 
  921                             psfCandidate=starObs[
'psf_candidate'][starIndices[
'obsIndex']],
 
  939         fgcmFitCycle.setLUT(fgcmLut)
 
  940         fgcmFitCycle.setStars(fgcmStars)
 
  941         fgcmFitCycle.setPars(fgcmPars)
 
  944         fgcmFitCycle.finishSetup()
 
  958         updatedPhotometricCutDict = {b: float(fgcmFitCycle.updatedPhotometricCut[i]) 
for 
  959                                      i, b 
in enumerate(self.config.bands)}
 
  960         updatedHighCutDict = {band: float(fgcmFitCycle.updatedHighCut[i]) 
for 
  961                               i, band 
in enumerate(self.config.bands)}
 
  963         outConfig = copy.copy(self.config)
 
  964         outConfig.update(cycleNumber=(self.config.cycleNumber + 1),
 
  965                          precomputeSuperStarInitialCycle=
False,
 
  966                          freezeStdAtmosphere=
False,
 
  967                          expGrayPhotometricCutDict=updatedPhotometricCutDict,
 
  968                          expGrayHighCutDict=updatedHighCutDict)
 
  969         configFileName = 
'%s_cycle%02d_config.py' % (outConfig.outfileBase,
 
  970                                                      outConfig.cycleNumber)
 
  971         outConfig.save(configFileName)
 
  973         if self.config.isFinalCycle == 1:
 
  975             self.log.
info(
"Everything is in place to run fgcmOutputProducts.py")
 
  977             self.log.
info(
"Saved config for next cycle to %s" % (configFileName))
 
  978             self.log.
info(
"Be sure to look at:")
 
  979             self.log.
info(
"   config.expGrayPhotometricCut")
 
  980             self.log.
info(
"   config.expGrayHighCut")
 
  981             self.log.
info(
"If you are satisfied with the fit, please set:")
 
  982             self.log.
info(
"   config.isFinalCycle = True")
 
  984     def _checkDatasetsExist(self, butler):
 
  986         Check if necessary datasets exist to run fgcmFitCycle 
  990         butler: `lsst.daf.persistence.Butler` 
  995            If any of fgcmVisitCatalog, fgcmStarObservations, fgcmStarIds, 
  996            fgcmStarIndices, fgcmLookUpTable datasets do not exist. 
  997            If cycleNumber > 0, then also checks for fgcmFitParameters, 
 1001         if not butler.datasetExists(
'fgcmVisitCatalog'):
 
 1002             raise RuntimeError(
"Could not find fgcmVisitCatalog in repo!")
 
 1003         if not butler.datasetExists(
'fgcmStarObservations'):
 
 1004             raise RuntimeError(
"Could not find fgcmStarObservations in repo!")
 
 1005         if not butler.datasetExists(
'fgcmStarIds'):
 
 1006             raise RuntimeError(
"Could not find fgcmStarIds in repo!")
 
 1007         if not butler.datasetExists(
'fgcmStarIndices'):
 
 1008             raise RuntimeError(
"Could not find fgcmStarIndices in repo!")
 
 1009         if not butler.datasetExists(
'fgcmLookUpTable'):
 
 1010             raise RuntimeError(
"Could not find fgcmLookUpTable in repo!")
 
 1013         if (self.config.cycleNumber > 0):
 
 1014             if not butler.datasetExists(
'fgcmFitParameters',
 
 1015                                         fgcmcycle=self.config.cycleNumber-1):
 
 1016                 raise RuntimeError(
"Could not find fgcmFitParameters for previous cycle (%d) in repo!" %
 
 1017                                    (self.config.cycleNumber-1))
 
 1018             if not butler.datasetExists(
'fgcmFlaggedStars',
 
 1019                                         fgcmcycle=self.config.cycleNumber-1):
 
 1020                 raise RuntimeError(
"Could not find fgcmFlaggedStars for previous cycle (%d) in repo!" %
 
 1021                                    (self.config.cycleNumber-1))
 
 1024         if self.config.doReferenceCalibration:
 
 1025             if not butler.datasetExists(
'fgcmReferenceStars'):
 
 1026                 raise RuntimeError(
"Could not find fgcmReferenceStars in repo, and " 
 1027                                    "doReferenceCalibration is True.")
 
 1029     def _loadParameters(self, butler):
 
 1031         Load FGCM parameters from a previous fit cycle 
 1035         butler:  `lsst.daf.persistence.Butler` 
 1039         inParInfo: `numpy.ndarray` 
 1040            Numpy array parameter information formatted for input to fgcm 
 1041         inParameters: `numpy.ndarray` 
 1042            Numpy array parameter values formatted for input to fgcm 
 1043         inSuperStar: `numpy.array` 
 1044            Superstar flat formatted for input to fgcm 
 1048         parCat = butler.get(
'fgcmFitParameters', fgcmcycle=self.config.cycleNumber-1)
 
 1050         parLutFilterNames = np.array(parCat[0][
'lutFilterNames'].split(
','))
 
 1051         parFitBands = np.array(parCat[0][
'fitBands'].split(
','))
 
 1052         parNotFitBands = np.array(parCat[0][
'notFitBands'].split(
','))
 
 1054         inParInfo = np.zeros(1, dtype=[(
'NCCD', 
'i4'),
 
 1055                                        (
'LUTFILTERNAMES', parLutFilterNames.dtype.str,
 
 1056                                         (parLutFilterNames.size, )),
 
 1057                                        (
'FITBANDS', parFitBands.dtype.str, (parFitBands.size, )),
 
 1058                                        (
'NOTFITBANDS', parNotFitBands.dtype.str, (parNotFitBands.size, )),
 
 1059                                        (
'LNTAUUNIT', 
'f8'),
 
 1060                                        (
'LNTAUSLOPEUNIT', 
'f8'),
 
 1061                                        (
'ALPHAUNIT', 
'f8'),
 
 1062                                        (
'LNPWVUNIT', 
'f8'),
 
 1063                                        (
'LNPWVSLOPEUNIT', 
'f8'),
 
 1064                                        (
'LNPWVQUADRATICUNIT', 
'f8'),
 
 1065                                        (
'LNPWVGLOBALUNIT', 
'f8'),
 
 1067                                        (
'QESYSUNIT', 
'f8'),
 
 1068                                        (
'FILTEROFFSETUNIT', 
'f8'),
 
 1069                                        (
'HASEXTERNALPWV', 
'i2'),
 
 1070                                        (
'HASEXTERNALTAU', 
'i2')])
 
 1071         inParInfo[
'NCCD'] = parCat[
'nCcd']
 
 1072         inParInfo[
'LUTFILTERNAMES'][:] = parLutFilterNames
 
 1073         inParInfo[
'FITBANDS'][:] = parFitBands
 
 1074         inParInfo[
'NOTFITBANDS'][:] = parNotFitBands
 
 1075         inParInfo[
'HASEXTERNALPWV'] = parCat[
'hasExternalPwv']
 
 1076         inParInfo[
'HASEXTERNALTAU'] = parCat[
'hasExternalTau']
 
 1078         inParams = np.zeros(1, dtype=[(
'PARALPHA', 
'f8', (parCat[
'parAlpha'].size, )),
 
 1079                                       (
'PARO3', 
'f8', (parCat[
'parO3'].size, )),
 
 1080                                       (
'PARLNTAUINTERCEPT', 
'f8',
 
 1081                                        (parCat[
'parLnTauIntercept'].size, )),
 
 1082                                       (
'PARLNTAUSLOPE', 
'f8',
 
 1083                                        (parCat[
'parLnTauSlope'].size, )),
 
 1084                                       (
'PARLNPWVINTERCEPT', 
'f8',
 
 1085                                        (parCat[
'parLnPwvIntercept'].size, )),
 
 1086                                       (
'PARLNPWVSLOPE', 
'f8',
 
 1087                                        (parCat[
'parLnPwvSlope'].size, )),
 
 1088                                       (
'PARLNPWVQUADRATIC', 
'f8',
 
 1089                                        (parCat[
'parLnPwvQuadratic'].size, )),
 
 1090                                       (
'PARQESYSINTERCEPT', 
'f8',
 
 1091                                        (parCat[
'parQeSysIntercept'].size, )),
 
 1092                                       (
'COMPQESYSSLOPE', 
'f8',
 
 1093                                        (parCat[
'compQeSysSlope'].size, )),
 
 1094                                       (
'PARFILTEROFFSET', 
'f8',
 
 1095                                        (parCat[
'parFilterOffset'].size, )),
 
 1096                                       (
'PARFILTEROFFSETFITFLAG', 
'i2',
 
 1097                                        (parCat[
'parFilterOffsetFitFlag'].size, )),
 
 1098                                       (
'PARRETRIEVEDLNPWVSCALE', 
'f8'),
 
 1099                                       (
'PARRETRIEVEDLNPWVOFFSET', 
'f8'),
 
 1100                                       (
'PARRETRIEVEDLNPWVNIGHTLYOFFSET', 
'f8',
 
 1101                                        (parCat[
'parRetrievedLnPwvNightlyOffset'].size, )),
 
 1102                                       (
'COMPABSTHROUGHPUT', 
'f8',
 
 1103                                        (parCat[
'compAbsThroughput'].size, )),
 
 1104                                       (
'COMPREFOFFSET', 
'f8',
 
 1105                                        (parCat[
'compRefOffset'].size, )),
 
 1106                                       (
'COMPREFSIGMA', 
'f8',
 
 1107                                        (parCat[
'compRefSigma'].size, )),
 
 1108                                       (
'COMPMIRRORCHROMATICITY', 
'f8',
 
 1109                                        (parCat[
'compMirrorChromaticity'].size, )),
 
 1110                                       (
'MIRRORCHROMATICITYPIVOT', 
'f8',
 
 1111                                        (parCat[
'mirrorChromaticityPivot'].size, )),
 
 1112                                       (
'COMPAPERCORRPIVOT', 
'f8',
 
 1113                                        (parCat[
'compAperCorrPivot'].size, )),
 
 1114                                       (
'COMPAPERCORRSLOPE', 
'f8',
 
 1115                                        (parCat[
'compAperCorrSlope'].size, )),
 
 1116                                       (
'COMPAPERCORRSLOPEERR', 
'f8',
 
 1117                                        (parCat[
'compAperCorrSlopeErr'].size, )),
 
 1118                                       (
'COMPAPERCORRRANGE', 
'f8',
 
 1119                                        (parCat[
'compAperCorrRange'].size, )),
 
 1120                                       (
'COMPMODELERREXPTIMEPIVOT', 
'f8',
 
 1121                                        (parCat[
'compModelErrExptimePivot'].size, )),
 
 1122                                       (
'COMPMODELERRFWHMPIVOT', 
'f8',
 
 1123                                        (parCat[
'compModelErrFwhmPivot'].size, )),
 
 1124                                       (
'COMPMODELERRSKYPIVOT', 
'f8',
 
 1125                                        (parCat[
'compModelErrSkyPivot'].size, )),
 
 1126                                       (
'COMPMODELERRPARS', 
'f8',
 
 1127                                        (parCat[
'compModelErrPars'].size, )),
 
 1128                                       (
'COMPEXPGRAY', 
'f8',
 
 1129                                        (parCat[
'compExpGray'].size, )),
 
 1130                                       (
'COMPVARGRAY', 
'f8',
 
 1131                                        (parCat[
'compVarGray'].size, )),
 
 1132                                       (
'COMPNGOODSTARPEREXP', 
'i4',
 
 1133                                        (parCat[
'compNGoodStarPerExp'].size, )),
 
 1134                                       (
'COMPSIGFGCM', 
'f8',
 
 1135                                        (parCat[
'compSigFgcm'].size, )),
 
 1136                                       (
'COMPSIGMACAL', 
'f8',
 
 1137                                        (parCat[
'compSigmaCal'].size, )),
 
 1138                                       (
'COMPRETRIEVEDLNPWV', 
'f8',
 
 1139                                        (parCat[
'compRetrievedLnPwv'].size, )),
 
 1140                                       (
'COMPRETRIEVEDLNPWVRAW', 
'f8',
 
 1141                                        (parCat[
'compRetrievedLnPwvRaw'].size, )),
 
 1142                                       (
'COMPRETRIEVEDLNPWVFLAG', 
'i2',
 
 1143                                        (parCat[
'compRetrievedLnPwvFlag'].size, )),
 
 1144                                       (
'COMPRETRIEVEDTAUNIGHT', 
'f8',
 
 1145                                        (parCat[
'compRetrievedTauNight'].size, ))])
 
 1147         inParams[
'PARALPHA'][:] = parCat[
'parAlpha'][0, :]
 
 1148         inParams[
'PARO3'][:] = parCat[
'parO3'][0, :]
 
 1149         inParams[
'PARLNTAUINTERCEPT'][:] = parCat[
'parLnTauIntercept'][0, :]
 
 1150         inParams[
'PARLNTAUSLOPE'][:] = parCat[
'parLnTauSlope'][0, :]
 
 1151         inParams[
'PARLNPWVINTERCEPT'][:] = parCat[
'parLnPwvIntercept'][0, :]
 
 1152         inParams[
'PARLNPWVSLOPE'][:] = parCat[
'parLnPwvSlope'][0, :]
 
 1153         inParams[
'PARLNPWVQUADRATIC'][:] = parCat[
'parLnPwvQuadratic'][0, :]
 
 1154         inParams[
'PARQESYSINTERCEPT'][:] = parCat[
'parQeSysIntercept'][0, :]
 
 1155         inParams[
'COMPQESYSSLOPE'][:] = parCat[
'compQeSysSlope'][0, :]
 
 1156         inParams[
'PARFILTEROFFSET'][:] = parCat[
'parFilterOffset'][0, :]
 
 1157         inParams[
'PARFILTEROFFSETFITFLAG'][:] = parCat[
'parFilterOffsetFitFlag'][0, :]
 
 1158         inParams[
'PARRETRIEVEDLNPWVSCALE'] = parCat[
'parRetrievedLnPwvScale']
 
 1159         inParams[
'PARRETRIEVEDLNPWVOFFSET'] = parCat[
'parRetrievedLnPwvOffset']
 
 1160         inParams[
'PARRETRIEVEDLNPWVNIGHTLYOFFSET'][:] = parCat[
'parRetrievedLnPwvNightlyOffset'][0, :]
 
 1161         inParams[
'COMPABSTHROUGHPUT'][:] = parCat[
'compAbsThroughput'][0, :]
 
 1162         inParams[
'COMPREFOFFSET'][:] = parCat[
'compRefOffset'][0, :]
 
 1163         inParams[
'COMPREFSIGMA'][:] = parCat[
'compRefSigma'][0, :]
 
 1164         inParams[
'COMPMIRRORCHROMATICITY'][:] = parCat[
'compMirrorChromaticity'][0, :]
 
 1165         inParams[
'MIRRORCHROMATICITYPIVOT'][:] = parCat[
'mirrorChromaticityPivot'][0, :]
 
 1166         inParams[
'COMPAPERCORRPIVOT'][:] = parCat[
'compAperCorrPivot'][0, :]
 
 1167         inParams[
'COMPAPERCORRSLOPE'][:] = parCat[
'compAperCorrSlope'][0, :]
 
 1168         inParams[
'COMPAPERCORRSLOPEERR'][:] = parCat[
'compAperCorrSlopeErr'][0, :]
 
 1169         inParams[
'COMPAPERCORRRANGE'][:] = parCat[
'compAperCorrRange'][0, :]
 
 1170         inParams[
'COMPMODELERREXPTIMEPIVOT'][:] = parCat[
'compModelErrExptimePivot'][0, :]
 
 1171         inParams[
'COMPMODELERRFWHMPIVOT'][:] = parCat[
'compModelErrFwhmPivot'][0, :]
 
 1172         inParams[
'COMPMODELERRSKYPIVOT'][:] = parCat[
'compModelErrSkyPivot'][0, :]
 
 1173         inParams[
'COMPMODELERRPARS'][:] = parCat[
'compModelErrPars'][0, :]
 
 1174         inParams[
'COMPEXPGRAY'][:] = parCat[
'compExpGray'][0, :]
 
 1175         inParams[
'COMPVARGRAY'][:] = parCat[
'compVarGray'][0, :]
 
 1176         inParams[
'COMPNGOODSTARPEREXP'][:] = parCat[
'compNGoodStarPerExp'][0, :]
 
 1177         inParams[
'COMPSIGFGCM'][:] = parCat[
'compSigFgcm'][0, :]
 
 1178         inParams[
'COMPSIGMACAL'][:] = parCat[
'compSigmaCal'][0, :]
 
 1179         inParams[
'COMPRETRIEVEDLNPWV'][:] = parCat[
'compRetrievedLnPwv'][0, :]
 
 1180         inParams[
'COMPRETRIEVEDLNPWVRAW'][:] = parCat[
'compRetrievedLnPwvRaw'][0, :]
 
 1181         inParams[
'COMPRETRIEVEDLNPWVFLAG'][:] = parCat[
'compRetrievedLnPwvFlag'][0, :]
 
 1182         inParams[
'COMPRETRIEVEDTAUNIGHT'][:] = parCat[
'compRetrievedTauNight'][0, :]
 
 1184         inSuperStar = np.zeros(parCat[
'superstarSize'][0, :], dtype=
'f8')
 
 1185         inSuperStar[:, :, :, :] = parCat[
'superstar'][0, :].reshape(inSuperStar.shape)
 
 1187         return (inParInfo, inParams, inSuperStar)
 
 1189     def _persistFgcmDatasets(self, butler, fgcmFitCycle):
 
 1191         Persist FGCM datasets through the butler. 
 1195         butler: `lsst.daf.persistence.Butler` 
 1196         fgcmFitCycle: `lsst.fgcm.FgcmFitCycle` 
 1197            Fgcm Fit cycle object 
 1201         parInfo, pars = fgcmFitCycle.fgcmPars.parsToArrays()
 
 1206         lutFilterNameString = comma.join([n.decode(
'utf-8')
 
 1207                                           for n 
in parInfo[
'LUTFILTERNAMES'][0]])
 
 1208         fitBandString = comma.join([n.decode(
'utf-8')
 
 1209                                     for n 
in parInfo[
'FITBANDS'][0]])
 
 1210         notFitBandString = comma.join([n.decode(
'utf-8')
 
 1211                                        for n 
in parInfo[
'NOTFITBANDS'][0]])
 
 1213         parSchema = self.
_makeParSchema(parInfo, pars, fgcmFitCycle.fgcmPars.parSuperStarFlat,
 
 1214                                         lutFilterNameString, fitBandString, notFitBandString)
 
 1216                                       fgcmFitCycle.fgcmPars.parSuperStarFlat,
 
 1217                                       lutFilterNameString, fitBandString, notFitBandString)
 
 1219         butler.put(parCat, 
'fgcmFitParameters', fgcmcycle=self.config.cycleNumber)
 
 1225         flagStarStruct = fgcmFitCycle.fgcmStars.getFlagStarIndices()
 
 1228         butler.put(flagStarCat, 
'fgcmFlaggedStars', fgcmcycle=self.config.cycleNumber)
 
 1232             superStarChebSize = fgcmFitCycle.fgcmZpts.zpStruct[
'FGCM_FZPT_SSTAR_CHEB'].shape[1]
 
 1233             zptChebSize = fgcmFitCycle.fgcmZpts.zpStruct[
'FGCM_FZPT_CHEB'].shape[1]
 
 1236             zptCat = 
makeZptCat(zptSchema, fgcmFitCycle.fgcmZpts.zpStruct)
 
 1238             butler.put(zptCat, 
'fgcmZeropoints', fgcmcycle=self.config.cycleNumber)
 
 1243             atmCat = 
makeAtmCat(atmSchema, fgcmFitCycle.fgcmZpts.atmStruct)
 
 1245             butler.put(atmCat, 
'fgcmAtmosphereParameters', fgcmcycle=self.config.cycleNumber)
 
 1249             stdStruct, goodBands = fgcmFitCycle.fgcmStars.retrieveStdStarCatalog(fgcmFitCycle.fgcmPars)
 
 1251             stdCat = 
makeStdCat(stdSchema, stdStruct, goodBands)
 
 1253             butler.put(stdCat, 
'fgcmStandardStars', fgcmcycle=self.config.cycleNumber)
 
 1255     def _makeParSchema(self, parInfo, pars, parSuperStarFlat,
 
 1256                        lutFilterNameString, fitBandString, notFitBandString):
 
 1258         Make the parameter persistence schema 
 1262         parInfo: `numpy.ndarray` 
 1263            Parameter information returned by fgcm 
 1264         pars: `numpy.ndarray` 
 1265            Parameter values returned by fgcm 
 1266         parSuperStarFlat: `numpy.array` 
 1267            Superstar flat values returned by fgcm 
 1268         lutFilterNameString: `str` 
 1269            Combined string of all the lutFilterNames 
 1270         fitBandString: `str` 
 1271            Combined string of all the fitBands 
 1272         notFitBandString: `str` 
 1273            Combined string of all the bands not used in the fit 
 1277         parSchema: `afwTable.schema` 
 1283         parSchema.addField(
'nCcd', type=np.int32, doc=
'Number of CCDs')
 
 1284         parSchema.addField(
'lutFilterNames', type=str, doc=
'LUT Filter names in parameter file',
 
 1285                            size=len(lutFilterNameString))
 
 1286         parSchema.addField(
'fitBands', type=str, doc=
'Bands that were fit',
 
 1287                            size=len(fitBandString))
 
 1288         parSchema.addField(
'notFitBands', type=str, doc=
'Bands that were not fit',
 
 1289                            size=len(notFitBandString))
 
 1290         parSchema.addField(
'lnTauUnit', type=np.float64, doc=
'Step units for ln(AOD)')
 
 1291         parSchema.addField(
'lnTauSlopeUnit', type=np.float64,
 
 1292                            doc=
'Step units for ln(AOD) slope')
 
 1293         parSchema.addField(
'alphaUnit', type=np.float64, doc=
'Step units for alpha')
 
 1294         parSchema.addField(
'lnPwvUnit', type=np.float64, doc=
'Step units for ln(pwv)')
 
 1295         parSchema.addField(
'lnPwvSlopeUnit', type=np.float64,
 
 1296                            doc=
'Step units for ln(pwv) slope')
 
 1297         parSchema.addField(
'lnPwvQuadraticUnit', type=np.float64,
 
 1298                            doc=
'Step units for ln(pwv) quadratic term')
 
 1299         parSchema.addField(
'lnPwvGlobalUnit', type=np.float64,
 
 1300                            doc=
'Step units for global ln(pwv) parameters')
 
 1301         parSchema.addField(
'o3Unit', type=np.float64, doc=
'Step units for O3')
 
 1302         parSchema.addField(
'qeSysUnit', type=np.float64, doc=
'Step units for mirror gray')
 
 1303         parSchema.addField(
'filterOffsetUnit', type=np.float64, doc=
'Step units for filter offset')
 
 1304         parSchema.addField(
'hasExternalPwv', type=np.int32, doc=
'Parameters fit using external pwv')
 
 1305         parSchema.addField(
'hasExternalTau', type=np.int32, doc=
'Parameters fit using external tau')
 
 1308         parSchema.addField(
'parAlpha', type=
'ArrayD', doc=
'Alpha parameter vector',
 
 1309                            size=pars[
'PARALPHA'].size)
 
 1310         parSchema.addField(
'parO3', type=
'ArrayD', doc=
'O3 parameter vector',
 
 1311                            size=pars[
'PARO3'].size)
 
 1312         parSchema.addField(
'parLnTauIntercept', type=
'ArrayD',
 
 1313                            doc=
'ln(Tau) intercept parameter vector',
 
 1314                            size=pars[
'PARLNTAUINTERCEPT'].size)
 
 1315         parSchema.addField(
'parLnTauSlope', type=
'ArrayD',
 
 1316                            doc=
'ln(Tau) slope parameter vector',
 
 1317                            size=pars[
'PARLNTAUSLOPE'].size)
 
 1318         parSchema.addField(
'parLnPwvIntercept', type=
'ArrayD', doc=
'ln(pwv) intercept parameter vector',
 
 1319                            size=pars[
'PARLNPWVINTERCEPT'].size)
 
 1320         parSchema.addField(
'parLnPwvSlope', type=
'ArrayD', doc=
'ln(pwv) slope parameter vector',
 
 1321                            size=pars[
'PARLNPWVSLOPE'].size)
 
 1322         parSchema.addField(
'parLnPwvQuadratic', type=
'ArrayD', doc=
'ln(pwv) quadratic parameter vector',
 
 1323                            size=pars[
'PARLNPWVQUADRATIC'].size)
 
 1324         parSchema.addField(
'parQeSysIntercept', type=
'ArrayD', doc=
'Mirror gray intercept parameter vector',
 
 1325                            size=pars[
'PARQESYSINTERCEPT'].size)
 
 1326         parSchema.addField(
'compQeSysSlope', type=
'ArrayD', doc=
'Mirror gray slope parameter vector',
 
 1327                            size=pars[0][
'COMPQESYSSLOPE'].size)
 
 1328         parSchema.addField(
'parFilterOffset', type=
'ArrayD', doc=
'Filter offset parameter vector',
 
 1329                            size=pars[
'PARFILTEROFFSET'].size)
 
 1330         parSchema.addField(
'parFilterOffsetFitFlag', type=
'ArrayI', doc=
'Filter offset parameter fit flag',
 
 1331                            size=pars[
'PARFILTEROFFSETFITFLAG'].size)
 
 1332         parSchema.addField(
'parRetrievedLnPwvScale', type=np.float64,
 
 1333                            doc=
'Global scale for retrieved ln(pwv)')
 
 1334         parSchema.addField(
'parRetrievedLnPwvOffset', type=np.float64,
 
 1335                            doc=
'Global offset for retrieved ln(pwv)')
 
 1336         parSchema.addField(
'parRetrievedLnPwvNightlyOffset', type=
'ArrayD',
 
 1337                            doc=
'Nightly offset for retrieved ln(pwv)',
 
 1338                            size=pars[
'PARRETRIEVEDLNPWVNIGHTLYOFFSET'].size)
 
 1339         parSchema.addField(
'compAbsThroughput', type=
'ArrayD',
 
 1340                            doc=
'Absolute throughput (relative to transmission curves)',
 
 1341                            size=pars[
'COMPABSTHROUGHPUT'].size)
 
 1342         parSchema.addField(
'compRefOffset', type=
'ArrayD',
 
 1343                            doc=
'Offset between reference stars and calibrated stars',
 
 1344                            size=pars[
'COMPREFOFFSET'].size)
 
 1345         parSchema.addField(
'compRefSigma', type=
'ArrayD',
 
 1346                            doc=
'Width of reference star/calibrated star distribution',
 
 1347                            size=pars[
'COMPREFSIGMA'].size)
 
 1348         parSchema.addField(
'compMirrorChromaticity', type=
'ArrayD',
 
 1349                            doc=
'Computed mirror chromaticity terms',
 
 1350                            size=pars[
'COMPMIRRORCHROMATICITY'].size)
 
 1351         parSchema.addField(
'mirrorChromaticityPivot', type=
'ArrayD',
 
 1352                            doc=
'Mirror chromaticity pivot mjd',
 
 1353                            size=pars[
'MIRRORCHROMATICITYPIVOT'].size)
 
 1354         parSchema.addField(
'compAperCorrPivot', type=
'ArrayD', doc=
'Aperture correction pivot',
 
 1355                            size=pars[
'COMPAPERCORRPIVOT'].size)
 
 1356         parSchema.addField(
'compAperCorrSlope', type=
'ArrayD', doc=
'Aperture correction slope',
 
 1357                            size=pars[
'COMPAPERCORRSLOPE'].size)
 
 1358         parSchema.addField(
'compAperCorrSlopeErr', type=
'ArrayD', doc=
'Aperture correction slope error',
 
 1359                            size=pars[
'COMPAPERCORRSLOPEERR'].size)
 
 1360         parSchema.addField(
'compAperCorrRange', type=
'ArrayD', doc=
'Aperture correction range',
 
 1361                            size=pars[
'COMPAPERCORRRANGE'].size)
 
 1362         parSchema.addField(
'compModelErrExptimePivot', type=
'ArrayD', doc=
'Model error exptime pivot',
 
 1363                            size=pars[
'COMPMODELERREXPTIMEPIVOT'].size)
 
 1364         parSchema.addField(
'compModelErrFwhmPivot', type=
'ArrayD', doc=
'Model error fwhm pivot',
 
 1365                            size=pars[
'COMPMODELERRFWHMPIVOT'].size)
 
 1366         parSchema.addField(
'compModelErrSkyPivot', type=
'ArrayD', doc=
'Model error sky pivot',
 
 1367                            size=pars[
'COMPMODELERRSKYPIVOT'].size)
 
 1368         parSchema.addField(
'compModelErrPars', type=
'ArrayD', doc=
'Model error parameters',
 
 1369                            size=pars[
'COMPMODELERRPARS'].size)
 
 1370         parSchema.addField(
'compExpGray', type=
'ArrayD', doc=
'Computed exposure gray',
 
 1371                            size=pars[
'COMPEXPGRAY'].size)
 
 1372         parSchema.addField(
'compVarGray', type=
'ArrayD', doc=
'Computed exposure variance',
 
 1373                            size=pars[
'COMPVARGRAY'].size)
 
 1374         parSchema.addField(
'compNGoodStarPerExp', type=
'ArrayI',
 
 1375                            doc=
'Computed number of good stars per exposure',
 
 1376                            size=pars[
'COMPNGOODSTARPEREXP'].size)
 
 1377         parSchema.addField(
'compSigFgcm', type=
'ArrayD', doc=
'Computed sigma_fgcm (intrinsic repeatability)',
 
 1378                            size=pars[
'COMPSIGFGCM'].size)
 
 1379         parSchema.addField(
'compSigmaCal', type=
'ArrayD', doc=
'Computed sigma_cal (systematic error floor)',
 
 1380                            size=pars[
'COMPSIGMACAL'].size)
 
 1381         parSchema.addField(
'compRetrievedLnPwv', type=
'ArrayD', doc=
'Retrieved ln(pwv) (smoothed)',
 
 1382                            size=pars[
'COMPRETRIEVEDLNPWV'].size)
 
 1383         parSchema.addField(
'compRetrievedLnPwvRaw', type=
'ArrayD', doc=
'Retrieved ln(pwv) (raw)',
 
 1384                            size=pars[
'COMPRETRIEVEDLNPWVRAW'].size)
 
 1385         parSchema.addField(
'compRetrievedLnPwvFlag', type=
'ArrayI', doc=
'Retrieved ln(pwv) Flag',
 
 1386                            size=pars[
'COMPRETRIEVEDLNPWVFLAG'].size)
 
 1387         parSchema.addField(
'compRetrievedTauNight', type=
'ArrayD', doc=
'Retrieved tau (per night)',
 
 1388                            size=pars[
'COMPRETRIEVEDTAUNIGHT'].size)
 
 1390         parSchema.addField(
'superstarSize', type=
'ArrayI', doc=
'Superstar matrix size',
 
 1392         parSchema.addField(
'superstar', type=
'ArrayD', doc=
'Superstar matrix (flattened)',
 
 1393                            size=parSuperStarFlat.size)
 
 1397     def _makeParCatalog(self, parSchema, parInfo, pars, parSuperStarFlat,
 
 1398                         lutFilterNameString, fitBandString, notFitBandString):
 
 1400         Make the FGCM parameter catalog for persistence 
 1404         parSchema: `lsst.afw.table.Schema` 
 1405            Parameter catalog schema 
 1406         pars: `numpy.ndarray` 
 1407            FGCM parameters to put into parCat 
 1408         parSuperStarFlat: `numpy.array` 
 1409            FGCM superstar flat array to put into parCat 
 1410         lutFilterNameString: `str` 
 1411            Combined string of all the lutFilterNames 
 1412         fitBandString: `str` 
 1413            Combined string of all the fitBands 
 1414         notFitBandString: `str` 
 1415            Combined string of all the bands not used in the fit 
 1419         parCat: `afwTable.BasicCatalog` 
 1420            Atmosphere and instrumental model parameter catalog for persistence 
 1428         rec = parCat.addNew()
 
 1431         rec[
'nCcd'] = parInfo[
'NCCD']
 
 1432         rec[
'lutFilterNames'] = lutFilterNameString
 
 1433         rec[
'fitBands'] = fitBandString
 
 1434         rec[
'notFitBands'] = notFitBandString
 
 1436         rec[
'hasExternalPwv'] = 0
 
 1437         rec[
'hasExternalTau'] = 0
 
 1441         scalarNames = [
'parRetrievedLnPwvScale', 
'parRetrievedLnPwvOffset']
 
 1443         arrNames = [
'parAlpha', 
'parO3', 
'parLnTauIntercept', 
'parLnTauSlope',
 
 1444                     'parLnPwvIntercept', 
'parLnPwvSlope', 
'parLnPwvQuadratic',
 
 1445                     'parQeSysIntercept', 
'compQeSysSlope',
 
 1446                     'parRetrievedLnPwvNightlyOffset', 
'compAperCorrPivot',
 
 1447                     'parFilterOffset', 
'parFilterOffsetFitFlag',
 
 1448                     'compAbsThroughput', 
'compRefOffset', 
'compRefSigma',
 
 1449                     'compMirrorChromaticity', 
'mirrorChromaticityPivot',
 
 1450                     'compAperCorrSlope', 
'compAperCorrSlopeErr', 
'compAperCorrRange',
 
 1451                     'compModelErrExptimePivot', 
'compModelErrFwhmPivot',
 
 1452                     'compModelErrSkyPivot', 
'compModelErrPars',
 
 1453                     'compExpGray', 
'compVarGray', 
'compNGoodStarPerExp', 
'compSigFgcm',
 
 1455                     'compRetrievedLnPwv', 
'compRetrievedLnPwvRaw', 
'compRetrievedLnPwvFlag',
 
 1456                     'compRetrievedTauNight']
 
 1458         for scalarName 
in scalarNames:
 
 1459             rec[scalarName] = pars[scalarName.upper()]
 
 1461         for arrName 
in arrNames:
 
 1462             rec[arrName][:] = np.atleast_1d(pars[0][arrName.upper()])[:]
 
 1465         rec[
'superstarSize'][:] = parSuperStarFlat.shape
 
 1466         rec[
'superstar'][:] = parSuperStarFlat.flatten()
 
 1470     def _makeFlagStarSchema(self):
 
 1472         Make the flagged-stars schema 
 1476         flagStarSchema: `lsst.afw.table.Schema` 
 1481         flagStarSchema.addField(
'objId', type=np.int32, doc=
'FGCM object id')
 
 1482         flagStarSchema.addField(
'objFlag', type=np.int32, doc=
'FGCM object flag')
 
 1484         return flagStarSchema
 
 1486     def _makeFlagStarCat(self, flagStarSchema, flagStarStruct):
 
 1488         Make the flagged star catalog for persistence 
 1492         flagStarSchema: `lsst.afw.table.Schema` 
 1494         flagStarStruct: `numpy.ndarray` 
 1495            Flagged star structure from fgcm 
 1499         flagStarCat: `lsst.afw.table.BaseCatalog` 
 1500            Flagged star catalog for persistence 
 1504         flagStarCat.reserve(flagStarStruct.size)
 
 1505         for i 
in range(flagStarStruct.size):
 
 1506             flagStarCat.addNew()
 
 1508         flagStarCat[
'objId'][:] = flagStarStruct[
'OBJID']
 
 1509         flagStarCat[
'objFlag'][:] = flagStarStruct[
'OBJFLAG']