23"""Perform a single fit cycle of FGCM.
25This task runs a single "fit cycle" of fgcm. Prior to running this task
26one must run both fgcmMakeLut (to construct the atmosphere and instrumental
27look-up-table) and fgcmBuildStars (to extract visits and star observations
30The 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
32be inspected to set parameters for outlier rejection on the following
33cycle. Please see the fgcmcal Cookbook for details.
45from .utilities
import makeConfigDict, translateFgcmLut, translateVisitCatalog
46from .utilities
import extractReferenceMags
47from .utilities
import makeZptSchema, makeZptCat
48from .utilities
import makeAtmSchema, makeAtmCat, makeStdSchema, makeStdCat
49from .sedterms
import SedboundarytermDict, SedtermDict
50from .focalPlaneProjector
import FocalPlaneProjector
54__all__ = [
'FgcmFitCycleConfig',
'FgcmFitCycleTask']
56MULTIPLE_CYCLES_MAX = 10
60 dimensions=(
"instrument",),
61 defaultTemplates={
"previousCycleNumber":
"-1",
63 camera = connectionTypes.PrerequisiteInput(
64 doc=
"Camera instrument",
66 storageClass=
"Camera",
67 dimensions=(
"instrument",),
71 fgcmLookUpTable = connectionTypes.PrerequisiteInput(
72 doc=(
"Atmosphere + instrument look-up-table for FGCM throughput and "
73 "chromatic corrections."),
74 name=
"fgcmLookUpTable",
75 storageClass=
"Catalog",
76 dimensions=(
"instrument",),
80 fgcmVisitCatalog = connectionTypes.Input(
81 doc=
"Catalog of visit information for fgcm",
82 name=
"fgcmVisitCatalog",
83 storageClass=
"Catalog",
84 dimensions=(
"instrument",),
88 fgcmStarObservationsParquet = connectionTypes.Input(
89 doc=(
"Catalog of star observations for fgcm, in parquet format. "
90 "Used if useParquetCatalogFormat is True."),
91 name=
"fgcm_star_observations",
92 storageClass=
"ArrowAstropy",
93 dimensions=(
"instrument",),
97 fgcmStarIdsParquet = connectionTypes.Input(
98 doc=(
"Catalog of fgcm calibration star IDs, in parquet format. "
99 "Used if useParquetCatalogFormat is True."),
100 name=
"fgcm_star_ids",
101 storageClass=
"ArrowAstropy",
102 dimensions=(
"instrument",),
106 fgcmReferenceStarsParquet = connectionTypes.Input(
107 doc=(
"Catalog of fgcm-matched reference stars, in parquet format. "
108 "Used if useParquetCatalogFormat is True."),
109 name=
"fgcm_reference_stars",
110 storageClass=
"ArrowAstropy",
111 dimensions=(
"instrument",),
115 fgcmStarObservations = connectionTypes.Input(
116 doc=(
"Catalog of star observations for fgcm; old format. "
117 "Used if useParquetCatalogFormat is False."),
118 name=
"fgcmStarObservations",
119 storageClass=
"Catalog",
120 dimensions=(
"instrument",),
124 fgcmStarIds = connectionTypes.Input(
125 doc=(
"Catalog of fgcm calibration star IDs. "
126 "Used if useParquetCatalogFormat is False."),
128 storageClass=
"Catalog",
129 dimensions=(
"instrument",),
133 fgcmStarIndices = connectionTypes.Input(
134 doc=(
"Catalog of fgcm calibration star indices; old format."
135 "Used if useParquetCatalogFormat is False."),
136 name=
"fgcmStarIndices",
137 storageClass=
"Catalog",
138 dimensions=(
"instrument",),
142 fgcmReferenceStars = connectionTypes.Input(
143 doc=(
"Catalog of fgcm-matched reference stars; old format."
144 "Used if useParquetCatalogFormat is False."),
145 name=
"fgcmReferenceStars",
146 storageClass=
"Catalog",
147 dimensions=(
"instrument",),
151 def __init__(self, *, config=None):
152 super().__init__(config=config)
157 if str(int(config.connections.cycleNumber)) != config.connections.cycleNumber:
158 raise ValueError(
"cycleNumber must be of integer format")
159 if str(int(config.connections.previousCycleNumber)) != config.connections.previousCycleNumber:
160 raise ValueError(
"previousCycleNumber must be of integer format")
164 if int(config.connections.previousCycleNumber) != (int(config.connections.cycleNumber) - 1):
165 raise ValueError(
"previousCycleNumber must be 1 less than cycleNumber")
167 instDims = (
"instrument",)
168 bandDims = (
"instrument",
"band")
169 filterDims = (
"instrument",
"physical_filter")
171 inputAndOutputConnections = [
172 (
"FitParameters",
"Catalog",
"Catalog of fgcm fit parameters.", instDims),
173 (
"FlaggedStars",
"Catalog",
"Catalog of flagged stars for fgcm calibration.", instDims),
175 multicycleOutputConnections = [
176 (
"OutputConfig",
"Config",
"Configuration for next fgcm fit cycle.", instDims),
178 optionalZpOutputConnections = [
179 (
"Zeropoints",
"Catalog",
"Catalog of fgcm zeropoint data.", instDims),
180 (
"AtmosphereParameters",
"Catalog",
"Catalog of atmospheric fit parameters.", instDims),
182 optionalStarOutputConnections = [
183 (
"StandardStars",
"SimpleCatalog",
"Catalog of standard star magnitudes.", instDims),
186 epochs = [f
"epoch{i}" for i
in range(len(config.epochMjds))]
190 (
"Zeropoints_Plot",
"Plot",
"Plot of fgcm zeropoints.", instDims),
193 "Plot of gray term per exposure per time for deep fields.",
195 (
"NightlyAlpha_Plot",
"Plot",
"Plot of nightly AOD alpha term.", instDims),
196 (
"NightlyTau_Plot",
"Plot",
"Plot of nightly aerosol optical depth (tau).", instDims),
197 (
"NightlyPwv_Plot",
"Plot",
"Plot of nightly water vapor.", instDims),
198 (
"NightlyO3_Plot",
"Plot",
"Plot of nightly ozone.", instDims),
199 (
"FilterOffsets_Plot",
"Plot",
"Plot of in-band filter offsets.", instDims),
200 (
"AbsThroughputs_Plot",
"Plot",
"Plot of absolute throughput fractions.", instDims),
201 (
"QESysWashesInitial_Plot",
"Plot",
"Plot of initial system QE with mirror washes.", instDims),
202 (
"QESysWashesFinal_Plot",
"Plot",
"Plot of final system QE with mirror washes.", instDims),
203 (
"RpwvVsRpwvInput_Plot",
205 "Plot of change in per-visit ``retrieved`` PWV from previous fit cycle.",
207 (
"RpwvVsRpwvSmooth_Plot",
209 "Plot of per-visit ``retrieved`` PWV vs. smoothed PWV.",
211 (
"ModelPwvVsRpwv_Plot",
213 "Plot of model PWV vs. per-visit ``retrieved`` PWV.",
217 "Plot of chisq as a function of iteration.",
221 plotConnections.extend(
223 (
"Apercorr_Plot",
"Plot",
"Plot of fgcm aperture corrections.", bandDims),
224 (
"EpsilonGlobal_Plot",
226 "Plot of global background over/undersubtraction.",
230 "Map of spatially varying background over/undersubtraction.",
232 (
"ExpgrayInitial_Plot",
234 "Histogram of initial gray term per exposure.",
236 (
"CompareRedblueExpgray_Plot",
238 "Plot of red/blue split gray term per exposure",
240 (
"Expgray_Plot",
"Plot",
"Histogram of gray term per exposure.", bandDims),
241 (
"ExpgrayAirmass_Plot",
243 "Plot of exposure gray term as a function of airmass.",
245 (
"ExpgrayCompareMjdRedblue_Plot",
247 "Plot of red/blue split gray term per exposure as a function of time.",
251 "Plot of grey term per exposure as a function of time of night.",
253 (
"ExpgrayCompareBands_Plot",
255 "Plot of gray term per exposure between bands nearby in time.",
257 (
"ExpgrayReference_Plot",
259 "Histogram of gray term per exposure compared to reference mags.",
261 (
"QESysRefstarsStdInitial_Plot",
263 "Plot of reference mag - calibrated (standard) mag vs. time (before fit).",
265 (
"QESysRefstarsStdFinal_Plot",
267 "Plot of reference mag - calibrated (standard) mag vs. time (after fit).",
269 (
"QESysRefstarsObsInitial_Plot",
271 "Plot of reference mag - observed (instrumental) mag vs. time (before fit).",
273 (
"QESysRefstarsObsFinal_Plot",
275 "Plot of reference mag - observed (instrumental) mag vs. time (after fit).",
277 (
"ModelMagerrInitial_Plot",
279 "Plots for magnitude error model, initial estimate.",
281 (
"ModelMagerrPostfit_Plot",
283 "Plots for magnitude error model, after fitting.",
285 (
"SigmaFgcmAllStars_Plot",
287 "Histograms for intrinsic scatter for all bright stars.",
289 (
"SigmaFgcmReservedStars_Plot",
291 "Histograms for intrinsic scatter for reserved bright stars.",
293 (
"SigmaFgcmReservedStarsCrunched_Plot",
295 "Histograms for intrinsic scatter for reserved bright stars (after gray correction).",
297 (
"SigmaFgcmPullsAllStars_Plot",
299 "Histograms for pulls for all bright stars.",
301 (
"SigmaFgcmPullsReservedStars_Plot",
303 "Histograms for pulls for reserved bright stars.",
305 (
"SigmaFgcmPullsReservedStarsCrunched_Plot",
307 "Histograms for pulls for reserved bright stars (after gray correction).",
311 "Plot showing scatter as a function of systematic error floor.",
315 "Histograms of scatter with respect to reference stars.",
317 (
"RefResidVsColorAll_Plot",
319 "Plot of reference star residuals vs. color (all stars).",
321 (
"RefResidVsColorCut_Plot",
323 "Plot of reference star residuals vs. color (reference star color cuts).",
328 plotConnections.extend(
330 (
"I1R1_Plot",
"Plot",
"Plot of fgcm R1 vs. I1.", filterDims),
331 (
"I1_Plot",
"Plot",
"Focal plane map of fgcm I1.", filterDims),
332 (
"R1_Plot",
"Plot",
"Focal plane map of fgcm R1.", filterDims),
333 (
"R1mI1_Plot",
"Plot",
"Focal plane map of fgcm R1 - I1.", filterDims),
334 (
"R1mI1_vs_mjd_Plot",
"Plot",
"R1 - I1 residuals vs. mjd.", filterDims),
335 (
"CompareRedblueMirrorchrom_Plot",
337 "Comparison of mirror chromaticity residuals for red/blue stars.",
339 (
"CcdChromaticity_Plot",
341 "Focal plane map of fgcm ccd chromaticity.",
343 (
"EpsilonDetector_Plot",
345 "Focal plane map of background over/undersubtraction.",
347 (
"EpsilonDetectorMatchscale_Plot",
349 "Focal plane map of background over/undersubtraction.",
354 plotConnections.extend(
357 f
"Superstar_{epoch}_Plot",
359 "Plot of illumination Correction.",
365 if config.doMultipleCycles:
369 for cycle
in range(config.multipleCyclesFinalCycleNumber):
370 outputConnections = copy.copy(inputAndOutputConnections)
371 outputConnections.extend(multicycleOutputConnections)
372 if config.outputZeropointsBeforeFinalCycle:
373 outputConnections.extend(optionalZpOutputConnections)
374 if config.outputStandardsBeforeFinalCycle:
375 outputConnections.extend(optionalStarOutputConnections)
383 if cycle == (config.multipleCyclesFinalCycleNumber - 1) \
384 or config.doPlotsBeforeFinalCycles:
385 outputConnections.extend(plotConnections)
387 for (name, storageClass, doc, dims)
in outputConnections:
388 connectionName = f
"fgcm_Cycle{cycle}_{name}"
389 storageName = connectionName
390 outConnection = connectionTypes.Output(
392 storageClass=storageClass,
395 multiple=(len(dims) > 1),
397 setattr(self, connectionName, outConnection)
400 outputConnections = copy.copy(inputAndOutputConnections)
401 outputConnections.extend(multicycleOutputConnections)
402 outputConnections.extend(optionalZpOutputConnections)
403 outputConnections.extend(optionalStarOutputConnections)
405 outputConnections.extend(plotConnections)
406 for (name, storageClass, doc, dims)
in outputConnections:
407 connectionName = f
"fgcm_Cycle{config.multipleCyclesFinalCycleNumber}_{name}"
408 storageName = connectionName
409 outConnection = connectionTypes.Output(
411 storageClass=storageClass,
414 multiple=(len(dims) > 1),
416 setattr(self, connectionName, outConnection)
419 if config.cycleNumber > 0:
420 inputConnections = copy.copy(inputAndOutputConnections)
422 inputConnections = []
423 outputConnections = copy.copy(inputAndOutputConnections)
428 if config.isFinalCycle
or config.outputZeropointsBeforeFinalCycle:
429 outputConnections.extend(optionalZpOutputConnections)
430 if config.isFinalCycle
or config.outputStandardsBeforeFinalCycle:
431 outputConnections.extend(optionalStarOutputConnections)
434 outputConnections.extend(plotConnections)
436 for (name, storageClass, doc, dims)
in inputConnections:
437 connectionName = f
"fgcm{name}Input"
438 storageName = f
"fgcm_Cycle{config.cycleNumber - 1}_{name}"
439 inConnection = connectionTypes.PrerequisiteInput(
441 storageClass=storageClass,
445 setattr(self, connectionName, inConnection)
447 for (name, storageClass, doc, dims)
in outputConnections:
448 connectionName = f
"fgcm{name}"
449 storageName = f
"fgcm_Cycle{config.cycleNumber}_{name}"
451 if storageClass ==
"Plot":
452 connectionName = storageName
453 outConnection = connectionTypes.Output(
455 storageClass=storageClass,
458 multiple=(len(dims) > 1),
460 setattr(self, connectionName, outConnection)
462 if not config.doReferenceCalibration:
463 self.inputs.remove(
"fgcmReferenceStars")
464 self.inputs.remove(
"fgcmReferenceStarsParquet")
466 if config.useParquetCatalogFormat:
467 self.inputs.remove(
"fgcmStarObservations")
468 self.inputs.remove(
"fgcmStarIds")
469 self.inputs.remove(
"fgcmStarIndices")
470 if config.doReferenceCalibration:
471 self.inputs.remove(
"fgcmReferenceStars")
473 self.inputs.remove(
"fgcmStarObservationsParquet")
474 self.inputs.remove(
"fgcmStarIdsParquet")
475 if config.doReferenceCalibration:
476 self.inputs.remove(
"fgcmReferenceStarsParquet")
479class FgcmFitCycleConfig(pipeBase.PipelineTaskConfig,
480 pipelineConnections=FgcmFitCycleConnections):
481 """Config for FgcmFitCycle"""
483 doMultipleCycles = pexConfig.Field(
484 doc=
"Run multiple fit cycles in one task",
488 useParquetCatalogFormat = pexConfig.Field(
489 doc=
"Use parquet catalog format?",
493 multipleCyclesFinalCycleNumber = pexConfig.RangeField(
494 doc=(
"Final cycle number in multiple cycle mode. The initial cycle "
495 "is 0, with limited parameters fit. The next cycle is 1 with "
496 "full parameter fit. The final cycle is a clean-up with no "
497 "parameters fit. There will be a total of "
498 "(multipleCycleFinalCycleNumber + 1) cycles run, and the final "
499 "cycle number cannot be less than 2."),
503 max=MULTIPLE_CYCLES_MAX,
506 bands = pexConfig.ListField(
507 doc=
"Bands to run calibration",
511 fitBands = pexConfig.ListField(
512 doc=(
"Bands to use in atmospheric fit. The bands not listed here will have "
513 "the atmosphere constrained from the 'fitBands' on the same night. "
514 "Must be a subset of `config.bands`"),
518 requiredBands = pexConfig.ListField(
519 doc=(
"Bands that are required for a star to be considered a calibration star. "
520 "Must be a subset of `config.bands`"),
524 physicalFilterMap = pexConfig.DictField(
525 doc=
"Mapping from 'physicalFilter' to band.",
530 doReferenceCalibration = pexConfig.Field(
531 doc=
"Use reference catalog as additional constraint on calibration",
535 refStarSnMin = pexConfig.Field(
536 doc=
"Reference star signal-to-noise minimum to use in calibration. Set to <=0 for no cut.",
540 refStarOutlierNSig = pexConfig.Field(
541 doc=(
"Number of sigma compared to average mag for reference star to be considered an outlier. "
542 "Computed per-band, and if it is an outlier in any band it is rejected from fits."),
546 applyRefStarColorCuts = pexConfig.Field(
547 doc=(
"Apply color cuts defined in ``starColorCuts`` to reference stars? "
548 "These cuts are in addition to any cuts defined in ``refStarColorCuts``"),
552 refStarMaxFracUse = pexConfig.Field(
553 doc=(
"Maximum fraction of reference stars to use in the fit. Remainder will "
554 "be used only for validation."),
558 useExposureReferenceOffset = pexConfig.Field(
559 doc=(
"Use per-exposure (visit) offsets between calibrated stars and reference stars "
560 "for final zeropoints? This may help uniformity for disjoint surveys."),
564 nCore = pexConfig.Field(
565 doc=
"Number of cores to use",
568 deprecated=
"Number of cores is deprecated as a config, and will be removed after v27. "
569 "Please use ``pipetask run --cores-per-quantum`` instead.",
571 nStarPerRun = pexConfig.Field(
572 doc=
"Number of stars to run in each chunk",
576 nExpPerRun = pexConfig.Field(
577 doc=
"Number of exposures to run in each chunk",
581 reserveFraction = pexConfig.Field(
582 doc=
"Fraction of stars to reserve for testing",
586 freezeStdAtmosphere = pexConfig.Field(
587 doc=
"Freeze atmosphere parameters to standard (for testing)",
591 precomputeSuperStarInitialCycle = pexConfig.Field(
592 doc=
"Precompute superstar flat for initial cycle",
596 superStarSubCcdDict = pexConfig.DictField(
597 doc=(
"Per-band specification on whether to compute superstar flat on sub-ccd scale. "
598 "Must have one entry per band."),
603 superStarSubCcdChebyshevOrder = pexConfig.Field(
604 doc=(
"Order of the 2D chebyshev polynomials for sub-ccd superstar fit. "
605 "Global default is first-order polynomials, and should be overridden "
606 "on a camera-by-camera basis depending on the ISR."),
610 superStarSubCcdTriangular = pexConfig.Field(
611 doc=(
"Should the sub-ccd superstar chebyshev matrix be triangular to "
612 "suppress high-order cross terms?"),
616 superStarSigmaClip = pexConfig.Field(
617 doc=
"Number of sigma to clip outliers when selecting for superstar flats",
621 superStarPlotCcdResiduals = pexConfig.Field(
622 doc=
"If plotting is enabled, should per-detector residuals be plotted? "
623 "This may produce a lot of output, and should be used only for "
624 "debugging purposes.",
628 superStarForceZeroMean = pexConfig.Field(
629 doc=
"When computing the super-star flat, force the focal-plane mean to "
630 "zero (per band)? This should only be used when computing stand-alone "
631 "illumination corrections.",
635 focalPlaneSigmaClip = pexConfig.Field(
636 doc=
"Number of sigma to clip outliers per focal-plane.",
640 ccdGraySubCcdDict = pexConfig.DictField(
641 doc=(
"Per-band specification on whether to compute achromatic per-ccd residual "
642 "('ccd gray') on a sub-ccd scale."),
647 ccdGraySubCcdChebyshevOrder = pexConfig.Field(
648 doc=
"Order of the 2D chebyshev polynomials for sub-ccd gray fit.",
652 ccdGraySubCcdTriangular = pexConfig.Field(
653 doc=(
"Should the sub-ccd gray chebyshev matrix be triangular to "
654 "suppress high-order cross terms?"),
658 ccdGrayFocalPlaneDict = pexConfig.DictField(
659 doc=(
"Per-band specification on whether to compute focal-plane residual "
660 "('ccd gray') corrections."),
665 ccdGrayFocalPlaneFitMinCcd = pexConfig.Field(
666 doc=(
"Minimum number of 'good' CCDs required to perform focal-plane "
667 "gray corrections. If there are fewer good CCDs then the gray "
668 "correction is computed per-ccd."),
672 ccdGrayFocalPlaneChebyshevOrder = pexConfig.Field(
673 doc=
"Order of the 2D chebyshev polynomials for focal plane fit.",
677 cycleNumber = pexConfig.Field(
678 doc=(
"FGCM fit cycle number. This is automatically incremented after each run "
679 "and stage of outlier rejection. See cookbook for details."),
683 isFinalCycle = pexConfig.Field(
684 doc=(
"Is this the final cycle of the fitting? Will automatically compute final "
685 "selection of stars and photometric exposures, and will output zeropoints "
686 "and standard stars for use in fgcmOutputProducts"),
690 maxIterBeforeFinalCycle = pexConfig.Field(
691 doc=(
"Maximum fit iterations, prior to final cycle. The number of iterations "
692 "will always be 0 in the final cycle for cleanup and final selection."),
696 deltaMagBkgOffsetPercentile = pexConfig.Field(
697 doc=(
"Percentile brightest stars on a visit/ccd to use to compute net "
698 "offset from local background subtraction."),
702 deltaMagBkgPerCcd = pexConfig.Field(
703 doc=(
"Compute net offset from local background subtraction per-ccd? "
704 "Otherwise, use computation per visit."),
708 utBoundary = pexConfig.Field(
709 doc=
"Boundary (in UTC) from day-to-day",
713 washMjds = pexConfig.ListField(
714 doc=
"Mirror wash MJDs",
718 epochMjds = pexConfig.ListField(
719 doc=
"Epoch boundaries in MJD",
723 minObsPerBand = pexConfig.Field(
724 doc=
"Minimum good observations per band",
730 latitude = pexConfig.Field(
731 doc=
"Observatory latitude",
735 mirrorArea = pexConfig.Field(
736 doc=
"Mirror area (square meters) of telescope. If not set, will "
737 "try to estimate from camera.telescopeDiameter.",
742 cameraGain = pexConfig.Field(
743 doc=
"Average camera gain. If not set, will use the median of the "
744 "camera model/detector/amplifier gains.",
749 defaultCameraOrientation = pexConfig.Field(
750 doc=
"Default camera orientation for QA plots.",
754 brightObsGrayMax = pexConfig.Field(
755 doc=
"Maximum gray extinction to be considered bright observation",
759 minStarPerCcd = pexConfig.Field(
760 doc=(
"Minimum number of good stars per CCD to be used in calibration fit. "
761 "CCDs with fewer stars will have their calibration estimated from other "
762 "CCDs in the same visit, with zeropoint error increased accordingly."),
766 minCcdPerExp = pexConfig.Field(
767 doc=(
"Minimum number of good CCDs per exposure/visit to be used in calibration fit. "
768 "Visits with fewer good CCDs will have CCD zeropoints estimated where possible."),
772 maxCcdGrayErr = pexConfig.Field(
773 doc=
"Maximum error on CCD gray offset to be considered photometric",
777 minStarPerExp = pexConfig.Field(
778 doc=(
"Minimum number of good stars per exposure/visit to be used in calibration fit. "
779 "Visits with fewer good stars will have CCD zeropoints estimated where possible."),
783 minExpPerNight = pexConfig.Field(
784 doc=
"Minimum number of good exposures/visits to consider a partly photometric night",
788 expGrayInitialCut = pexConfig.Field(
789 doc=(
"Maximum exposure/visit gray value for initial selection of possible photometric "
794 expFwhmCutDict = pexConfig.DictField(
795 doc=(
"Per-band specification on maximum exposure FWHM (arcseconds) that will "
796 "be considered for the model fit. Exposures with median FWHM larger "
797 "than this threshold will get zeropoints based on matching to good "
803 expGrayPhotometricCutDict = pexConfig.DictField(
804 doc=(
"Per-band specification on maximum (negative) achromatic exposure residual "
805 "('gray term') for a visit to be considered photometric. Must have one "
806 "entry per band. Broad-band filters should be -0.05."),
811 expGrayHighCutDict = pexConfig.DictField(
812 doc=(
"Per-band specification on maximum (positive) achromatic exposure residual "
813 "('gray term') for a visit to be considered photometric. Must have one "
814 "entry per band. Broad-band filters should be 0.2."),
819 expGrayRecoverCut = pexConfig.Field(
820 doc=(
"Maximum (negative) exposure gray to be able to recover bad ccds via interpolation. "
821 "Visits with more gray extinction will only get CCD zeropoints if there are "
822 "sufficient star observations (minStarPerCcd) on that CCD."),
826 expVarGrayPhotometricCutDict = pexConfig.DictField(
827 doc=(
"Per-band specification on maximum exposure variance to be considered possibly "
828 "photometric. Must have one entry per band. Broad-band filters should be "
834 expGrayErrRecoverCut = pexConfig.Field(
835 doc=(
"Maximum exposure gray error to be able to recover bad ccds via interpolation. "
836 "Visits with more gray variance will only get CCD zeropoints if there are "
837 "sufficient star observations (minStarPerCcd) on that CCD."),
841 aperCorrFitNBins = pexConfig.Field(
842 doc=(
"Number of aperture bins used in aperture correction fit. When set to 0"
843 "no fit will be performed, and the config.aperCorrInputSlopes will be "
844 "used if available."),
848 aperCorrInputSlopeDict = pexConfig.DictField(
849 doc=(
"Per-band specification of aperture correction input slope parameters. These "
850 "are used on the first fit iteration, and aperture correction parameters will "
851 "be updated from the data if config.aperCorrFitNBins > 0. It is recommended "
852 "to set this when there is insufficient data to fit the parameters (e.g. "
858 sedboundaryterms = pexConfig.ConfigField(
859 doc=
"Mapping from bands to SED boundary term names used is sedterms.",
860 dtype=SedboundarytermDict,
862 sedterms = pexConfig.ConfigField(
863 doc=
"Mapping from terms to bands for fgcm linear SED approximations.",
866 sigFgcmMaxErr = pexConfig.Field(
867 doc=
"Maximum mag error for fitting sigma_FGCM",
871 sigFgcmMaxEGrayDict = pexConfig.DictField(
872 doc=(
"Per-band specification for maximum (absolute) achromatic residual (gray value) "
873 "for observations in sigma_fgcm (raw repeatability). Broad-band filters "
879 ccdGrayMaxStarErr = pexConfig.Field(
880 doc=(
"Maximum error on a star observation to use in ccd gray (achromatic residual) "
885 approxThroughputDict = pexConfig.DictField(
886 doc=(
"Per-band specification of the approximate overall throughput at the start of "
887 "calibration observations. Must have one entry per band. Typically should "
893 sigmaCalRange = pexConfig.ListField(
894 doc=
"Allowed range for systematic error floor estimation",
896 default=(0.001, 0.003),
898 sigmaCalFitPercentile = pexConfig.ListField(
899 doc=
"Magnitude percentile range to fit systematic error floor",
901 default=(0.05, 0.15),
903 sigmaCalPlotPercentile = pexConfig.ListField(
904 doc=
"Magnitude percentile range to plot systematic error floor",
906 default=(0.05, 0.95),
908 sigma0Phot = pexConfig.Field(
909 doc=
"Systematic error floor for all zeropoints",
913 mapLongitudeRef = pexConfig.Field(
914 doc=
"Reference longitude for plotting maps",
918 mapNSide = pexConfig.Field(
919 doc=
"Healpix nside for plotting maps",
923 outfileBase = pexConfig.Field(
924 doc=
"Filename start for plot output files",
928 starColorCuts = pexConfig.ListField(
929 doc=(
"Encoded star-color cuts (using calibration star colors). "
930 "This is a list with each entry a string of the format "
931 "``band1,band2,low,high`` such that only stars of color "
932 "low < band1 - band2 < high will be used for calibration."),
934 default=(
"NO_DATA",),
936 refStarColorCuts = pexConfig.ListField(
937 doc=(
"Encoded star color cuts specifically to apply to reference stars. "
938 "This is a list with each entry a string of the format "
939 "``band1,band2,low,high`` such that only stars of color "
940 "low < band1 - band2 < high will be used as reference stars."),
942 default=(
"NO_DATA",),
944 colorSplitBands = pexConfig.ListField(
945 doc=
"Band names to use to split stars by color. Must have 2 entries.",
950 modelMagErrors = pexConfig.Field(
951 doc=
"Should FGCM model the magnitude errors from sky/fwhm? (False means trust inputs)",
955 useQuadraticPwv = pexConfig.Field(
956 doc=
"Model PWV with a quadratic term for variation through the night?",
960 instrumentParsPerBand = pexConfig.Field(
961 doc=(
"Model instrumental parameters per band? "
962 "Otherwise, instrumental parameters (QE changes with time) are "
963 "shared among all bands."),
967 instrumentSlopeMinDeltaT = pexConfig.Field(
968 doc=(
"Minimum time change (in days) between observations to use in constraining "
969 "instrument slope."),
973 fitMirrorChromaticity = pexConfig.Field(
974 doc=
"Fit (intraband) mirror chromatic term?",
978 fitCcdChromaticityDict = pexConfig.DictField(
979 doc=
"Specification on whether to compute first-order quantum efficiency (QE) "
980 "adjustments. Key is band, and value will be True or False. Any band "
981 "not explicitly specified will default to False.",
986 coatingMjds = pexConfig.ListField(
987 doc=
"Mirror coating dates in MJD",
991 outputStandardsBeforeFinalCycle = pexConfig.Field(
992 doc=
"Output standard stars prior to final cycle? Used in debugging.",
996 outputZeropointsBeforeFinalCycle = pexConfig.Field(
997 doc=
"Output standard stars prior to final cycle? Used in debugging.",
1001 useRepeatabilityForExpGrayCutsDict = pexConfig.DictField(
1002 doc=(
"Per-band specification on whether to use star repeatability (instead of exposures) "
1003 "for computing photometric cuts. Recommended for tract mode or bands with few visits."),
1008 autoPhotometricCutNSig = pexConfig.Field(
1009 doc=(
"Number of sigma for automatic computation of (low) photometric cut. "
1010 "Cut is based on exposure gray width (per band), unless "
1011 "useRepeatabilityForExpGrayCuts is set, in which case the star "
1012 "repeatability is used (also per band)."),
1016 autoHighCutNSig = pexConfig.Field(
1017 doc=(
"Number of sigma for automatic computation of (high) outlier cut. "
1018 "Cut is based on exposure gray width (per band), unless "
1019 "useRepeatabilityForExpGrayCuts is set, in which case the star "
1020 "repeatability is used (also per band)."),
1024 quietMode = pexConfig.Field(
1025 doc=
"Be less verbose with logging.",
1029 doPlots = pexConfig.Field(
1030 doc=
"Make fgcm QA plots.",
1034 doPlotsBeforeFinalCycles = pexConfig.Field(
1035 doc=
"Make fgcm QA plots before the final two fit cycles? This only applies in"
1036 "multi-cycle mode, and if doPlots is True. These are typically the most"
1037 "important QA plots to inspect.",
1041 randomSeed = pexConfig.Field(
1042 doc=
"Random seed for fgcm for consistency in tests.",
1047 deltaAperFitMinNgoodObs = pexConfig.Field(
1048 doc=
"Minimum number of good observations to use mean delta-aper values in fits.",
1052 deltaAperFitPerCcdNx = pexConfig.Field(
1053 doc=(
"Number of x bins per ccd when computing delta-aper background offsets. "
1054 "Only used when ``doComputeDeltaAperPerCcd`` is True."),
1058 deltaAperFitPerCcdNy = pexConfig.Field(
1059 doc=(
"Number of y bins per ccd when computing delta-aper background offsets. "
1060 "Only used when ``doComputeDeltaAperPerCcd`` is True."),
1064 deltaAperFitSpatialNside = pexConfig.Field(
1065 doc=
"Healpix nside to compute spatial delta-aper background offset maps.",
1069 deltaAperInnerRadiusArcsec = pexConfig.Field(
1070 doc=(
"Inner radius used to compute deltaMagAper (arcseconds). "
1071 "Must be positive and less than ``deltaAperOuterRadiusArcsec`` if "
1072 "any of ``doComputeDeltaAperPerVisit``, ``doComputeDeltaAperPerStar``, "
1073 "``doComputeDeltaAperMap``, ``doComputeDeltaAperPerCcd`` are set."),
1077 deltaAperOuterRadiusArcsec = pexConfig.Field(
1078 doc=(
"Outer radius used to compute deltaMagAper (arcseconds). "
1079 "Must be positive and greater than ``deltaAperInnerRadiusArcsec`` if "
1080 "any of ``doComputeDeltaAperPerVisit``, ``doComputeDeltaAperPerStar``, "
1081 "``doComputeDeltaAperMap``, ``doComputeDeltaAperPerCcd`` are set."),
1085 doComputeDeltaAperPerVisit = pexConfig.Field(
1086 doc=(
"Do the computation of delta-aper background offsets per visit? "
1087 "Note: this option can be very slow when there are many visits."),
1091 doComputeDeltaAperPerStar = pexConfig.Field(
1092 doc=
"Do the computation of delta-aper mean values per star?",
1096 doComputeDeltaAperMap = pexConfig.Field(
1097 doc=(
"Do the computation of delta-aper spatial maps? "
1098 "This is only used if ``doComputeDeltaAperPerStar`` is True,"),
1102 doComputeDeltaAperPerCcd = pexConfig.Field(
1103 doc=
"Do the computation of per-ccd delta-aper background offsets?",
1111 if self.connections.previousCycleNumber != str(self.cycleNumber - 1):
1112 msg =
"cycleNumber in template must be connections.previousCycleNumber + 1"
1113 raise RuntimeError(msg)
1114 if self.connections.cycleNumber != str(self.cycleNumber):
1115 msg =
"cycleNumber in template must be equal to connections.cycleNumber"
1116 raise RuntimeError(msg)
1118 for band
in self.fitBands:
1119 if band
not in self.bands:
1120 msg =
'fitBand %s not in bands' % (band)
1121 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.fitBands, self, msg)
1122 for band
in self.requiredBands:
1123 if band
not in self.bands:
1124 msg =
'requiredBand %s not in bands' % (band)
1125 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.requiredBands, self, msg)
1126 for band
in self.colorSplitBands:
1127 if band
not in self.bands:
1128 msg =
'colorSplitBand %s not in bands' % (band)
1129 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.colorSplitBands, self, msg)
1130 for band
in self.bands:
1131 if band
not in self.superStarSubCcdDict:
1132 msg =
'band %s not in superStarSubCcdDict' % (band)
1133 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.superStarSubCcdDict,
1135 if band
not in self.ccdGraySubCcdDict:
1136 msg =
'band %s not in ccdGraySubCcdDict' % (band)
1137 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.ccdGraySubCcdDict,
1139 if band
not in self.expGrayPhotometricCutDict:
1140 msg =
'band %s not in expGrayPhotometricCutDict' % (band)
1141 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.expGrayPhotometricCutDict,
1143 if band
not in self.expGrayHighCutDict:
1144 msg =
'band %s not in expGrayHighCutDict' % (band)
1145 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.expGrayHighCutDict,
1147 if band
not in self.expVarGrayPhotometricCutDict:
1148 msg =
'band %s not in expVarGrayPhotometricCutDict' % (band)
1149 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.expVarGrayPhotometricCutDict,
1151 if band
not in self.sigFgcmMaxEGrayDict:
1152 msg =
'band %s not in sigFgcmMaxEGrayDict' % (band)
1153 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.sigFgcmMaxEGrayDict,
1155 if band
not in self.approxThroughputDict:
1156 msg =
'band %s not in approxThroughputDict' % (band)
1157 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.approxThroughputDict,
1159 if band
not in self.useRepeatabilityForExpGrayCutsDict:
1160 msg =
'band %s not in useRepeatabilityForExpGrayCutsDict' % (band)
1161 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.useRepeatabilityForExpGrayCutsDict,
1164 if self.doComputeDeltaAperPerVisit
or self.doComputeDeltaAperMap \
1165 or self.doComputeDeltaAperPerCcd:
1166 if self.deltaAperInnerRadiusArcsec <= 0.0:
1167 msg =
'deltaAperInnerRadiusArcsec must be positive if deltaAper computations are turned on.'
1168 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.deltaAperInnerRadiusArcsec,
1170 if self.deltaAperOuterRadiusArcsec <= 0.0:
1171 msg =
'deltaAperOuterRadiusArcsec must be positive if deltaAper computations are turned on.'
1172 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.deltaAperOuterRadiusArcsec,
1174 if self.deltaAperOuterRadiusArcsec <= self.deltaAperInnerRadiusArcsec:
1175 msg = (
'deltaAperOuterRadiusArcsec must be greater than deltaAperInnerRadiusArcsec if '
1176 'deltaAper computations are turned on.')
1177 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.deltaAperOuterRadiusArcsec,
1181class FgcmFitCycleTask(pipeBase.PipelineTask):
1183 Run Single fit cycle for FGCM global calibration
1186 ConfigClass = FgcmFitCycleConfig
1187 _DefaultName =
"fgcmFitCycle"
1189 def __init__(self, initInputs=None, **kwargs):
1190 super().__init__(**kwargs)
1192 def runQuantum(self, butlerQC, inputRefs, outputRefs):
1193 camera = butlerQC.get(inputRefs.camera)
1195 nCore = butlerQC.resources.num_cores
1199 handleDict[
'fgcmLookUpTable'] = butlerQC.get(inputRefs.fgcmLookUpTable)
1200 handleDict[
'fgcmVisitCatalog'] = butlerQC.get(inputRefs.fgcmVisitCatalog)
1202 if self.config.useParquetCatalogFormat:
1203 handleDict[
'fgcmStarObservations'] = butlerQC.get(inputRefs.fgcmStarObservationsParquet)
1204 handleDict[
'fgcmStarIds'] = butlerQC.get(inputRefs.fgcmStarIdsParquet)
1205 if self.config.doReferenceCalibration:
1206 handleDict[
'fgcmReferenceStars'] = butlerQC.get(inputRefs.fgcmReferenceStarsParquet)
1208 handleDict[
'fgcmStarObservations'] = butlerQC.get(inputRefs.fgcmStarObservations)
1209 handleDict[
'fgcmStarIds'] = butlerQC.get(inputRefs.fgcmStarIds)
1210 handleDict[
'fgcmStarIndices'] = butlerQC.get(inputRefs.fgcmStarIndices)
1211 if self.config.doReferenceCalibration:
1212 handleDict[
'fgcmReferenceStars'] = butlerQC.get(inputRefs.fgcmReferenceStars)
1213 if self.config.cycleNumber > 0:
1214 handleDict[
'fgcmFlaggedStars'] = butlerQC.get(inputRefs.fgcmFlaggedStarsInput)
1215 handleDict[
'fgcmFitParameters'] = butlerQC.get(inputRefs.fgcmFitParametersInput)
1217 fgcmDatasetDict =
None
1218 if self.config.doMultipleCycles:
1220 config = copy.copy(self.config)
1221 config.update(cycleNumber=0)
1222 for cycle
in range(self.config.multipleCyclesFinalCycleNumber + 1):
1223 if cycle == self.config.multipleCyclesFinalCycleNumber:
1224 config.update(isFinalCycle=
True)
1227 handleDict[
'fgcmFlaggedStars'] = fgcmDatasetDict[
'fgcmFlaggedStars']
1228 handleDict[
'fgcmFitParameters'] = fgcmDatasetDict[
'fgcmFitParameters']
1233 for outputRefName
in outputRefs.keys():
1234 if outputRefName.endswith(
"Plot")
and f
"Cycle{cycle}" in outputRefName:
1235 ref = getattr(outputRefs, outputRefName)
1236 if isinstance(ref, (tuple, list)):
1237 if "physical_filter" in ref[0].dimensions:
1238 for filterRef
in ref:
1239 handleDictKey = f
"{outputRefName}_{filterRef.dataId['physical_filter']}"
1240 plotHandleDict[handleDictKey] = filterRef
1241 if "band" in ref[0].dimensions:
1243 handleDictKey = f
"{outputRefName}_{bandRef.dataId['band']}"
1244 plotHandleDict[handleDictKey] = bandRef
1246 plotHandleDict[outputRefName] = ref
1248 fgcmDatasetDict, config = self._fgcmFitCycle(
1252 plotHandleDict=plotHandleDict,
1256 butlerQC.put(fgcmDatasetDict[
'fgcmFitParameters'],
1257 getattr(outputRefs, f
'fgcm_Cycle{cycle}_FitParameters'))
1258 butlerQC.put(fgcmDatasetDict[
'fgcmFlaggedStars'],
1259 getattr(outputRefs, f
'fgcm_Cycle{cycle}_FlaggedStars'))
1260 butlerQC.put(config,
1261 getattr(outputRefs, f
'fgcm_Cycle{cycle}_OutputConfig'))
1262 if self.outputZeropoints:
1263 butlerQC.put(fgcmDatasetDict[
'fgcmZeropoints'],
1264 getattr(outputRefs, f
'fgcm_Cycle{cycle}_Zeropoints'))
1265 butlerQC.put(fgcmDatasetDict[
'fgcmAtmosphereParameters'],
1266 getattr(outputRefs, f
'fgcm_Cycle{cycle}_AtmosphereParameters'))
1267 if self.outputStandards:
1268 butlerQC.put(fgcmDatasetDict[
'fgcmStandardStars'],
1269 getattr(outputRefs, f
'fgcm_Cycle{cycle}_StandardStars'))
1276 for outputRefName
in outputRefs.keys():
1277 if outputRefName.endswith(
"Plot")
and f
"Cycle{self.config.cycleNumber}" in outputRefName:
1278 ref = getattr(outputRefs, outputRefName)
1279 if isinstance(ref, (tuple, list)):
1280 if "physical_filter" in ref[0].dimensions:
1281 for filterRef
in ref:
1282 handleDictKey = f
"{outputRefName}_{filterRef.dataId['physical_filter']}"
1283 plotHandleDict[handleDictKey] = filterRef
1284 if "band" in ref[0].dimensions:
1286 handleDictKey = f
"{outputRefName}_{bandRef.dataId['band']}"
1287 plotHandleDict[handleDictKey] = bandRef
1289 plotHandleDict[outputRefName] = ref
1291 fgcmDatasetDict, _ = self._fgcmFitCycle(
1296 plotHandleDict=plotHandleDict,
1300 butlerQC.put(fgcmDatasetDict[
'fgcmFitParameters'], outputRefs.fgcmFitParameters)
1301 butlerQC.put(fgcmDatasetDict[
'fgcmFlaggedStars'], outputRefs.fgcmFlaggedStars)
1302 if self.outputZeropoints:
1303 butlerQC.put(fgcmDatasetDict[
'fgcmZeropoints'], outputRefs.fgcmZeropoints)
1304 butlerQC.put(fgcmDatasetDict[
'fgcmAtmosphereParameters'], outputRefs.fgcmAtmosphereParameters)
1305 if self.outputStandards:
1306 butlerQC.put(fgcmDatasetDict[
'fgcmStandardStars'], outputRefs.fgcmStandardStars)
1313 plotHandleDict=None,
1323 camera : `lsst.afw.cameraGeom.Camera`
1325 All handles are `lsst.daf.butler.DeferredDatasetHandle`
1326 handle dictionary with keys:
1328 ``"fgcmLookUpTable"``
1329 handle for the FGCM look-up table.
1330 ``"fgcmVisitCatalog"``
1331 handle for visit summary catalog.
1332 ``"fgcmStarObservations"``
1333 handle for star observation catalog.
1335 handle for star id catalog.
1336 ``"fgcmStarIndices"``
1337 handle for star index catalog.
1338 ``"fgcmReferenceStars"``
1339 handle for matched reference star catalog.
1340 ``"fgcmFlaggedStars"``
1341 handle for flagged star catalog.
1342 ``"fgcmFitParameters"``
1343 handle for fit parameter catalog.
1344 butlerQC : `lsst.pipe.base.QuantumContext`, optional
1345 Quantum context used for serializing plots.
1346 plotHandleDict : `dict` [`str`, `lsst.daf.butler.DatasetRef`], optional
1347 Dictionary of plot dataset refs, keyed by plot name.
1348 config : `lsst.pex.config.Config`, optional
1349 Configuration to use to override self.config.
1350 nCore : `int`, optional
1351 Number of cores to use during fitting.
1352 multiCycle : `bool`, optional
1353 Is this part of a multicycle run?
1357 fgcmDatasetDict : `dict`
1358 Dictionary of datasets to persist.
1360 if config
is not None:
1363 _config = self.config
1366 self.maxIter = _config.maxIterBeforeFinalCycle
1367 self.outputStandards = _config.outputStandardsBeforeFinalCycle
1368 self.outputZeropoints = _config.outputZeropointsBeforeFinalCycle
1369 self.resetFitParameters =
True
1371 if _config.isFinalCycle:
1376 self.outputStandards =
True
1377 self.outputZeropoints =
True
1378 self.resetFitParameters =
False
1380 lutCat = handleDict[
'fgcmLookUpTable'].get()
1381 fgcmLut, lutIndexVals, lutStd = translateFgcmLut(lutCat,
1382 dict(_config.physicalFilterMap))
1386 doPlots = _config.doPlots
1387 if doPlots
and multiCycle:
1388 if _config.cycleNumber < (_config.multipleCyclesFinalCycleNumber - 1) \
1389 and not _config.doPlotsBeforeFinalCycles:
1392 configDict = makeConfigDict(_config, self.log, camera,
1393 self.maxIter, self.resetFitParameters,
1394 self.outputZeropoints,
1395 lutIndexVals[0][
'FILTERNAMES'],
1400 visitCat = handleDict[
'fgcmVisitCatalog'].get()
1401 fgcmExpInfo = translateVisitCatalog(visitCat)
1405 self.config.defaultCameraOrientation)
1407 noFitsDict = {
'lutIndex': lutIndexVals,
1409 'expInfo': fgcmExpInfo,
1410 'focalPlaneProjector': focalPlaneProjector}
1413 fgcmFitCycle = fgcm.FgcmFitCycle(
1416 noFitsDict=noFitsDict,
1419 plotHandleDict=plotHandleDict,
1423 if (fgcmFitCycle.initialCycle):
1425 fgcmPars = fgcm.FgcmParameters.newParsWithArrays(fgcmFitCycle.fgcmConfig,
1429 plotHandleDict=plotHandleDict)
1432 parCat = handleDict[
'fgcmFitParameters']
1434 parCat = handleDict[
'fgcmFitParameters'].get()
1435 inParInfo, inParams, inSuperStar = self._loadParameters(parCat)
1437 fgcmPars = fgcm.FgcmParameters.loadParsWithArrays(fgcmFitCycle.fgcmConfig,
1443 plotHandleDict=plotHandleDict)
1446 fgcmStars = fgcm.FgcmStars(fgcmFitCycle.fgcmConfig, butlerQC=butlerQC, plotHandleDict=plotHandleDict)
1448 starObs = handleDict[
'fgcmStarObservations'].get()
1449 starIds = handleDict[
'fgcmStarIds'].get()
1450 if not self.config.useParquetCatalogFormat:
1451 starIndices = handleDict[
'fgcmStarIndices'].get()
1456 if 'fgcmFlaggedStars' in handleDict:
1458 flaggedStars = handleDict[
'fgcmFlaggedStars']
1460 flaggedStars = handleDict[
'fgcmFlaggedStars'].get()
1461 flagId = flaggedStars[
'objId'][:]
1462 flagFlag = flaggedStars[
'objFlag'][:]
1465 elif self.config.useParquetCatalogFormat:
1471 (flagged,) = (starIds[
'obj_flag'] > 0).nonzero()
1472 flagId = starIds[
'fgcm_id'][flagged]
1473 flagFlag = starIds[
'obj_flag'][flagged]
1478 if _config.doReferenceCalibration:
1479 refStars = handleDict[
'fgcmReferenceStars'].get()
1481 refMag, refMagErr = extractReferenceMags(refStars,
1483 _config.physicalFilterMap)
1485 refId = refStars[
'fgcm_id'][:]
1495 if self.config.useParquetCatalogFormat:
1496 visitIndex = np.searchsorted(fgcmExpInfo[
'VISIT'], starObs[
'visit'])
1498 visitIndex = np.searchsorted(fgcmExpInfo[
'VISIT'], starObs[
'visit'][starIndices[
'obsIndex']])
1507 if self.config.useParquetCatalogFormat:
1510 fgcmStars.loadStars(fgcmPars,
1511 starObs[
'visit'][:],
1512 starObs[
'detector'][:],
1515 starObs[
'inst_mag'][:],
1516 starObs[
'inst_mag_err'][:],
1517 fgcmExpInfo[
'FILTERNAME'][visitIndex],
1518 starIds[
'fgcm_id'][:],
1521 starIds[
'obs_arr_index'][:],
1522 starIds[
'n_obs'][:],
1523 obsX=starObs[
'x'][:],
1524 obsY=starObs[
'y'][:],
1525 obsDeltaMagBkg=starObs[
'delta_mag_bkg'][:],
1526 obsDeltaAper=starObs[
'delta_mag_aper'][:],
1529 refMagErr=refMagErr,
1533 objIDAlternate=starIds[
'isolated_star_id'])
1538 conv = starObs[0][
'ra'].asDegrees() / float(starObs[0][
'ra'])
1540 fgcmStars.loadStars(fgcmPars,
1541 starObs[
'visit'][starIndices[
'obsIndex']],
1542 starObs[
'ccd'][starIndices[
'obsIndex']],
1543 starObs[
'ra'][starIndices[
'obsIndex']] * conv,
1544 starObs[
'dec'][starIndices[
'obsIndex']] * conv,
1545 starObs[
'instMag'][starIndices[
'obsIndex']],
1546 starObs[
'instMagErr'][starIndices[
'obsIndex']],
1547 fgcmExpInfo[
'FILTERNAME'][visitIndex],
1548 starIds[
'fgcm_id'][:],
1551 starIds[
'obsArrIndex'][:],
1553 obsX=starObs[
'x'][starIndices[
'obsIndex']],
1554 obsY=starObs[
'y'][starIndices[
'obsIndex']],
1555 obsDeltaMagBkg=starObs[
'deltaMagBkg'][starIndices[
'obsIndex']],
1556 obsDeltaAper=starObs[
'deltaMagAper'][starIndices[
'obsIndex']],
1557 psfCandidate=starObs[
'psf_candidate'][starIndices[
'obsIndex']],
1560 refMagErr=refMagErr,
1577 fgcmFitCycle.setLUT(fgcmLut)
1578 fgcmFitCycle.setStars(fgcmStars, fgcmPars)
1579 fgcmFitCycle.setPars(fgcmPars)
1582 fgcmFitCycle.finishSetup()
1591 fgcmDatasetDict = self._makeFgcmOutputDatasets(fgcmFitCycle)
1596 updatedPhotometricCutDict = {b: float(fgcmFitCycle.updatedPhotometricCut[i])
for
1597 i, b
in enumerate(_config.bands)}
1598 updatedHighCutDict = {band: float(fgcmFitCycle.updatedHighCut[i])
for
1599 i, band
in enumerate(_config.bands)}
1601 outConfig = copy.copy(_config)
1602 outConfig.update(cycleNumber=(_config.cycleNumber + 1),
1603 precomputeSuperStarInitialCycle=
False,
1604 freezeStdAtmosphere=
False,
1605 expGrayPhotometricCutDict=updatedPhotometricCutDict,
1606 expGrayHighCutDict=updatedHighCutDict)
1608 outConfig.connections.update(previousCycleNumber=str(_config.cycleNumber),
1609 cycleNumber=str(_config.cycleNumber + 1))
1612 configFileName =
'%s_cycle%02d_config.py' % (outConfig.outfileBase,
1613 outConfig.cycleNumber)
1614 outConfig.save(configFileName)
1616 if _config.isFinalCycle == 1:
1618 self.log.info(
"Everything is in place to run fgcmOutputProducts.py")
1620 self.log.info(
"Saved config for next cycle to %s" % (configFileName))
1621 self.log.info(
"Be sure to look at:")
1622 self.log.info(
" config.expGrayPhotometricCut")
1623 self.log.info(
" config.expGrayHighCut")
1624 self.log.info(
"If you are satisfied with the fit, please set:")
1625 self.log.info(
" config.isFinalCycle = True")
1627 fgcmFitCycle.freeSharedMemory()
1629 return fgcmDatasetDict, outConfig
1631 def _loadParameters(self, parCat):
1633 Load FGCM parameters from a previous fit cycle
1637 parCat : `lsst.afw.table.BaseCatalog`
1638 Parameter catalog in afw table form.
1642 inParInfo: `numpy.ndarray`
1643 Numpy array parameter information formatted for input to fgcm
1644 inParameters: `numpy.ndarray`
1645 Numpy array parameter values formatted for input to fgcm
1646 inSuperStar: `numpy.array`
1647 Superstar flat formatted for input to fgcm
1649 parLutFilterNames = np.array(parCat[0][
'lutFilterNames'].split(
','))
1650 parFitBands = np.array(parCat[0][
'fitBands'].split(
','))
1652 inParInfo = np.zeros(1, dtype=[(
'NCCD',
'i4'),
1653 (
'LUTFILTERNAMES', parLutFilterNames.dtype.str,
1654 (parLutFilterNames.size, )),
1655 (
'FITBANDS', parFitBands.dtype.str, (parFitBands.size, )),
1656 (
'LNTAUUNIT',
'f8'),
1657 (
'LNTAUSLOPEUNIT',
'f8'),
1658 (
'ALPHAUNIT',
'f8'),
1659 (
'LNPWVUNIT',
'f8'),
1660 (
'LNPWVSLOPEUNIT',
'f8'),
1661 (
'LNPWVQUADRATICUNIT',
'f8'),
1662 (
'LNPWVGLOBALUNIT',
'f8'),
1664 (
'QESYSUNIT',
'f8'),
1665 (
'FILTEROFFSETUNIT',
'f8'),
1666 (
'HASEXTERNALPWV',
'i2'),
1667 (
'HASEXTERNALTAU',
'i2')])
1668 inParInfo[
'NCCD'] = parCat[
'nCcd']
1669 inParInfo[
'LUTFILTERNAMES'][:] = parLutFilterNames
1670 inParInfo[
'FITBANDS'][:] = parFitBands
1671 inParInfo[
'HASEXTERNALPWV'] = parCat[
'hasExternalPwv']
1672 inParInfo[
'HASEXTERNALTAU'] = parCat[
'hasExternalTau']
1674 inParams = np.zeros(1, dtype=[(
'PARALPHA',
'f8', (parCat[
'parAlpha'].size, )),
1675 (
'PARO3',
'f8', (parCat[
'parO3'].size, )),
1676 (
'PARLNTAUINTERCEPT',
'f8',
1677 (parCat[
'parLnTauIntercept'].size, )),
1678 (
'PARLNTAUSLOPE',
'f8',
1679 (parCat[
'parLnTauSlope'].size, )),
1680 (
'PARLNPWVINTERCEPT',
'f8',
1681 (parCat[
'parLnPwvIntercept'].size, )),
1682 (
'PARLNPWVSLOPE',
'f8',
1683 (parCat[
'parLnPwvSlope'].size, )),
1684 (
'PARLNPWVQUADRATIC',
'f8',
1685 (parCat[
'parLnPwvQuadratic'].size, )),
1686 (
'PARQESYSINTERCEPT',
'f8',
1687 (parCat[
'parQeSysIntercept'].size, )),
1688 (
'COMPQESYSSLOPE',
'f8',
1689 (parCat[
'compQeSysSlope'].size, )),
1690 (
'PARFILTEROFFSET',
'f8',
1691 (parCat[
'parFilterOffset'].size, )),
1692 (
'PARFILTEROFFSETFITFLAG',
'i2',
1693 (parCat[
'parFilterOffsetFitFlag'].size, )),
1694 (
'PARRETRIEVEDLNPWVSCALE',
'f8'),
1695 (
'PARRETRIEVEDLNPWVOFFSET',
'f8'),
1696 (
'PARRETRIEVEDLNPWVNIGHTLYOFFSET',
'f8',
1697 (parCat[
'parRetrievedLnPwvNightlyOffset'].size, )),
1698 (
'COMPABSTHROUGHPUT',
'f8',
1699 (parCat[
'compAbsThroughput'].size, )),
1700 (
'COMPREFOFFSET',
'f8',
1701 (parCat[
'compRefOffset'].size, )),
1702 (
'COMPREFSIGMA',
'f8',
1703 (parCat[
'compRefSigma'].size, )),
1704 (
'COMPMIRRORCHROMATICITY',
'f8',
1705 (parCat[
'compMirrorChromaticity'].size, )),
1706 (
'MIRRORCHROMATICITYPIVOT',
'f8',
1707 (parCat[
'mirrorChromaticityPivot'].size, )),
1708 (
'COMPCCDCHROMATICITY',
'f8',
1709 (parCat[
'compCcdChromaticity'].size, )),
1710 (
'COMPMEDIANSEDSLOPE',
'f8',
1711 (parCat[
'compMedianSedSlope'].size, )),
1712 (
'COMPAPERCORRPIVOT',
'f8',
1713 (parCat[
'compAperCorrPivot'].size, )),
1714 (
'COMPAPERCORRSLOPE',
'f8',
1715 (parCat[
'compAperCorrSlope'].size, )),
1716 (
'COMPAPERCORRSLOPEERR',
'f8',
1717 (parCat[
'compAperCorrSlopeErr'].size, )),
1718 (
'COMPAPERCORRRANGE',
'f8',
1719 (parCat[
'compAperCorrRange'].size, )),
1720 (
'COMPMODELERREXPTIMEPIVOT',
'f8',
1721 (parCat[
'compModelErrExptimePivot'].size, )),
1722 (
'COMPMODELERRFWHMPIVOT',
'f8',
1723 (parCat[
'compModelErrFwhmPivot'].size, )),
1724 (
'COMPMODELERRSKYPIVOT',
'f8',
1725 (parCat[
'compModelErrSkyPivot'].size, )),
1726 (
'COMPMODELERRPARS',
'f8',
1727 (parCat[
'compModelErrPars'].size, )),
1728 (
'COMPEXPGRAY',
'f8',
1729 (parCat[
'compExpGray'].size, )),
1730 (
'COMPVARGRAY',
'f8',
1731 (parCat[
'compVarGray'].size, )),
1732 (
'COMPEXPDELTAMAGBKG',
'f8',
1733 (parCat[
'compExpDeltaMagBkg'].size, )),
1734 (
'COMPNGOODSTARPEREXP',
'i4',
1735 (parCat[
'compNGoodStarPerExp'].size, )),
1736 (
'COMPEXPREFOFFSET',
'f8',
1737 (parCat[
'compExpRefOffset'].size, )),
1738 (
'COMPSIGFGCM',
'f8',
1739 (parCat[
'compSigFgcm'].size, )),
1740 (
'COMPSIGMACAL',
'f8',
1741 (parCat[
'compSigmaCal'].size, )),
1742 (
'COMPRETRIEVEDLNPWV',
'f8',
1743 (parCat[
'compRetrievedLnPwv'].size, )),
1744 (
'COMPRETRIEVEDLNPWVRAW',
'f8',
1745 (parCat[
'compRetrievedLnPwvRaw'].size, )),
1746 (
'COMPRETRIEVEDLNPWVFLAG',
'i2',
1747 (parCat[
'compRetrievedLnPwvFlag'].size, )),
1748 (
'COMPRETRIEVEDTAUNIGHT',
'f8',
1749 (parCat[
'compRetrievedTauNight'].size, )),
1750 (
'COMPEPSILON',
'f8',
1751 (parCat[
'compEpsilon'].size, )),
1752 (
'COMPMEDDELTAAPER',
'f8',
1753 (parCat[
'compMedDeltaAper'].size, )),
1754 (
'COMPGLOBALEPSILON',
'f4',
1755 (parCat[
'compGlobalEpsilon'].size, )),
1756 (
'COMPEPSILONMAP',
'f4',
1757 (parCat[
'compEpsilonMap'].size, )),
1758 (
'COMPEPSILONNSTARMAP',
'i4',
1759 (parCat[
'compEpsilonNStarMap'].size, )),
1760 (
'COMPEPSILONCCDMAP',
'f4',
1761 (parCat[
'compEpsilonCcdMap'].size, )),
1762 (
'COMPEPSILONCCDNSTARMAP',
'i4',
1763 (parCat[
'compEpsilonCcdNStarMap'].size, ))])
1765 inParams[
'PARALPHA'][:] = parCat[
'parAlpha'][0, :]
1766 inParams[
'PARO3'][:] = parCat[
'parO3'][0, :]
1767 inParams[
'PARLNTAUINTERCEPT'][:] = parCat[
'parLnTauIntercept'][0, :]
1768 inParams[
'PARLNTAUSLOPE'][:] = parCat[
'parLnTauSlope'][0, :]
1769 inParams[
'PARLNPWVINTERCEPT'][:] = parCat[
'parLnPwvIntercept'][0, :]
1770 inParams[
'PARLNPWVSLOPE'][:] = parCat[
'parLnPwvSlope'][0, :]
1771 inParams[
'PARLNPWVQUADRATIC'][:] = parCat[
'parLnPwvQuadratic'][0, :]
1772 inParams[
'PARQESYSINTERCEPT'][:] = parCat[
'parQeSysIntercept'][0, :]
1773 inParams[
'COMPQESYSSLOPE'][:] = parCat[
'compQeSysSlope'][0, :]
1774 inParams[
'PARFILTEROFFSET'][:] = parCat[
'parFilterOffset'][0, :]
1775 inParams[
'PARFILTEROFFSETFITFLAG'][:] = parCat[
'parFilterOffsetFitFlag'][0, :]
1776 inParams[
'PARRETRIEVEDLNPWVSCALE'] = parCat[
'parRetrievedLnPwvScale']
1777 inParams[
'PARRETRIEVEDLNPWVOFFSET'] = parCat[
'parRetrievedLnPwvOffset']
1778 inParams[
'PARRETRIEVEDLNPWVNIGHTLYOFFSET'][:] = parCat[
'parRetrievedLnPwvNightlyOffset'][0, :]
1779 inParams[
'COMPABSTHROUGHPUT'][:] = parCat[
'compAbsThroughput'][0, :]
1780 inParams[
'COMPREFOFFSET'][:] = parCat[
'compRefOffset'][0, :]
1781 inParams[
'COMPREFSIGMA'][:] = parCat[
'compRefSigma'][0, :]
1782 inParams[
'COMPMIRRORCHROMATICITY'][:] = parCat[
'compMirrorChromaticity'][0, :]
1783 inParams[
'MIRRORCHROMATICITYPIVOT'][:] = parCat[
'mirrorChromaticityPivot'][0, :]
1784 inParams[
'COMPCCDCHROMATICITY'][:] = parCat[
'compCcdChromaticity'][0, :]
1785 inParams[
'COMPMEDIANSEDSLOPE'][:] = parCat[
'compMedianSedSlope'][0, :]
1786 inParams[
'COMPAPERCORRPIVOT'][:] = parCat[
'compAperCorrPivot'][0, :]
1787 inParams[
'COMPAPERCORRSLOPE'][:] = parCat[
'compAperCorrSlope'][0, :]
1788 inParams[
'COMPAPERCORRSLOPEERR'][:] = parCat[
'compAperCorrSlopeErr'][0, :]
1789 inParams[
'COMPAPERCORRRANGE'][:] = parCat[
'compAperCorrRange'][0, :]
1790 inParams[
'COMPMODELERREXPTIMEPIVOT'][:] = parCat[
'compModelErrExptimePivot'][0, :]
1791 inParams[
'COMPMODELERRFWHMPIVOT'][:] = parCat[
'compModelErrFwhmPivot'][0, :]
1792 inParams[
'COMPMODELERRSKYPIVOT'][:] = parCat[
'compModelErrSkyPivot'][0, :]
1793 inParams[
'COMPMODELERRPARS'][:] = parCat[
'compModelErrPars'][0, :]
1794 inParams[
'COMPEXPGRAY'][:] = parCat[
'compExpGray'][0, :]
1795 inParams[
'COMPVARGRAY'][:] = parCat[
'compVarGray'][0, :]
1796 inParams[
'COMPEXPDELTAMAGBKG'][:] = parCat[
'compExpDeltaMagBkg'][0, :]
1797 inParams[
'COMPNGOODSTARPEREXP'][:] = parCat[
'compNGoodStarPerExp'][0, :]
1798 inParams[
'COMPEXPREFOFFSET'][:] = parCat[
'compExpRefOffset'][0, :]
1799 inParams[
'COMPSIGFGCM'][:] = parCat[
'compSigFgcm'][0, :]
1800 inParams[
'COMPSIGMACAL'][:] = parCat[
'compSigmaCal'][0, :]
1801 inParams[
'COMPRETRIEVEDLNPWV'][:] = parCat[
'compRetrievedLnPwv'][0, :]
1802 inParams[
'COMPRETRIEVEDLNPWVRAW'][:] = parCat[
'compRetrievedLnPwvRaw'][0, :]
1803 inParams[
'COMPRETRIEVEDLNPWVFLAG'][:] = parCat[
'compRetrievedLnPwvFlag'][0, :]
1804 inParams[
'COMPRETRIEVEDTAUNIGHT'][:] = parCat[
'compRetrievedTauNight'][0, :]
1805 inParams[
'COMPEPSILON'][:] = parCat[
'compEpsilon'][0, :]
1806 inParams[
'COMPMEDDELTAAPER'][:] = parCat[
'compMedDeltaAper'][0, :]
1807 inParams[
'COMPGLOBALEPSILON'][:] = parCat[
'compGlobalEpsilon'][0, :]
1808 inParams[
'COMPEPSILONMAP'][:] = parCat[
'compEpsilonMap'][0, :]
1809 inParams[
'COMPEPSILONNSTARMAP'][:] = parCat[
'compEpsilonNStarMap'][0, :]
1810 inParams[
'COMPEPSILONCCDMAP'][:] = parCat[
'compEpsilonCcdMap'][0, :]
1811 inParams[
'COMPEPSILONCCDNSTARMAP'][:] = parCat[
'compEpsilonCcdNStarMap'][0, :]
1813 inSuperStar = np.zeros(parCat[
'superstarSize'][0, :], dtype=
'f8')
1814 inSuperStar[:, :, :, :] = parCat[
'superstar'][0, :].reshape(inSuperStar.shape)
1816 return (inParInfo, inParams, inSuperStar)
1818 def _makeFgcmOutputDatasets(self, fgcmFitCycle):
1820 Persist FGCM datasets through the butler.
1824 fgcmFitCycle: `lsst.fgcm.FgcmFitCycle`
1825 Fgcm Fit cycle object
1827 fgcmDatasetDict = {}
1830 parInfo, pars = fgcmFitCycle.fgcmPars.parsToArrays()
1835 lutFilterNameString = comma.join([n.decode(
'utf-8')
1836 for n
in parInfo[
'LUTFILTERNAMES'][0]])
1837 fitBandString = comma.join([n.decode(
'utf-8')
1838 for n
in parInfo[
'FITBANDS'][0]])
1840 parSchema = self._makeParSchema(parInfo, pars, fgcmFitCycle.fgcmPars.parSuperStarFlat,
1841 lutFilterNameString, fitBandString)
1842 parCat = self._makeParCatalog(parSchema, parInfo, pars,
1843 fgcmFitCycle.fgcmPars.parSuperStarFlat,
1844 lutFilterNameString, fitBandString)
1846 fgcmDatasetDict[
'fgcmFitParameters'] = parCat
1851 flagStarSchema = self._makeFlagStarSchema()
1852 flagStarStruct = fgcmFitCycle.fgcmStars.getFlagStarIndices()
1853 flagStarCat = self._makeFlagStarCat(flagStarSchema, flagStarStruct)
1855 fgcmDatasetDict[
'fgcmFlaggedStars'] = flagStarCat
1858 if self.outputZeropoints:
1859 superStarChebSize = fgcmFitCycle.fgcmZpts.zpStruct[
'FGCM_FZPT_SSTAR_CHEB'].shape[1]
1860 zptChebSize = fgcmFitCycle.fgcmZpts.zpStruct[
'FGCM_FZPT_CHEB'].shape[1]
1862 zptSchema = makeZptSchema(superStarChebSize, zptChebSize)
1863 zptCat = makeZptCat(zptSchema, fgcmFitCycle.fgcmZpts.zpStruct)
1865 fgcmDatasetDict[
'fgcmZeropoints'] = zptCat
1869 atmSchema = makeAtmSchema()
1870 atmCat = makeAtmCat(atmSchema, fgcmFitCycle.fgcmZpts.atmStruct)
1872 fgcmDatasetDict[
'fgcmAtmosphereParameters'] = atmCat
1875 if self.outputStandards:
1876 stdStruct, goodBands = fgcmFitCycle.fgcmStars.retrieveStdStarCatalog(fgcmFitCycle.fgcmPars)
1877 stdSchema = makeStdSchema(len(goodBands))
1878 stdCat = makeStdCat(stdSchema, stdStruct, goodBands)
1880 fgcmDatasetDict[
'fgcmStandardStars'] = stdCat
1882 return fgcmDatasetDict
1884 def _makeParSchema(self, parInfo, pars, parSuperStarFlat,
1885 lutFilterNameString, fitBandString):
1887 Make the parameter persistence schema
1891 parInfo: `numpy.ndarray`
1892 Parameter information returned by fgcm
1893 pars: `numpy.ndarray`
1894 Parameter values returned by fgcm
1895 parSuperStarFlat: `numpy.array`
1896 Superstar flat values returned by fgcm
1897 lutFilterNameString: `str`
1898 Combined string of all the lutFilterNames
1899 fitBandString: `str`
1900 Combined string of all the fitBands
1904 parSchema: `afwTable.schema`
1910 parSchema.addField(
'nCcd', type=np.int32, doc=
'Number of CCDs')
1911 parSchema.addField(
'lutFilterNames', type=str, doc=
'LUT Filter names in parameter file',
1912 size=len(lutFilterNameString))
1913 parSchema.addField(
'fitBands', type=str, doc=
'Bands that were fit',
1914 size=len(fitBandString))
1915 parSchema.addField(
'lnTauUnit', type=np.float64, doc=
'Step units for ln(AOD)')
1916 parSchema.addField(
'lnTauSlopeUnit', type=np.float64,
1917 doc=
'Step units for ln(AOD) slope')
1918 parSchema.addField(
'alphaUnit', type=np.float64, doc=
'Step units for alpha')
1919 parSchema.addField(
'lnPwvUnit', type=np.float64, doc=
'Step units for ln(pwv)')
1920 parSchema.addField(
'lnPwvSlopeUnit', type=np.float64,
1921 doc=
'Step units for ln(pwv) slope')
1922 parSchema.addField(
'lnPwvQuadraticUnit', type=np.float64,
1923 doc=
'Step units for ln(pwv) quadratic term')
1924 parSchema.addField(
'lnPwvGlobalUnit', type=np.float64,
1925 doc=
'Step units for global ln(pwv) parameters')
1926 parSchema.addField(
'o3Unit', type=np.float64, doc=
'Step units for O3')
1927 parSchema.addField(
'qeSysUnit', type=np.float64, doc=
'Step units for mirror gray')
1928 parSchema.addField(
'filterOffsetUnit', type=np.float64, doc=
'Step units for filter offset')
1929 parSchema.addField(
'hasExternalPwv', type=np.int32, doc=
'Parameters fit using external pwv')
1930 parSchema.addField(
'hasExternalTau', type=np.int32, doc=
'Parameters fit using external tau')
1933 parSchema.addField(
'parAlpha', type=
'ArrayD', doc=
'Alpha parameter vector',
1934 size=pars[
'PARALPHA'].size)
1935 parSchema.addField(
'parO3', type=
'ArrayD', doc=
'O3 parameter vector',
1936 size=pars[
'PARO3'].size)
1937 parSchema.addField(
'parLnTauIntercept', type=
'ArrayD',
1938 doc=
'ln(Tau) intercept parameter vector',
1939 size=pars[
'PARLNTAUINTERCEPT'].size)
1940 parSchema.addField(
'parLnTauSlope', type=
'ArrayD',
1941 doc=
'ln(Tau) slope parameter vector',
1942 size=pars[
'PARLNTAUSLOPE'].size)
1943 parSchema.addField(
'parLnPwvIntercept', type=
'ArrayD', doc=
'ln(pwv) intercept parameter vector',
1944 size=pars[
'PARLNPWVINTERCEPT'].size)
1945 parSchema.addField(
'parLnPwvSlope', type=
'ArrayD', doc=
'ln(pwv) slope parameter vector',
1946 size=pars[
'PARLNPWVSLOPE'].size)
1947 parSchema.addField(
'parLnPwvQuadratic', type=
'ArrayD', doc=
'ln(pwv) quadratic parameter vector',
1948 size=pars[
'PARLNPWVQUADRATIC'].size)
1949 parSchema.addField(
'parQeSysIntercept', type=
'ArrayD', doc=
'Mirror gray intercept parameter vector',
1950 size=pars[
'PARQESYSINTERCEPT'].size)
1951 parSchema.addField(
'compQeSysSlope', type=
'ArrayD', doc=
'Mirror gray slope parameter vector',
1952 size=pars[0][
'COMPQESYSSLOPE'].size)
1953 parSchema.addField(
'parFilterOffset', type=
'ArrayD', doc=
'Filter offset parameter vector',
1954 size=pars[
'PARFILTEROFFSET'].size)
1955 parSchema.addField(
'parFilterOffsetFitFlag', type=
'ArrayI', doc=
'Filter offset parameter fit flag',
1956 size=pars[
'PARFILTEROFFSETFITFLAG'].size)
1957 parSchema.addField(
'parRetrievedLnPwvScale', type=np.float64,
1958 doc=
'Global scale for retrieved ln(pwv)')
1959 parSchema.addField(
'parRetrievedLnPwvOffset', type=np.float64,
1960 doc=
'Global offset for retrieved ln(pwv)')
1961 parSchema.addField(
'parRetrievedLnPwvNightlyOffset', type=
'ArrayD',
1962 doc=
'Nightly offset for retrieved ln(pwv)',
1963 size=pars[
'PARRETRIEVEDLNPWVNIGHTLYOFFSET'].size)
1964 parSchema.addField(
'compAbsThroughput', type=
'ArrayD',
1965 doc=
'Absolute throughput (relative to transmission curves)',
1966 size=pars[
'COMPABSTHROUGHPUT'].size)
1967 parSchema.addField(
'compRefOffset', type=
'ArrayD',
1968 doc=
'Offset between reference stars and calibrated stars',
1969 size=pars[
'COMPREFOFFSET'].size)
1970 parSchema.addField(
'compRefSigma', type=
'ArrayD',
1971 doc=
'Width of reference star/calibrated star distribution',
1972 size=pars[
'COMPREFSIGMA'].size)
1973 parSchema.addField(
'compMirrorChromaticity', type=
'ArrayD',
1974 doc=
'Computed mirror chromaticity terms',
1975 size=pars[
'COMPMIRRORCHROMATICITY'].size)
1976 parSchema.addField(
'mirrorChromaticityPivot', type=
'ArrayD',
1977 doc=
'Mirror chromaticity pivot mjd',
1978 size=pars[
'MIRRORCHROMATICITYPIVOT'].size)
1979 parSchema.addField(
'compCcdChromaticity', type=
'ArrayD',
1980 doc=
'Computed CCD chromaticity terms',
1981 size=pars[
'COMPCCDCHROMATICITY'].size)
1982 parSchema.addField(
'compMedianSedSlope', type=
'ArrayD',
1983 doc=
'Computed median SED slope (per band)',
1984 size=pars[
'COMPMEDIANSEDSLOPE'].size)
1985 parSchema.addField(
'compAperCorrPivot', type=
'ArrayD', doc=
'Aperture correction pivot',
1986 size=pars[
'COMPAPERCORRPIVOT'].size)
1987 parSchema.addField(
'compAperCorrSlope', type=
'ArrayD', doc=
'Aperture correction slope',
1988 size=pars[
'COMPAPERCORRSLOPE'].size)
1989 parSchema.addField(
'compAperCorrSlopeErr', type=
'ArrayD', doc=
'Aperture correction slope error',
1990 size=pars[
'COMPAPERCORRSLOPEERR'].size)
1991 parSchema.addField(
'compAperCorrRange', type=
'ArrayD', doc=
'Aperture correction range',
1992 size=pars[
'COMPAPERCORRRANGE'].size)
1993 parSchema.addField(
'compModelErrExptimePivot', type=
'ArrayD', doc=
'Model error exptime pivot',
1994 size=pars[
'COMPMODELERREXPTIMEPIVOT'].size)
1995 parSchema.addField(
'compModelErrFwhmPivot', type=
'ArrayD', doc=
'Model error fwhm pivot',
1996 size=pars[
'COMPMODELERRFWHMPIVOT'].size)
1997 parSchema.addField(
'compModelErrSkyPivot', type=
'ArrayD', doc=
'Model error sky pivot',
1998 size=pars[
'COMPMODELERRSKYPIVOT'].size)
1999 parSchema.addField(
'compModelErrPars', type=
'ArrayD', doc=
'Model error parameters',
2000 size=pars[
'COMPMODELERRPARS'].size)
2001 parSchema.addField(
'compExpGray', type=
'ArrayD', doc=
'Computed exposure gray',
2002 size=pars[
'COMPEXPGRAY'].size)
2003 parSchema.addField(
'compVarGray', type=
'ArrayD', doc=
'Computed exposure variance',
2004 size=pars[
'COMPVARGRAY'].size)
2005 parSchema.addField(
'compExpDeltaMagBkg', type=
'ArrayD',
2006 doc=
'Computed exposure offset due to background',
2007 size=pars[
'COMPEXPDELTAMAGBKG'].size)
2008 parSchema.addField(
'compNGoodStarPerExp', type=
'ArrayI',
2009 doc=
'Computed number of good stars per exposure',
2010 size=pars[
'COMPNGOODSTARPEREXP'].size)
2011 parSchema.addField(
'compExpRefOffset', type=
'ArrayD',
2012 doc=
'Computed per-visit median offset between standard stars and ref stars.',
2013 size=pars[
'COMPEXPREFOFFSET'].size)
2014 parSchema.addField(
'compSigFgcm', type=
'ArrayD', doc=
'Computed sigma_fgcm (intrinsic repeatability)',
2015 size=pars[
'COMPSIGFGCM'].size)
2016 parSchema.addField(
'compSigmaCal', type=
'ArrayD', doc=
'Computed sigma_cal (systematic error floor)',
2017 size=pars[
'COMPSIGMACAL'].size)
2018 parSchema.addField(
'compRetrievedLnPwv', type=
'ArrayD', doc=
'Retrieved ln(pwv) (smoothed)',
2019 size=pars[
'COMPRETRIEVEDLNPWV'].size)
2020 parSchema.addField(
'compRetrievedLnPwvRaw', type=
'ArrayD', doc=
'Retrieved ln(pwv) (raw)',
2021 size=pars[
'COMPRETRIEVEDLNPWVRAW'].size)
2022 parSchema.addField(
'compRetrievedLnPwvFlag', type=
'ArrayI', doc=
'Retrieved ln(pwv) Flag',
2023 size=pars[
'COMPRETRIEVEDLNPWVFLAG'].size)
2024 parSchema.addField(
'compRetrievedTauNight', type=
'ArrayD', doc=
'Retrieved tau (per night)',
2025 size=pars[
'COMPRETRIEVEDTAUNIGHT'].size)
2026 parSchema.addField(
'compEpsilon', type=
'ArrayD',
2027 doc=
'Computed epsilon background offset per visit (nJy/arcsec2)',
2028 size=pars[
'COMPEPSILON'].size)
2029 parSchema.addField(
'compMedDeltaAper', type=
'ArrayD',
2030 doc=
'Median delta mag aper per visit',
2031 size=pars[
'COMPMEDDELTAAPER'].size)
2032 parSchema.addField(
'compGlobalEpsilon', type=
'ArrayD',
2033 doc=
'Computed epsilon bkg offset (global) (nJy/arcsec2)',
2034 size=pars[
'COMPGLOBALEPSILON'].size)
2035 parSchema.addField(
'compEpsilonMap', type=
'ArrayD',
2036 doc=
'Computed epsilon maps (nJy/arcsec2)',
2037 size=pars[
'COMPEPSILONMAP'].size)
2038 parSchema.addField(
'compEpsilonNStarMap', type=
'ArrayI',
2039 doc=
'Number of stars per pixel in computed epsilon maps',
2040 size=pars[
'COMPEPSILONNSTARMAP'].size)
2041 parSchema.addField(
'compEpsilonCcdMap', type=
'ArrayD',
2042 doc=
'Computed epsilon ccd maps (nJy/arcsec2)',
2043 size=pars[
'COMPEPSILONCCDMAP'].size)
2044 parSchema.addField(
'compEpsilonCcdNStarMap', type=
'ArrayI',
2045 doc=
'Number of stars per ccd bin in epsilon ccd maps',
2046 size=pars[
'COMPEPSILONCCDNSTARMAP'].size)
2047 parSchema.addField(
'epochMjdStart', type=
'ArrayD',
2048 doc=
'Epoch MJD start times',
2049 size=pars[
'EPOCHMJDSTART'].size)
2050 parSchema.addField(
'epochMjdEnd', type=
'ArrayD',
2051 doc=
'EpochMJD end times',
2052 size=pars[
'EPOCHMJDEND'].size)
2054 parSchema.addField(
'superstarSize', type=
'ArrayI', doc=
'Superstar matrix size',
2056 parSchema.addField(
'superstar', type=
'ArrayD', doc=
'Superstar matrix (flattened)',
2057 size=parSuperStarFlat.size)
2061 def _makeParCatalog(self, parSchema, parInfo, pars, parSuperStarFlat,
2062 lutFilterNameString, fitBandString):
2064 Make the FGCM parameter catalog for persistence
2068 parSchema: `lsst.afw.table.Schema`
2069 Parameter catalog schema
2070 pars: `numpy.ndarray`
2071 FGCM parameters to put into parCat
2072 parSuperStarFlat: `numpy.array`
2073 FGCM superstar flat array to put into parCat
2074 lutFilterNameString: `str`
2075 Combined string of all the lutFilterNames
2076 fitBandString: `str`
2077 Combined string of all the fitBands
2081 parCat: `afwTable.BasicCatalog`
2082 Atmosphere and instrumental model parameter catalog for persistence
2090 rec = parCat.addNew()
2093 rec[
'nCcd'] = parInfo[
'NCCD'][0]
2094 rec[
'lutFilterNames'] = lutFilterNameString
2095 rec[
'fitBands'] = fitBandString
2097 rec[
'hasExternalPwv'] = 0
2098 rec[
'hasExternalTau'] = 0
2102 scalarNames = [
'parRetrievedLnPwvScale',
'parRetrievedLnPwvOffset']
2104 arrNames = [
'parAlpha',
'parO3',
'parLnTauIntercept',
'parLnTauSlope',
2105 'parLnPwvIntercept',
'parLnPwvSlope',
'parLnPwvQuadratic',
2106 'parQeSysIntercept',
'compQeSysSlope',
2107 'parRetrievedLnPwvNightlyOffset',
'compAperCorrPivot',
2108 'parFilterOffset',
'parFilterOffsetFitFlag',
2109 'compAbsThroughput',
'compRefOffset',
'compRefSigma',
2110 'compMirrorChromaticity',
'mirrorChromaticityPivot',
'compCcdChromaticity',
2111 'compAperCorrSlope',
'compAperCorrSlopeErr',
'compAperCorrRange',
2112 'compModelErrExptimePivot',
'compModelErrFwhmPivot',
2113 'compModelErrSkyPivot',
'compModelErrPars',
2114 'compExpGray',
'compVarGray',
'compNGoodStarPerExp',
'compSigFgcm',
2115 'compSigmaCal',
'compExpDeltaMagBkg',
'compMedianSedSlope',
2116 'compRetrievedLnPwv',
'compRetrievedLnPwvRaw',
'compRetrievedLnPwvFlag',
2117 'compRetrievedTauNight',
'compEpsilon',
'compMedDeltaAper',
2118 'compGlobalEpsilon',
'compEpsilonMap',
'compEpsilonNStarMap',
2119 'compEpsilonCcdMap',
'compEpsilonCcdNStarMap',
'compExpRefOffset',
2120 'epochMjdStart',
'epochMjdEnd']
2122 for scalarName
in scalarNames:
2123 rec[scalarName] = pars[scalarName.upper()][0]
2125 for arrName
in arrNames:
2126 rec[arrName][:] = np.atleast_1d(pars[0][arrName.upper()])[:]
2129 rec[
'superstarSize'][:] = parSuperStarFlat.shape
2130 rec[
'superstar'][:] = parSuperStarFlat.ravel()
2134 def _makeFlagStarSchema(self):
2136 Make the flagged-stars schema
2140 flagStarSchema: `lsst.afw.table.Schema`
2145 flagStarSchema.addField(
'objId', type=np.int32, doc=
'FGCM object id')
2146 flagStarSchema.addField(
'objFlag', type=np.int32, doc=
'FGCM object flag')
2148 return flagStarSchema
2150 def _makeFlagStarCat(self, flagStarSchema, flagStarStruct):
2152 Make the flagged star catalog for persistence
2156 flagStarSchema: `lsst.afw.table.Schema`
2158 flagStarStruct: `numpy.ndarray`
2159 Flagged star structure from fgcm
2163 flagStarCat: `lsst.afw.table.BaseCatalog`
2164 Flagged star catalog for persistence
2168 flagStarCat.resize(flagStarStruct.size)
2170 flagStarCat[
'objId'][:] = flagStarStruct[
'OBJID']
2171 flagStarCat[
'objFlag'][:] = flagStarStruct[
'OBJFLAG']
Defines the fields and offsets for a table.