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).",
299 "Plot showing scatter as a function of systematic error floor.",
303 "Histograms of scatter with respect to reference stars.",
305 (
"RefResidVsColorAll_Plot",
307 "Plot of reference star residuals vs. color (all stars).",
309 (
"RefResidVsColorCut_Plot",
311 "Plot of reference star residuals vs. color (reference star color cuts).",
316 plotConnections.extend(
318 (
"I1R1_Plot",
"Plot",
"Plot of fgcm R1 vs. I1.", filterDims),
319 (
"I1_Plot",
"Plot",
"Focal plane map of fgcm I1.", filterDims),
320 (
"R1_Plot",
"Plot",
"Focal plane map of fgcm R1.", filterDims),
321 (
"R1mI1_Plot",
"Plot",
"Focal plane map of fgcm R1 - I1.", filterDims),
322 (
"R1mI1_vs_mjd_Plot",
"Plot",
"R1 - I1 residuals vs. mjd.", filterDims),
323 (
"CompareRedblueMirrorchrom_Plot",
325 "Comparison of mirror chromaticity residuals for red/blue stars.",
327 (
"CcdChromaticity_Plot",
329 "Focal plane map of fgcm ccd chromaticity.",
331 (
"EpsilonDetector_Plot",
333 "Focal plane map of background over/undersubtraction.",
335 (
"EpsilonDetectorMatchscale_Plot",
337 "Focal plane map of background over/undersubtraction.",
342 plotConnections.extend(
345 f
"Superstar_{epoch}_Plot",
347 "Plot of illumination Correction.",
353 if config.doMultipleCycles:
357 for cycle
in range(config.multipleCyclesFinalCycleNumber):
358 outputConnections = copy.copy(inputAndOutputConnections)
359 outputConnections.extend(multicycleOutputConnections)
360 if config.outputZeropointsBeforeFinalCycle:
361 outputConnections.extend(optionalZpOutputConnections)
362 if config.outputStandardsBeforeFinalCycle:
363 outputConnections.extend(optionalStarOutputConnections)
371 if cycle == (config.multipleCyclesFinalCycleNumber - 1) \
372 or config.doPlotsBeforeFinalCycles:
373 outputConnections.extend(plotConnections)
375 for (name, storageClass, doc, dims)
in outputConnections:
376 connectionName = f
"fgcm_Cycle{cycle}_{name}"
377 storageName = connectionName
378 outConnection = connectionTypes.Output(
380 storageClass=storageClass,
383 multiple=(len(dims) > 1),
385 setattr(self, connectionName, outConnection)
388 outputConnections = copy.copy(inputAndOutputConnections)
389 outputConnections.extend(multicycleOutputConnections)
390 outputConnections.extend(optionalZpOutputConnections)
391 outputConnections.extend(optionalStarOutputConnections)
393 outputConnections.extend(plotConnections)
394 for (name, storageClass, doc, dims)
in outputConnections:
395 connectionName = f
"fgcm_Cycle{config.multipleCyclesFinalCycleNumber}_{name}"
396 storageName = connectionName
397 outConnection = connectionTypes.Output(
399 storageClass=storageClass,
402 multiple=(len(dims) > 1),
404 setattr(self, connectionName, outConnection)
407 if config.cycleNumber > 0:
408 inputConnections = copy.copy(inputAndOutputConnections)
410 inputConnections = []
411 outputConnections = copy.copy(inputAndOutputConnections)
416 if config.isFinalCycle
or config.outputZeropointsBeforeFinalCycle:
417 outputConnections.extend(optionalZpOutputConnections)
418 if config.isFinalCycle
or config.outputStandardsBeforeFinalCycle:
419 outputConnections.extend(optionalStarOutputConnections)
422 outputConnections.extend(plotConnections)
424 for (name, storageClass, doc, dims)
in inputConnections:
425 connectionName = f
"fgcm{name}Input"
426 storageName = f
"fgcm_Cycle{config.cycleNumber - 1}_{name}"
427 inConnection = connectionTypes.PrerequisiteInput(
429 storageClass=storageClass,
433 setattr(self, connectionName, inConnection)
435 for (name, storageClass, doc, dims)
in outputConnections:
436 connectionName = f
"fgcm{name}"
437 storageName = f
"fgcm_Cycle{config.cycleNumber}_{name}"
439 if storageClass ==
"Plot":
440 connectionName = storageName
441 outConnection = connectionTypes.Output(
443 storageClass=storageClass,
446 multiple=(len(dims) > 1),
448 setattr(self, connectionName, outConnection)
450 if not config.doReferenceCalibration:
451 self.inputs.remove(
"fgcmReferenceStars")
452 self.inputs.remove(
"fgcmReferenceStarsParquet")
454 if config.useParquetCatalogFormat:
455 self.inputs.remove(
"fgcmStarObservations")
456 self.inputs.remove(
"fgcmStarIds")
457 self.inputs.remove(
"fgcmStarIndices")
458 if config.doReferenceCalibration:
459 self.inputs.remove(
"fgcmReferenceStars")
461 self.inputs.remove(
"fgcmStarObservationsParquet")
462 self.inputs.remove(
"fgcmStarIdsParquet")
463 if config.doReferenceCalibration:
464 self.inputs.remove(
"fgcmReferenceStarsParquet")
467class FgcmFitCycleConfig(pipeBase.PipelineTaskConfig,
468 pipelineConnections=FgcmFitCycleConnections):
469 """Config for FgcmFitCycle"""
471 doMultipleCycles = pexConfig.Field(
472 doc=
"Run multiple fit cycles in one task",
476 useParquetCatalogFormat = pexConfig.Field(
477 doc=
"Use parquet catalog format?",
481 multipleCyclesFinalCycleNumber = pexConfig.RangeField(
482 doc=(
"Final cycle number in multiple cycle mode. The initial cycle "
483 "is 0, with limited parameters fit. The next cycle is 1 with "
484 "full parameter fit. The final cycle is a clean-up with no "
485 "parameters fit. There will be a total of "
486 "(multipleCycleFinalCycleNumber + 1) cycles run, and the final "
487 "cycle number cannot be less than 2."),
491 max=MULTIPLE_CYCLES_MAX,
494 bands = pexConfig.ListField(
495 doc=
"Bands to run calibration",
499 fitBands = pexConfig.ListField(
500 doc=(
"Bands to use in atmospheric fit. The bands not listed here will have "
501 "the atmosphere constrained from the 'fitBands' on the same night. "
502 "Must be a subset of `config.bands`"),
506 requiredBands = pexConfig.ListField(
507 doc=(
"Bands that are required for a star to be considered a calibration star. "
508 "Must be a subset of `config.bands`"),
512 physicalFilterMap = pexConfig.DictField(
513 doc=
"Mapping from 'physicalFilter' to band.",
518 doReferenceCalibration = pexConfig.Field(
519 doc=
"Use reference catalog as additional constraint on calibration",
523 refStarSnMin = pexConfig.Field(
524 doc=
"Reference star signal-to-noise minimum to use in calibration. Set to <=0 for no cut.",
528 refStarOutlierNSig = pexConfig.Field(
529 doc=(
"Number of sigma compared to average mag for reference star to be considered an outlier. "
530 "Computed per-band, and if it is an outlier in any band it is rejected from fits."),
534 applyRefStarColorCuts = pexConfig.Field(
535 doc=(
"Apply color cuts defined in ``starColorCuts`` to reference stars? "
536 "These cuts are in addition to any cuts defined in ``refStarColorCuts``"),
540 refStarMaxFracUse = pexConfig.Field(
541 doc=(
"Maximum fraction of reference stars to use in the fit. Remainder will "
542 "be used only for validation."),
546 useExposureReferenceOffset = pexConfig.Field(
547 doc=(
"Use per-exposure (visit) offsets between calibrated stars and reference stars "
548 "for final zeropoints? This may help uniformity for disjoint surveys."),
552 nCore = pexConfig.Field(
553 doc=
"Number of cores to use",
556 deprecated=
"Number of cores is deprecated as a config, and will be removed after v27. "
557 "Please use ``pipetask run --cores-per-quantum`` instead.",
559 nStarPerRun = pexConfig.Field(
560 doc=
"Number of stars to run in each chunk",
564 nExpPerRun = pexConfig.Field(
565 doc=
"Number of exposures to run in each chunk",
569 reserveFraction = pexConfig.Field(
570 doc=
"Fraction of stars to reserve for testing",
574 freezeStdAtmosphere = pexConfig.Field(
575 doc=
"Freeze atmosphere parameters to standard (for testing)",
579 precomputeSuperStarInitialCycle = pexConfig.Field(
580 doc=
"Precompute superstar flat for initial cycle",
584 superStarSubCcdDict = pexConfig.DictField(
585 doc=(
"Per-band specification on whether to compute superstar flat on sub-ccd scale. "
586 "Must have one entry per band."),
591 superStarSubCcdChebyshevOrder = pexConfig.Field(
592 doc=(
"Order of the 2D chebyshev polynomials for sub-ccd superstar fit. "
593 "Global default is first-order polynomials, and should be overridden "
594 "on a camera-by-camera basis depending on the ISR."),
598 superStarSubCcdTriangular = pexConfig.Field(
599 doc=(
"Should the sub-ccd superstar chebyshev matrix be triangular to "
600 "suppress high-order cross terms?"),
604 superStarSigmaClip = pexConfig.Field(
605 doc=
"Number of sigma to clip outliers when selecting for superstar flats",
609 superStarPlotCcdResiduals = pexConfig.Field(
610 doc=
"If plotting is enabled, should per-detector residuals be plotted? "
611 "This may produce a lot of output, and should be used only for "
612 "debugging purposes.",
616 focalPlaneSigmaClip = pexConfig.Field(
617 doc=
"Number of sigma to clip outliers per focal-plane.",
621 ccdGraySubCcdDict = pexConfig.DictField(
622 doc=(
"Per-band specification on whether to compute achromatic per-ccd residual "
623 "('ccd gray') on a sub-ccd scale."),
628 ccdGraySubCcdChebyshevOrder = pexConfig.Field(
629 doc=
"Order of the 2D chebyshev polynomials for sub-ccd gray fit.",
633 ccdGraySubCcdTriangular = pexConfig.Field(
634 doc=(
"Should the sub-ccd gray chebyshev matrix be triangular to "
635 "suppress high-order cross terms?"),
639 ccdGrayFocalPlaneDict = pexConfig.DictField(
640 doc=(
"Per-band specification on whether to compute focal-plane residual "
641 "('ccd gray') corrections."),
646 ccdGrayFocalPlaneFitMinCcd = pexConfig.Field(
647 doc=(
"Minimum number of 'good' CCDs required to perform focal-plane "
648 "gray corrections. If there are fewer good CCDs then the gray "
649 "correction is computed per-ccd."),
653 ccdGrayFocalPlaneChebyshevOrder = pexConfig.Field(
654 doc=
"Order of the 2D chebyshev polynomials for focal plane fit.",
658 cycleNumber = pexConfig.Field(
659 doc=(
"FGCM fit cycle number. This is automatically incremented after each run "
660 "and stage of outlier rejection. See cookbook for details."),
664 isFinalCycle = pexConfig.Field(
665 doc=(
"Is this the final cycle of the fitting? Will automatically compute final "
666 "selection of stars and photometric exposures, and will output zeropoints "
667 "and standard stars for use in fgcmOutputProducts"),
671 maxIterBeforeFinalCycle = pexConfig.Field(
672 doc=(
"Maximum fit iterations, prior to final cycle. The number of iterations "
673 "will always be 0 in the final cycle for cleanup and final selection."),
677 deltaMagBkgOffsetPercentile = pexConfig.Field(
678 doc=(
"Percentile brightest stars on a visit/ccd to use to compute net "
679 "offset from local background subtraction."),
683 deltaMagBkgPerCcd = pexConfig.Field(
684 doc=(
"Compute net offset from local background subtraction per-ccd? "
685 "Otherwise, use computation per visit."),
689 utBoundary = pexConfig.Field(
690 doc=
"Boundary (in UTC) from day-to-day",
694 washMjds = pexConfig.ListField(
695 doc=
"Mirror wash MJDs",
699 epochMjds = pexConfig.ListField(
700 doc=
"Epoch boundaries in MJD",
704 minObsPerBand = pexConfig.Field(
705 doc=
"Minimum good observations per band",
711 latitude = pexConfig.Field(
712 doc=
"Observatory latitude",
716 mirrorArea = pexConfig.Field(
717 doc=
"Mirror area (square meters) of telescope. If not set, will "
718 "try to estimate from camera.telescopeDiameter.",
723 cameraGain = pexConfig.Field(
724 doc=
"Average camera gain. If not set, will use the median of the "
725 "camera model/detector/amplifier gains.",
730 defaultCameraOrientation = pexConfig.Field(
731 doc=
"Default camera orientation for QA plots.",
735 brightObsGrayMax = pexConfig.Field(
736 doc=
"Maximum gray extinction to be considered bright observation",
740 minStarPerCcd = pexConfig.Field(
741 doc=(
"Minimum number of good stars per CCD to be used in calibration fit. "
742 "CCDs with fewer stars will have their calibration estimated from other "
743 "CCDs in the same visit, with zeropoint error increased accordingly."),
747 minCcdPerExp = pexConfig.Field(
748 doc=(
"Minimum number of good CCDs per exposure/visit to be used in calibration fit. "
749 "Visits with fewer good CCDs will have CCD zeropoints estimated where possible."),
753 maxCcdGrayErr = pexConfig.Field(
754 doc=
"Maximum error on CCD gray offset to be considered photometric",
758 minStarPerExp = pexConfig.Field(
759 doc=(
"Minimum number of good stars per exposure/visit to be used in calibration fit. "
760 "Visits with fewer good stars will have CCD zeropoints estimated where possible."),
764 minExpPerNight = pexConfig.Field(
765 doc=
"Minimum number of good exposures/visits to consider a partly photometric night",
769 expGrayInitialCut = pexConfig.Field(
770 doc=(
"Maximum exposure/visit gray value for initial selection of possible photometric "
775 expFwhmCutDict = pexConfig.DictField(
776 doc=(
"Per-band specification on maximum exposure FWHM (arcseconds) that will "
777 "be considered for the model fit. Exposures with median FWHM larger "
778 "than this threshold will get zeropoints based on matching to good "
784 expGrayPhotometricCutDict = pexConfig.DictField(
785 doc=(
"Per-band specification on maximum (negative) achromatic exposure residual "
786 "('gray term') for a visit to be considered photometric. Must have one "
787 "entry per band. Broad-band filters should be -0.05."),
792 expGrayHighCutDict = pexConfig.DictField(
793 doc=(
"Per-band specification on maximum (positive) achromatic exposure residual "
794 "('gray term') for a visit to be considered photometric. Must have one "
795 "entry per band. Broad-band filters should be 0.2."),
800 expGrayRecoverCut = pexConfig.Field(
801 doc=(
"Maximum (negative) exposure gray to be able to recover bad ccds via interpolation. "
802 "Visits with more gray extinction will only get CCD zeropoints if there are "
803 "sufficient star observations (minStarPerCcd) on that CCD."),
807 expVarGrayPhotometricCutDict = pexConfig.DictField(
808 doc=(
"Per-band specification on maximum exposure variance to be considered possibly "
809 "photometric. Must have one entry per band. Broad-band filters should be "
815 expGrayErrRecoverCut = pexConfig.Field(
816 doc=(
"Maximum exposure gray error to be able to recover bad ccds via interpolation. "
817 "Visits with more gray variance will only get CCD zeropoints if there are "
818 "sufficient star observations (minStarPerCcd) on that CCD."),
822 aperCorrFitNBins = pexConfig.Field(
823 doc=(
"Number of aperture bins used in aperture correction fit. When set to 0"
824 "no fit will be performed, and the config.aperCorrInputSlopes will be "
825 "used if available."),
829 aperCorrInputSlopeDict = pexConfig.DictField(
830 doc=(
"Per-band specification of aperture correction input slope parameters. These "
831 "are used on the first fit iteration, and aperture correction parameters will "
832 "be updated from the data if config.aperCorrFitNBins > 0. It is recommended "
833 "to set this when there is insufficient data to fit the parameters (e.g. "
839 sedboundaryterms = pexConfig.ConfigField(
840 doc=
"Mapping from bands to SED boundary term names used is sedterms.",
841 dtype=SedboundarytermDict,
843 sedterms = pexConfig.ConfigField(
844 doc=
"Mapping from terms to bands for fgcm linear SED approximations.",
847 sigFgcmMaxErr = pexConfig.Field(
848 doc=
"Maximum mag error for fitting sigma_FGCM",
852 sigFgcmMaxEGrayDict = pexConfig.DictField(
853 doc=(
"Per-band specification for maximum (absolute) achromatic residual (gray value) "
854 "for observations in sigma_fgcm (raw repeatability). Broad-band filters "
860 ccdGrayMaxStarErr = pexConfig.Field(
861 doc=(
"Maximum error on a star observation to use in ccd gray (achromatic residual) "
866 approxThroughputDict = pexConfig.DictField(
867 doc=(
"Per-band specification of the approximate overall throughput at the start of "
868 "calibration observations. Must have one entry per band. Typically should "
874 sigmaCalRange = pexConfig.ListField(
875 doc=
"Allowed range for systematic error floor estimation",
877 default=(0.001, 0.003),
879 sigmaCalFitPercentile = pexConfig.ListField(
880 doc=
"Magnitude percentile range to fit systematic error floor",
882 default=(0.05, 0.15),
884 sigmaCalPlotPercentile = pexConfig.ListField(
885 doc=
"Magnitude percentile range to plot systematic error floor",
887 default=(0.05, 0.95),
889 sigma0Phot = pexConfig.Field(
890 doc=
"Systematic error floor for all zeropoints",
894 mapLongitudeRef = pexConfig.Field(
895 doc=
"Reference longitude for plotting maps",
899 mapNSide = pexConfig.Field(
900 doc=
"Healpix nside for plotting maps",
904 outfileBase = pexConfig.Field(
905 doc=
"Filename start for plot output files",
909 starColorCuts = pexConfig.ListField(
910 doc=(
"Encoded star-color cuts (using calibration star colors). "
911 "This is a list with each entry a string of the format "
912 "``band1,band2,low,high`` such that only stars of color "
913 "low < band1 - band2 < high will be used for calibration."),
915 default=(
"NO_DATA",),
917 refStarColorCuts = pexConfig.ListField(
918 doc=(
"Encoded star color cuts specifically to apply to reference stars. "
919 "This is a list with each entry a string of the format "
920 "``band1,band2,low,high`` such that only stars of color "
921 "low < band1 - band2 < high will be used as reference stars."),
923 default=(
"NO_DATA",),
925 colorSplitBands = pexConfig.ListField(
926 doc=
"Band names to use to split stars by color. Must have 2 entries.",
931 modelMagErrors = pexConfig.Field(
932 doc=
"Should FGCM model the magnitude errors from sky/fwhm? (False means trust inputs)",
936 useQuadraticPwv = pexConfig.Field(
937 doc=
"Model PWV with a quadratic term for variation through the night?",
941 instrumentParsPerBand = pexConfig.Field(
942 doc=(
"Model instrumental parameters per band? "
943 "Otherwise, instrumental parameters (QE changes with time) are "
944 "shared among all bands."),
948 instrumentSlopeMinDeltaT = pexConfig.Field(
949 doc=(
"Minimum time change (in days) between observations to use in constraining "
950 "instrument slope."),
954 fitMirrorChromaticity = pexConfig.Field(
955 doc=
"Fit (intraband) mirror chromatic term?",
959 fitCcdChromaticityDict = pexConfig.DictField(
960 doc=
"Specification on whether to compute first-order quantum efficiency (QE) "
961 "adjustments. Key is band, and value will be True or False. Any band "
962 "not explicitly specified will default to False.",
967 coatingMjds = pexConfig.ListField(
968 doc=
"Mirror coating dates in MJD",
972 outputStandardsBeforeFinalCycle = pexConfig.Field(
973 doc=
"Output standard stars prior to final cycle? Used in debugging.",
977 outputZeropointsBeforeFinalCycle = pexConfig.Field(
978 doc=
"Output standard stars prior to final cycle? Used in debugging.",
982 useRepeatabilityForExpGrayCutsDict = pexConfig.DictField(
983 doc=(
"Per-band specification on whether to use star repeatability (instead of exposures) "
984 "for computing photometric cuts. Recommended for tract mode or bands with few visits."),
989 autoPhotometricCutNSig = pexConfig.Field(
990 doc=(
"Number of sigma for automatic computation of (low) photometric cut. "
991 "Cut is based on exposure gray width (per band), unless "
992 "useRepeatabilityForExpGrayCuts is set, in which case the star "
993 "repeatability is used (also per band)."),
997 autoHighCutNSig = pexConfig.Field(
998 doc=(
"Number of sigma for automatic computation of (high) outlier cut. "
999 "Cut is based on exposure gray width (per band), unless "
1000 "useRepeatabilityForExpGrayCuts is set, in which case the star "
1001 "repeatability is used (also per band)."),
1005 quietMode = pexConfig.Field(
1006 doc=
"Be less verbose with logging.",
1010 doPlots = pexConfig.Field(
1011 doc=
"Make fgcm QA plots.",
1015 doPlotsBeforeFinalCycles = pexConfig.Field(
1016 doc=
"Make fgcm QA plots before the final two fit cycles? This only applies in"
1017 "multi-cycle mode, and if doPlots is True. These are typically the most"
1018 "important QA plots to inspect.",
1022 randomSeed = pexConfig.Field(
1023 doc=
"Random seed for fgcm for consistency in tests.",
1028 deltaAperFitMinNgoodObs = pexConfig.Field(
1029 doc=
"Minimum number of good observations to use mean delta-aper values in fits.",
1033 deltaAperFitPerCcdNx = pexConfig.Field(
1034 doc=(
"Number of x bins per ccd when computing delta-aper background offsets. "
1035 "Only used when ``doComputeDeltaAperPerCcd`` is True."),
1039 deltaAperFitPerCcdNy = pexConfig.Field(
1040 doc=(
"Number of y bins per ccd when computing delta-aper background offsets. "
1041 "Only used when ``doComputeDeltaAperPerCcd`` is True."),
1045 deltaAperFitSpatialNside = pexConfig.Field(
1046 doc=
"Healpix nside to compute spatial delta-aper background offset maps.",
1050 deltaAperInnerRadiusArcsec = pexConfig.Field(
1051 doc=(
"Inner radius used to compute deltaMagAper (arcseconds). "
1052 "Must be positive and less than ``deltaAperOuterRadiusArcsec`` if "
1053 "any of ``doComputeDeltaAperPerVisit``, ``doComputeDeltaAperPerStar``, "
1054 "``doComputeDeltaAperMap``, ``doComputeDeltaAperPerCcd`` are set."),
1058 deltaAperOuterRadiusArcsec = pexConfig.Field(
1059 doc=(
"Outer radius used to compute deltaMagAper (arcseconds). "
1060 "Must be positive and greater than ``deltaAperInnerRadiusArcsec`` if "
1061 "any of ``doComputeDeltaAperPerVisit``, ``doComputeDeltaAperPerStar``, "
1062 "``doComputeDeltaAperMap``, ``doComputeDeltaAperPerCcd`` are set."),
1066 doComputeDeltaAperPerVisit = pexConfig.Field(
1067 doc=(
"Do the computation of delta-aper background offsets per visit? "
1068 "Note: this option can be very slow when there are many visits."),
1072 doComputeDeltaAperPerStar = pexConfig.Field(
1073 doc=
"Do the computation of delta-aper mean values per star?",
1077 doComputeDeltaAperMap = pexConfig.Field(
1078 doc=(
"Do the computation of delta-aper spatial maps? "
1079 "This is only used if ``doComputeDeltaAperPerStar`` is True,"),
1083 doComputeDeltaAperPerCcd = pexConfig.Field(
1084 doc=
"Do the computation of per-ccd delta-aper background offsets?",
1092 if self.connections.previousCycleNumber != str(self.cycleNumber - 1):
1093 msg =
"cycleNumber in template must be connections.previousCycleNumber + 1"
1094 raise RuntimeError(msg)
1095 if self.connections.cycleNumber != str(self.cycleNumber):
1096 msg =
"cycleNumber in template must be equal to connections.cycleNumber"
1097 raise RuntimeError(msg)
1099 for band
in self.fitBands:
1100 if band
not in self.bands:
1101 msg =
'fitBand %s not in bands' % (band)
1102 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.fitBands, self, msg)
1103 for band
in self.requiredBands:
1104 if band
not in self.bands:
1105 msg =
'requiredBand %s not in bands' % (band)
1106 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.requiredBands, self, msg)
1107 for band
in self.colorSplitBands:
1108 if band
not in self.bands:
1109 msg =
'colorSplitBand %s not in bands' % (band)
1110 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.colorSplitBands, self, msg)
1111 for band
in self.bands:
1112 if band
not in self.superStarSubCcdDict:
1113 msg =
'band %s not in superStarSubCcdDict' % (band)
1114 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.superStarSubCcdDict,
1116 if band
not in self.ccdGraySubCcdDict:
1117 msg =
'band %s not in ccdGraySubCcdDict' % (band)
1118 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.ccdGraySubCcdDict,
1120 if band
not in self.expGrayPhotometricCutDict:
1121 msg =
'band %s not in expGrayPhotometricCutDict' % (band)
1122 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.expGrayPhotometricCutDict,
1124 if band
not in self.expGrayHighCutDict:
1125 msg =
'band %s not in expGrayHighCutDict' % (band)
1126 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.expGrayHighCutDict,
1128 if band
not in self.expVarGrayPhotometricCutDict:
1129 msg =
'band %s not in expVarGrayPhotometricCutDict' % (band)
1130 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.expVarGrayPhotometricCutDict,
1132 if band
not in self.sigFgcmMaxEGrayDict:
1133 msg =
'band %s not in sigFgcmMaxEGrayDict' % (band)
1134 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.sigFgcmMaxEGrayDict,
1136 if band
not in self.approxThroughputDict:
1137 msg =
'band %s not in approxThroughputDict' % (band)
1138 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.approxThroughputDict,
1140 if band
not in self.useRepeatabilityForExpGrayCutsDict:
1141 msg =
'band %s not in useRepeatabilityForExpGrayCutsDict' % (band)
1142 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.useRepeatabilityForExpGrayCutsDict,
1145 if self.doComputeDeltaAperPerVisit
or self.doComputeDeltaAperMap \
1146 or self.doComputeDeltaAperPerCcd:
1147 if self.deltaAperInnerRadiusArcsec <= 0.0:
1148 msg =
'deltaAperInnerRadiusArcsec must be positive if deltaAper computations are turned on.'
1149 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.deltaAperInnerRadiusArcsec,
1151 if self.deltaAperOuterRadiusArcsec <= 0.0:
1152 msg =
'deltaAperOuterRadiusArcsec must be positive if deltaAper computations are turned on.'
1153 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.deltaAperOuterRadiusArcsec,
1155 if self.deltaAperOuterRadiusArcsec <= self.deltaAperInnerRadiusArcsec:
1156 msg = (
'deltaAperOuterRadiusArcsec must be greater than deltaAperInnerRadiusArcsec if '
1157 'deltaAper computations are turned on.')
1158 raise pexConfig.FieldValidationError(FgcmFitCycleConfig.deltaAperOuterRadiusArcsec,
1162class FgcmFitCycleTask(pipeBase.PipelineTask):
1164 Run Single fit cycle for FGCM global calibration
1167 ConfigClass = FgcmFitCycleConfig
1168 _DefaultName =
"fgcmFitCycle"
1170 def __init__(self, initInputs=None, **kwargs):
1171 super().__init__(**kwargs)
1173 def runQuantum(self, butlerQC, inputRefs, outputRefs):
1174 camera = butlerQC.get(inputRefs.camera)
1176 nCore = butlerQC.resources.num_cores
1180 handleDict[
'fgcmLookUpTable'] = butlerQC.get(inputRefs.fgcmLookUpTable)
1181 handleDict[
'fgcmVisitCatalog'] = butlerQC.get(inputRefs.fgcmVisitCatalog)
1183 if self.config.useParquetCatalogFormat:
1184 handleDict[
'fgcmStarObservations'] = butlerQC.get(inputRefs.fgcmStarObservationsParquet)
1185 handleDict[
'fgcmStarIds'] = butlerQC.get(inputRefs.fgcmStarIdsParquet)
1186 if self.config.doReferenceCalibration:
1187 handleDict[
'fgcmReferenceStars'] = butlerQC.get(inputRefs.fgcmReferenceStarsParquet)
1189 handleDict[
'fgcmStarObservations'] = butlerQC.get(inputRefs.fgcmStarObservations)
1190 handleDict[
'fgcmStarIds'] = butlerQC.get(inputRefs.fgcmStarIds)
1191 handleDict[
'fgcmStarIndices'] = butlerQC.get(inputRefs.fgcmStarIndices)
1192 if self.config.doReferenceCalibration:
1193 handleDict[
'fgcmReferenceStars'] = butlerQC.get(inputRefs.fgcmReferenceStars)
1194 if self.config.cycleNumber > 0:
1195 handleDict[
'fgcmFlaggedStars'] = butlerQC.get(inputRefs.fgcmFlaggedStarsInput)
1196 handleDict[
'fgcmFitParameters'] = butlerQC.get(inputRefs.fgcmFitParametersInput)
1198 fgcmDatasetDict =
None
1199 if self.config.doMultipleCycles:
1201 config = copy.copy(self.config)
1202 config.update(cycleNumber=0)
1203 for cycle
in range(self.config.multipleCyclesFinalCycleNumber + 1):
1204 if cycle == self.config.multipleCyclesFinalCycleNumber:
1205 config.update(isFinalCycle=
True)
1208 handleDict[
'fgcmFlaggedStars'] = fgcmDatasetDict[
'fgcmFlaggedStars']
1209 handleDict[
'fgcmFitParameters'] = fgcmDatasetDict[
'fgcmFitParameters']
1214 for outputRefName
in outputRefs.keys():
1215 if outputRefName.endswith(
"Plot")
and f
"Cycle{cycle}" in outputRefName:
1216 ref = getattr(outputRefs, outputRefName)
1217 if isinstance(ref, (tuple, list)):
1218 if "physical_filter" in ref[0].dimensions:
1219 for filterRef
in ref:
1220 handleDictKey = f
"{outputRefName}_{filterRef.dataId['physical_filter']}"
1221 plotHandleDict[handleDictKey] = filterRef
1222 if "band" in ref[0].dimensions:
1224 handleDictKey = f
"{outputRefName}_{bandRef.dataId['band']}"
1225 plotHandleDict[handleDictKey] = bandRef
1227 plotHandleDict[outputRefName] = ref
1229 fgcmDatasetDict, config = self._fgcmFitCycle(
1233 plotHandleDict=plotHandleDict,
1237 butlerQC.put(fgcmDatasetDict[
'fgcmFitParameters'],
1238 getattr(outputRefs, f
'fgcm_Cycle{cycle}_FitParameters'))
1239 butlerQC.put(fgcmDatasetDict[
'fgcmFlaggedStars'],
1240 getattr(outputRefs, f
'fgcm_Cycle{cycle}_FlaggedStars'))
1241 butlerQC.put(config,
1242 getattr(outputRefs, f
'fgcm_Cycle{cycle}_OutputConfig'))
1243 if self.outputZeropoints:
1244 butlerQC.put(fgcmDatasetDict[
'fgcmZeropoints'],
1245 getattr(outputRefs, f
'fgcm_Cycle{cycle}_Zeropoints'))
1246 butlerQC.put(fgcmDatasetDict[
'fgcmAtmosphereParameters'],
1247 getattr(outputRefs, f
'fgcm_Cycle{cycle}_AtmosphereParameters'))
1248 if self.outputStandards:
1249 butlerQC.put(fgcmDatasetDict[
'fgcmStandardStars'],
1250 getattr(outputRefs, f
'fgcm_Cycle{cycle}_StandardStars'))
1257 for outputRefName
in outputRefs.keys():
1258 if outputRefName.endswith(
"Plot")
and f
"Cycle{self.config.cycleNumber}" in outputRefName:
1259 ref = getattr(outputRefs, outputRefName)
1260 if isinstance(ref, (tuple, list)):
1261 if "physical_filter" in ref[0].dimensions:
1262 for filterRef
in ref:
1263 handleDictKey = f
"{outputRefName}_{filterRef.dataId['physical_filter']}"
1264 plotHandleDict[handleDictKey] = filterRef
1265 if "band" in ref[0].dimensions:
1267 handleDictKey = f
"{outputRefName}_{bandRef.dataId['band']}"
1268 plotHandleDict[handleDictKey] = bandRef
1270 plotHandleDict[outputRefName] = ref
1272 fgcmDatasetDict, _ = self._fgcmFitCycle(
1277 plotHandleDict=plotHandleDict,
1281 butlerQC.put(fgcmDatasetDict[
'fgcmFitParameters'], outputRefs.fgcmFitParameters)
1282 butlerQC.put(fgcmDatasetDict[
'fgcmFlaggedStars'], outputRefs.fgcmFlaggedStars)
1283 if self.outputZeropoints:
1284 butlerQC.put(fgcmDatasetDict[
'fgcmZeropoints'], outputRefs.fgcmZeropoints)
1285 butlerQC.put(fgcmDatasetDict[
'fgcmAtmosphereParameters'], outputRefs.fgcmAtmosphereParameters)
1286 if self.outputStandards:
1287 butlerQC.put(fgcmDatasetDict[
'fgcmStandardStars'], outputRefs.fgcmStandardStars)
1294 plotHandleDict=None,
1304 camera : `lsst.afw.cameraGeom.Camera`
1306 All handles are `lsst.daf.butler.DeferredDatasetHandle`
1307 handle dictionary with keys:
1309 ``"fgcmLookUpTable"``
1310 handle for the FGCM look-up table.
1311 ``"fgcmVisitCatalog"``
1312 handle for visit summary catalog.
1313 ``"fgcmStarObservations"``
1314 handle for star observation catalog.
1316 handle for star id catalog.
1317 ``"fgcmStarIndices"``
1318 handle for star index catalog.
1319 ``"fgcmReferenceStars"``
1320 handle for matched reference star catalog.
1321 ``"fgcmFlaggedStars"``
1322 handle for flagged star catalog.
1323 ``"fgcmFitParameters"``
1324 handle for fit parameter catalog.
1325 butlerQC : `lsst.pipe.base.QuantumContext`, optional
1326 Quantum context used for serializing plots.
1327 plotHandleDict : `dict` [`str`, `lsst.daf.butler.DatasetRef`], optional
1328 Dictionary of plot dataset refs, keyed by plot name.
1329 config : `lsst.pex.config.Config`, optional
1330 Configuration to use to override self.config.
1331 nCore : `int`, optional
1332 Number of cores to use during fitting.
1333 multiCycle : `bool`, optional
1334 Is this part of a multicycle run?
1338 fgcmDatasetDict : `dict`
1339 Dictionary of datasets to persist.
1341 if config
is not None:
1344 _config = self.config
1347 self.maxIter = _config.maxIterBeforeFinalCycle
1348 self.outputStandards = _config.outputStandardsBeforeFinalCycle
1349 self.outputZeropoints = _config.outputZeropointsBeforeFinalCycle
1350 self.resetFitParameters =
True
1352 if _config.isFinalCycle:
1357 self.outputStandards =
True
1358 self.outputZeropoints =
True
1359 self.resetFitParameters =
False
1361 lutCat = handleDict[
'fgcmLookUpTable'].get()
1362 fgcmLut, lutIndexVals, lutStd = translateFgcmLut(lutCat,
1363 dict(_config.physicalFilterMap))
1367 doPlots = _config.doPlots
1368 if doPlots
and multiCycle:
1369 if _config.cycleNumber < (_config.multipleCyclesFinalCycleNumber - 1) \
1370 and not _config.doPlotsBeforeFinalCycles:
1373 configDict = makeConfigDict(_config, self.log, camera,
1374 self.maxIter, self.resetFitParameters,
1375 self.outputZeropoints,
1376 lutIndexVals[0][
'FILTERNAMES'],
1381 visitCat = handleDict[
'fgcmVisitCatalog'].get()
1382 fgcmExpInfo = translateVisitCatalog(visitCat)
1386 self.config.defaultCameraOrientation)
1388 noFitsDict = {
'lutIndex': lutIndexVals,
1390 'expInfo': fgcmExpInfo,
1391 'focalPlaneProjector': focalPlaneProjector}
1394 fgcmFitCycle = fgcm.FgcmFitCycle(
1397 noFitsDict=noFitsDict,
1400 plotHandleDict=plotHandleDict,
1404 if (fgcmFitCycle.initialCycle):
1406 fgcmPars = fgcm.FgcmParameters.newParsWithArrays(fgcmFitCycle.fgcmConfig,
1410 plotHandleDict=plotHandleDict)
1413 parCat = handleDict[
'fgcmFitParameters']
1415 parCat = handleDict[
'fgcmFitParameters'].get()
1416 inParInfo, inParams, inSuperStar = self._loadParameters(parCat)
1418 fgcmPars = fgcm.FgcmParameters.loadParsWithArrays(fgcmFitCycle.fgcmConfig,
1424 plotHandleDict=plotHandleDict)
1427 fgcmStars = fgcm.FgcmStars(fgcmFitCycle.fgcmConfig, butlerQC=butlerQC, plotHandleDict=plotHandleDict)
1429 starObs = handleDict[
'fgcmStarObservations'].get()
1430 starIds = handleDict[
'fgcmStarIds'].get()
1431 if not self.config.useParquetCatalogFormat:
1432 starIndices = handleDict[
'fgcmStarIndices'].get()
1437 if 'fgcmFlaggedStars' in handleDict:
1439 flaggedStars = handleDict[
'fgcmFlaggedStars']
1441 flaggedStars = handleDict[
'fgcmFlaggedStars'].get()
1442 flagId = flaggedStars[
'objId'][:]
1443 flagFlag = flaggedStars[
'objFlag'][:]
1446 elif self.config.useParquetCatalogFormat:
1452 (flagged,) = (starIds[
'obj_flag'] > 0).nonzero()
1453 flagId = starIds[
'fgcm_id'][flagged]
1454 flagFlag = starIds[
'obj_flag'][flagged]
1459 if _config.doReferenceCalibration:
1460 refStars = handleDict[
'fgcmReferenceStars'].get()
1462 refMag, refMagErr = extractReferenceMags(refStars,
1464 _config.physicalFilterMap)
1466 refId = refStars[
'fgcm_id'][:]
1476 if self.config.useParquetCatalogFormat:
1477 visitIndex = np.searchsorted(fgcmExpInfo[
'VISIT'], starObs[
'visit'])
1479 visitIndex = np.searchsorted(fgcmExpInfo[
'VISIT'], starObs[
'visit'][starIndices[
'obsIndex']])
1488 if self.config.useParquetCatalogFormat:
1491 fgcmStars.loadStars(fgcmPars,
1492 starObs[
'visit'][:],
1493 starObs[
'detector'][:],
1496 starObs[
'inst_mag'][:],
1497 starObs[
'inst_mag_err'][:],
1498 fgcmExpInfo[
'FILTERNAME'][visitIndex],
1499 starIds[
'fgcm_id'][:],
1502 starIds[
'obs_arr_index'][:],
1503 starIds[
'n_obs'][:],
1504 obsX=starObs[
'x'][:],
1505 obsY=starObs[
'y'][:],
1506 obsDeltaMagBkg=starObs[
'delta_mag_bkg'][:],
1507 obsDeltaAper=starObs[
'delta_mag_aper'][:],
1510 refMagErr=refMagErr,
1518 conv = starObs[0][
'ra'].asDegrees() / float(starObs[0][
'ra'])
1520 fgcmStars.loadStars(fgcmPars,
1521 starObs[
'visit'][starIndices[
'obsIndex']],
1522 starObs[
'ccd'][starIndices[
'obsIndex']],
1523 starObs[
'ra'][starIndices[
'obsIndex']] * conv,
1524 starObs[
'dec'][starIndices[
'obsIndex']] * conv,
1525 starObs[
'instMag'][starIndices[
'obsIndex']],
1526 starObs[
'instMagErr'][starIndices[
'obsIndex']],
1527 fgcmExpInfo[
'FILTERNAME'][visitIndex],
1528 starIds[
'fgcm_id'][:],
1531 starIds[
'obsArrIndex'][:],
1533 obsX=starObs[
'x'][starIndices[
'obsIndex']],
1534 obsY=starObs[
'y'][starIndices[
'obsIndex']],
1535 obsDeltaMagBkg=starObs[
'deltaMagBkg'][starIndices[
'obsIndex']],
1536 obsDeltaAper=starObs[
'deltaMagAper'][starIndices[
'obsIndex']],
1537 psfCandidate=starObs[
'psf_candidate'][starIndices[
'obsIndex']],
1540 refMagErr=refMagErr,
1557 fgcmFitCycle.setLUT(fgcmLut)
1558 fgcmFitCycle.setStars(fgcmStars, fgcmPars)
1559 fgcmFitCycle.setPars(fgcmPars)
1562 fgcmFitCycle.finishSetup()
1571 fgcmDatasetDict = self._makeFgcmOutputDatasets(fgcmFitCycle)
1576 updatedPhotometricCutDict = {b: float(fgcmFitCycle.updatedPhotometricCut[i])
for
1577 i, b
in enumerate(_config.bands)}
1578 updatedHighCutDict = {band: float(fgcmFitCycle.updatedHighCut[i])
for
1579 i, band
in enumerate(_config.bands)}
1581 outConfig = copy.copy(_config)
1582 outConfig.update(cycleNumber=(_config.cycleNumber + 1),
1583 precomputeSuperStarInitialCycle=
False,
1584 freezeStdAtmosphere=
False,
1585 expGrayPhotometricCutDict=updatedPhotometricCutDict,
1586 expGrayHighCutDict=updatedHighCutDict)
1588 outConfig.connections.update(previousCycleNumber=str(_config.cycleNumber),
1589 cycleNumber=str(_config.cycleNumber + 1))
1592 configFileName =
'%s_cycle%02d_config.py' % (outConfig.outfileBase,
1593 outConfig.cycleNumber)
1594 outConfig.save(configFileName)
1596 if _config.isFinalCycle == 1:
1598 self.log.info(
"Everything is in place to run fgcmOutputProducts.py")
1600 self.log.info(
"Saved config for next cycle to %s" % (configFileName))
1601 self.log.info(
"Be sure to look at:")
1602 self.log.info(
" config.expGrayPhotometricCut")
1603 self.log.info(
" config.expGrayHighCut")
1604 self.log.info(
"If you are satisfied with the fit, please set:")
1605 self.log.info(
" config.isFinalCycle = True")
1607 fgcmFitCycle.freeSharedMemory()
1609 return fgcmDatasetDict, outConfig
1611 def _loadParameters(self, parCat):
1613 Load FGCM parameters from a previous fit cycle
1617 parCat : `lsst.afw.table.BaseCatalog`
1618 Parameter catalog in afw table form.
1622 inParInfo: `numpy.ndarray`
1623 Numpy array parameter information formatted for input to fgcm
1624 inParameters: `numpy.ndarray`
1625 Numpy array parameter values formatted for input to fgcm
1626 inSuperStar: `numpy.array`
1627 Superstar flat formatted for input to fgcm
1629 parLutFilterNames = np.array(parCat[0][
'lutFilterNames'].split(
','))
1630 parFitBands = np.array(parCat[0][
'fitBands'].split(
','))
1632 inParInfo = np.zeros(1, dtype=[(
'NCCD',
'i4'),
1633 (
'LUTFILTERNAMES', parLutFilterNames.dtype.str,
1634 (parLutFilterNames.size, )),
1635 (
'FITBANDS', parFitBands.dtype.str, (parFitBands.size, )),
1636 (
'LNTAUUNIT',
'f8'),
1637 (
'LNTAUSLOPEUNIT',
'f8'),
1638 (
'ALPHAUNIT',
'f8'),
1639 (
'LNPWVUNIT',
'f8'),
1640 (
'LNPWVSLOPEUNIT',
'f8'),
1641 (
'LNPWVQUADRATICUNIT',
'f8'),
1642 (
'LNPWVGLOBALUNIT',
'f8'),
1644 (
'QESYSUNIT',
'f8'),
1645 (
'FILTEROFFSETUNIT',
'f8'),
1646 (
'HASEXTERNALPWV',
'i2'),
1647 (
'HASEXTERNALTAU',
'i2')])
1648 inParInfo[
'NCCD'] = parCat[
'nCcd']
1649 inParInfo[
'LUTFILTERNAMES'][:] = parLutFilterNames
1650 inParInfo[
'FITBANDS'][:] = parFitBands
1651 inParInfo[
'HASEXTERNALPWV'] = parCat[
'hasExternalPwv']
1652 inParInfo[
'HASEXTERNALTAU'] = parCat[
'hasExternalTau']
1654 inParams = np.zeros(1, dtype=[(
'PARALPHA',
'f8', (parCat[
'parAlpha'].size, )),
1655 (
'PARO3',
'f8', (parCat[
'parO3'].size, )),
1656 (
'PARLNTAUINTERCEPT',
'f8',
1657 (parCat[
'parLnTauIntercept'].size, )),
1658 (
'PARLNTAUSLOPE',
'f8',
1659 (parCat[
'parLnTauSlope'].size, )),
1660 (
'PARLNPWVINTERCEPT',
'f8',
1661 (parCat[
'parLnPwvIntercept'].size, )),
1662 (
'PARLNPWVSLOPE',
'f8',
1663 (parCat[
'parLnPwvSlope'].size, )),
1664 (
'PARLNPWVQUADRATIC',
'f8',
1665 (parCat[
'parLnPwvQuadratic'].size, )),
1666 (
'PARQESYSINTERCEPT',
'f8',
1667 (parCat[
'parQeSysIntercept'].size, )),
1668 (
'COMPQESYSSLOPE',
'f8',
1669 (parCat[
'compQeSysSlope'].size, )),
1670 (
'PARFILTEROFFSET',
'f8',
1671 (parCat[
'parFilterOffset'].size, )),
1672 (
'PARFILTEROFFSETFITFLAG',
'i2',
1673 (parCat[
'parFilterOffsetFitFlag'].size, )),
1674 (
'PARRETRIEVEDLNPWVSCALE',
'f8'),
1675 (
'PARRETRIEVEDLNPWVOFFSET',
'f8'),
1676 (
'PARRETRIEVEDLNPWVNIGHTLYOFFSET',
'f8',
1677 (parCat[
'parRetrievedLnPwvNightlyOffset'].size, )),
1678 (
'COMPABSTHROUGHPUT',
'f8',
1679 (parCat[
'compAbsThroughput'].size, )),
1680 (
'COMPREFOFFSET',
'f8',
1681 (parCat[
'compRefOffset'].size, )),
1682 (
'COMPREFSIGMA',
'f8',
1683 (parCat[
'compRefSigma'].size, )),
1684 (
'COMPMIRRORCHROMATICITY',
'f8',
1685 (parCat[
'compMirrorChromaticity'].size, )),
1686 (
'MIRRORCHROMATICITYPIVOT',
'f8',
1687 (parCat[
'mirrorChromaticityPivot'].size, )),
1688 (
'COMPCCDCHROMATICITY',
'f8',
1689 (parCat[
'compCcdChromaticity'].size, )),
1690 (
'COMPMEDIANSEDSLOPE',
'f8',
1691 (parCat[
'compMedianSedSlope'].size, )),
1692 (
'COMPAPERCORRPIVOT',
'f8',
1693 (parCat[
'compAperCorrPivot'].size, )),
1694 (
'COMPAPERCORRSLOPE',
'f8',
1695 (parCat[
'compAperCorrSlope'].size, )),
1696 (
'COMPAPERCORRSLOPEERR',
'f8',
1697 (parCat[
'compAperCorrSlopeErr'].size, )),
1698 (
'COMPAPERCORRRANGE',
'f8',
1699 (parCat[
'compAperCorrRange'].size, )),
1700 (
'COMPMODELERREXPTIMEPIVOT',
'f8',
1701 (parCat[
'compModelErrExptimePivot'].size, )),
1702 (
'COMPMODELERRFWHMPIVOT',
'f8',
1703 (parCat[
'compModelErrFwhmPivot'].size, )),
1704 (
'COMPMODELERRSKYPIVOT',
'f8',
1705 (parCat[
'compModelErrSkyPivot'].size, )),
1706 (
'COMPMODELERRPARS',
'f8',
1707 (parCat[
'compModelErrPars'].size, )),
1708 (
'COMPEXPGRAY',
'f8',
1709 (parCat[
'compExpGray'].size, )),
1710 (
'COMPVARGRAY',
'f8',
1711 (parCat[
'compVarGray'].size, )),
1712 (
'COMPEXPDELTAMAGBKG',
'f8',
1713 (parCat[
'compExpDeltaMagBkg'].size, )),
1714 (
'COMPNGOODSTARPEREXP',
'i4',
1715 (parCat[
'compNGoodStarPerExp'].size, )),
1716 (
'COMPEXPREFOFFSET',
'f8',
1717 (parCat[
'compExpRefOffset'].size, )),
1718 (
'COMPSIGFGCM',
'f8',
1719 (parCat[
'compSigFgcm'].size, )),
1720 (
'COMPSIGMACAL',
'f8',
1721 (parCat[
'compSigmaCal'].size, )),
1722 (
'COMPRETRIEVEDLNPWV',
'f8',
1723 (parCat[
'compRetrievedLnPwv'].size, )),
1724 (
'COMPRETRIEVEDLNPWVRAW',
'f8',
1725 (parCat[
'compRetrievedLnPwvRaw'].size, )),
1726 (
'COMPRETRIEVEDLNPWVFLAG',
'i2',
1727 (parCat[
'compRetrievedLnPwvFlag'].size, )),
1728 (
'COMPRETRIEVEDTAUNIGHT',
'f8',
1729 (parCat[
'compRetrievedTauNight'].size, )),
1730 (
'COMPEPSILON',
'f8',
1731 (parCat[
'compEpsilon'].size, )),
1732 (
'COMPMEDDELTAAPER',
'f8',
1733 (parCat[
'compMedDeltaAper'].size, )),
1734 (
'COMPGLOBALEPSILON',
'f4',
1735 (parCat[
'compGlobalEpsilon'].size, )),
1736 (
'COMPEPSILONMAP',
'f4',
1737 (parCat[
'compEpsilonMap'].size, )),
1738 (
'COMPEPSILONNSTARMAP',
'i4',
1739 (parCat[
'compEpsilonNStarMap'].size, )),
1740 (
'COMPEPSILONCCDMAP',
'f4',
1741 (parCat[
'compEpsilonCcdMap'].size, )),
1742 (
'COMPEPSILONCCDNSTARMAP',
'i4',
1743 (parCat[
'compEpsilonCcdNStarMap'].size, ))])
1745 inParams[
'PARALPHA'][:] = parCat[
'parAlpha'][0, :]
1746 inParams[
'PARO3'][:] = parCat[
'parO3'][0, :]
1747 inParams[
'PARLNTAUINTERCEPT'][:] = parCat[
'parLnTauIntercept'][0, :]
1748 inParams[
'PARLNTAUSLOPE'][:] = parCat[
'parLnTauSlope'][0, :]
1749 inParams[
'PARLNPWVINTERCEPT'][:] = parCat[
'parLnPwvIntercept'][0, :]
1750 inParams[
'PARLNPWVSLOPE'][:] = parCat[
'parLnPwvSlope'][0, :]
1751 inParams[
'PARLNPWVQUADRATIC'][:] = parCat[
'parLnPwvQuadratic'][0, :]
1752 inParams[
'PARQESYSINTERCEPT'][:] = parCat[
'parQeSysIntercept'][0, :]
1753 inParams[
'COMPQESYSSLOPE'][:] = parCat[
'compQeSysSlope'][0, :]
1754 inParams[
'PARFILTEROFFSET'][:] = parCat[
'parFilterOffset'][0, :]
1755 inParams[
'PARFILTEROFFSETFITFLAG'][:] = parCat[
'parFilterOffsetFitFlag'][0, :]
1756 inParams[
'PARRETRIEVEDLNPWVSCALE'] = parCat[
'parRetrievedLnPwvScale']
1757 inParams[
'PARRETRIEVEDLNPWVOFFSET'] = parCat[
'parRetrievedLnPwvOffset']
1758 inParams[
'PARRETRIEVEDLNPWVNIGHTLYOFFSET'][:] = parCat[
'parRetrievedLnPwvNightlyOffset'][0, :]
1759 inParams[
'COMPABSTHROUGHPUT'][:] = parCat[
'compAbsThroughput'][0, :]
1760 inParams[
'COMPREFOFFSET'][:] = parCat[
'compRefOffset'][0, :]
1761 inParams[
'COMPREFSIGMA'][:] = parCat[
'compRefSigma'][0, :]
1762 inParams[
'COMPMIRRORCHROMATICITY'][:] = parCat[
'compMirrorChromaticity'][0, :]
1763 inParams[
'MIRRORCHROMATICITYPIVOT'][:] = parCat[
'mirrorChromaticityPivot'][0, :]
1764 inParams[
'COMPCCDCHROMATICITY'][:] = parCat[
'compCcdChromaticity'][0, :]
1765 inParams[
'COMPMEDIANSEDSLOPE'][:] = parCat[
'compMedianSedSlope'][0, :]
1766 inParams[
'COMPAPERCORRPIVOT'][:] = parCat[
'compAperCorrPivot'][0, :]
1767 inParams[
'COMPAPERCORRSLOPE'][:] = parCat[
'compAperCorrSlope'][0, :]
1768 inParams[
'COMPAPERCORRSLOPEERR'][:] = parCat[
'compAperCorrSlopeErr'][0, :]
1769 inParams[
'COMPAPERCORRRANGE'][:] = parCat[
'compAperCorrRange'][0, :]
1770 inParams[
'COMPMODELERREXPTIMEPIVOT'][:] = parCat[
'compModelErrExptimePivot'][0, :]
1771 inParams[
'COMPMODELERRFWHMPIVOT'][:] = parCat[
'compModelErrFwhmPivot'][0, :]
1772 inParams[
'COMPMODELERRSKYPIVOT'][:] = parCat[
'compModelErrSkyPivot'][0, :]
1773 inParams[
'COMPMODELERRPARS'][:] = parCat[
'compModelErrPars'][0, :]
1774 inParams[
'COMPEXPGRAY'][:] = parCat[
'compExpGray'][0, :]
1775 inParams[
'COMPVARGRAY'][:] = parCat[
'compVarGray'][0, :]
1776 inParams[
'COMPEXPDELTAMAGBKG'][:] = parCat[
'compExpDeltaMagBkg'][0, :]
1777 inParams[
'COMPNGOODSTARPEREXP'][:] = parCat[
'compNGoodStarPerExp'][0, :]
1778 inParams[
'COMPEXPREFOFFSET'][:] = parCat[
'compExpRefOffset'][0, :]
1779 inParams[
'COMPSIGFGCM'][:] = parCat[
'compSigFgcm'][0, :]
1780 inParams[
'COMPSIGMACAL'][:] = parCat[
'compSigmaCal'][0, :]
1781 inParams[
'COMPRETRIEVEDLNPWV'][:] = parCat[
'compRetrievedLnPwv'][0, :]
1782 inParams[
'COMPRETRIEVEDLNPWVRAW'][:] = parCat[
'compRetrievedLnPwvRaw'][0, :]
1783 inParams[
'COMPRETRIEVEDLNPWVFLAG'][:] = parCat[
'compRetrievedLnPwvFlag'][0, :]
1784 inParams[
'COMPRETRIEVEDTAUNIGHT'][:] = parCat[
'compRetrievedTauNight'][0, :]
1785 inParams[
'COMPEPSILON'][:] = parCat[
'compEpsilon'][0, :]
1786 inParams[
'COMPMEDDELTAAPER'][:] = parCat[
'compMedDeltaAper'][0, :]
1787 inParams[
'COMPGLOBALEPSILON'][:] = parCat[
'compGlobalEpsilon'][0, :]
1788 inParams[
'COMPEPSILONMAP'][:] = parCat[
'compEpsilonMap'][0, :]
1789 inParams[
'COMPEPSILONNSTARMAP'][:] = parCat[
'compEpsilonNStarMap'][0, :]
1790 inParams[
'COMPEPSILONCCDMAP'][:] = parCat[
'compEpsilonCcdMap'][0, :]
1791 inParams[
'COMPEPSILONCCDNSTARMAP'][:] = parCat[
'compEpsilonCcdNStarMap'][0, :]
1793 inSuperStar = np.zeros(parCat[
'superstarSize'][0, :], dtype=
'f8')
1794 inSuperStar[:, :, :, :] = parCat[
'superstar'][0, :].reshape(inSuperStar.shape)
1796 return (inParInfo, inParams, inSuperStar)
1798 def _makeFgcmOutputDatasets(self, fgcmFitCycle):
1800 Persist FGCM datasets through the butler.
1804 fgcmFitCycle: `lsst.fgcm.FgcmFitCycle`
1805 Fgcm Fit cycle object
1807 fgcmDatasetDict = {}
1810 parInfo, pars = fgcmFitCycle.fgcmPars.parsToArrays()
1815 lutFilterNameString = comma.join([n.decode(
'utf-8')
1816 for n
in parInfo[
'LUTFILTERNAMES'][0]])
1817 fitBandString = comma.join([n.decode(
'utf-8')
1818 for n
in parInfo[
'FITBANDS'][0]])
1820 parSchema = self._makeParSchema(parInfo, pars, fgcmFitCycle.fgcmPars.parSuperStarFlat,
1821 lutFilterNameString, fitBandString)
1822 parCat = self._makeParCatalog(parSchema, parInfo, pars,
1823 fgcmFitCycle.fgcmPars.parSuperStarFlat,
1824 lutFilterNameString, fitBandString)
1826 fgcmDatasetDict[
'fgcmFitParameters'] = parCat
1831 flagStarSchema = self._makeFlagStarSchema()
1832 flagStarStruct = fgcmFitCycle.fgcmStars.getFlagStarIndices()
1833 flagStarCat = self._makeFlagStarCat(flagStarSchema, flagStarStruct)
1835 fgcmDatasetDict[
'fgcmFlaggedStars'] = flagStarCat
1838 if self.outputZeropoints:
1839 superStarChebSize = fgcmFitCycle.fgcmZpts.zpStruct[
'FGCM_FZPT_SSTAR_CHEB'].shape[1]
1840 zptChebSize = fgcmFitCycle.fgcmZpts.zpStruct[
'FGCM_FZPT_CHEB'].shape[1]
1842 zptSchema = makeZptSchema(superStarChebSize, zptChebSize)
1843 zptCat = makeZptCat(zptSchema, fgcmFitCycle.fgcmZpts.zpStruct)
1845 fgcmDatasetDict[
'fgcmZeropoints'] = zptCat
1849 atmSchema = makeAtmSchema()
1850 atmCat = makeAtmCat(atmSchema, fgcmFitCycle.fgcmZpts.atmStruct)
1852 fgcmDatasetDict[
'fgcmAtmosphereParameters'] = atmCat
1855 if self.outputStandards:
1856 stdStruct, goodBands = fgcmFitCycle.fgcmStars.retrieveStdStarCatalog(fgcmFitCycle.fgcmPars)
1857 stdSchema = makeStdSchema(len(goodBands))
1858 stdCat = makeStdCat(stdSchema, stdStruct, goodBands)
1860 fgcmDatasetDict[
'fgcmStandardStars'] = stdCat
1862 return fgcmDatasetDict
1864 def _makeParSchema(self, parInfo, pars, parSuperStarFlat,
1865 lutFilterNameString, fitBandString):
1867 Make the parameter persistence schema
1871 parInfo: `numpy.ndarray`
1872 Parameter information returned by fgcm
1873 pars: `numpy.ndarray`
1874 Parameter values returned by fgcm
1875 parSuperStarFlat: `numpy.array`
1876 Superstar flat values returned by fgcm
1877 lutFilterNameString: `str`
1878 Combined string of all the lutFilterNames
1879 fitBandString: `str`
1880 Combined string of all the fitBands
1884 parSchema: `afwTable.schema`
1890 parSchema.addField(
'nCcd', type=np.int32, doc=
'Number of CCDs')
1891 parSchema.addField(
'lutFilterNames', type=str, doc=
'LUT Filter names in parameter file',
1892 size=len(lutFilterNameString))
1893 parSchema.addField(
'fitBands', type=str, doc=
'Bands that were fit',
1894 size=len(fitBandString))
1895 parSchema.addField(
'lnTauUnit', type=np.float64, doc=
'Step units for ln(AOD)')
1896 parSchema.addField(
'lnTauSlopeUnit', type=np.float64,
1897 doc=
'Step units for ln(AOD) slope')
1898 parSchema.addField(
'alphaUnit', type=np.float64, doc=
'Step units for alpha')
1899 parSchema.addField(
'lnPwvUnit', type=np.float64, doc=
'Step units for ln(pwv)')
1900 parSchema.addField(
'lnPwvSlopeUnit', type=np.float64,
1901 doc=
'Step units for ln(pwv) slope')
1902 parSchema.addField(
'lnPwvQuadraticUnit', type=np.float64,
1903 doc=
'Step units for ln(pwv) quadratic term')
1904 parSchema.addField(
'lnPwvGlobalUnit', type=np.float64,
1905 doc=
'Step units for global ln(pwv) parameters')
1906 parSchema.addField(
'o3Unit', type=np.float64, doc=
'Step units for O3')
1907 parSchema.addField(
'qeSysUnit', type=np.float64, doc=
'Step units for mirror gray')
1908 parSchema.addField(
'filterOffsetUnit', type=np.float64, doc=
'Step units for filter offset')
1909 parSchema.addField(
'hasExternalPwv', type=np.int32, doc=
'Parameters fit using external pwv')
1910 parSchema.addField(
'hasExternalTau', type=np.int32, doc=
'Parameters fit using external tau')
1913 parSchema.addField(
'parAlpha', type=
'ArrayD', doc=
'Alpha parameter vector',
1914 size=pars[
'PARALPHA'].size)
1915 parSchema.addField(
'parO3', type=
'ArrayD', doc=
'O3 parameter vector',
1916 size=pars[
'PARO3'].size)
1917 parSchema.addField(
'parLnTauIntercept', type=
'ArrayD',
1918 doc=
'ln(Tau) intercept parameter vector',
1919 size=pars[
'PARLNTAUINTERCEPT'].size)
1920 parSchema.addField(
'parLnTauSlope', type=
'ArrayD',
1921 doc=
'ln(Tau) slope parameter vector',
1922 size=pars[
'PARLNTAUSLOPE'].size)
1923 parSchema.addField(
'parLnPwvIntercept', type=
'ArrayD', doc=
'ln(pwv) intercept parameter vector',
1924 size=pars[
'PARLNPWVINTERCEPT'].size)
1925 parSchema.addField(
'parLnPwvSlope', type=
'ArrayD', doc=
'ln(pwv) slope parameter vector',
1926 size=pars[
'PARLNPWVSLOPE'].size)
1927 parSchema.addField(
'parLnPwvQuadratic', type=
'ArrayD', doc=
'ln(pwv) quadratic parameter vector',
1928 size=pars[
'PARLNPWVQUADRATIC'].size)
1929 parSchema.addField(
'parQeSysIntercept', type=
'ArrayD', doc=
'Mirror gray intercept parameter vector',
1930 size=pars[
'PARQESYSINTERCEPT'].size)
1931 parSchema.addField(
'compQeSysSlope', type=
'ArrayD', doc=
'Mirror gray slope parameter vector',
1932 size=pars[0][
'COMPQESYSSLOPE'].size)
1933 parSchema.addField(
'parFilterOffset', type=
'ArrayD', doc=
'Filter offset parameter vector',
1934 size=pars[
'PARFILTEROFFSET'].size)
1935 parSchema.addField(
'parFilterOffsetFitFlag', type=
'ArrayI', doc=
'Filter offset parameter fit flag',
1936 size=pars[
'PARFILTEROFFSETFITFLAG'].size)
1937 parSchema.addField(
'parRetrievedLnPwvScale', type=np.float64,
1938 doc=
'Global scale for retrieved ln(pwv)')
1939 parSchema.addField(
'parRetrievedLnPwvOffset', type=np.float64,
1940 doc=
'Global offset for retrieved ln(pwv)')
1941 parSchema.addField(
'parRetrievedLnPwvNightlyOffset', type=
'ArrayD',
1942 doc=
'Nightly offset for retrieved ln(pwv)',
1943 size=pars[
'PARRETRIEVEDLNPWVNIGHTLYOFFSET'].size)
1944 parSchema.addField(
'compAbsThroughput', type=
'ArrayD',
1945 doc=
'Absolute throughput (relative to transmission curves)',
1946 size=pars[
'COMPABSTHROUGHPUT'].size)
1947 parSchema.addField(
'compRefOffset', type=
'ArrayD',
1948 doc=
'Offset between reference stars and calibrated stars',
1949 size=pars[
'COMPREFOFFSET'].size)
1950 parSchema.addField(
'compRefSigma', type=
'ArrayD',
1951 doc=
'Width of reference star/calibrated star distribution',
1952 size=pars[
'COMPREFSIGMA'].size)
1953 parSchema.addField(
'compMirrorChromaticity', type=
'ArrayD',
1954 doc=
'Computed mirror chromaticity terms',
1955 size=pars[
'COMPMIRRORCHROMATICITY'].size)
1956 parSchema.addField(
'mirrorChromaticityPivot', type=
'ArrayD',
1957 doc=
'Mirror chromaticity pivot mjd',
1958 size=pars[
'MIRRORCHROMATICITYPIVOT'].size)
1959 parSchema.addField(
'compCcdChromaticity', type=
'ArrayD',
1960 doc=
'Computed CCD chromaticity terms',
1961 size=pars[
'COMPCCDCHROMATICITY'].size)
1962 parSchema.addField(
'compMedianSedSlope', type=
'ArrayD',
1963 doc=
'Computed median SED slope (per band)',
1964 size=pars[
'COMPMEDIANSEDSLOPE'].size)
1965 parSchema.addField(
'compAperCorrPivot', type=
'ArrayD', doc=
'Aperture correction pivot',
1966 size=pars[
'COMPAPERCORRPIVOT'].size)
1967 parSchema.addField(
'compAperCorrSlope', type=
'ArrayD', doc=
'Aperture correction slope',
1968 size=pars[
'COMPAPERCORRSLOPE'].size)
1969 parSchema.addField(
'compAperCorrSlopeErr', type=
'ArrayD', doc=
'Aperture correction slope error',
1970 size=pars[
'COMPAPERCORRSLOPEERR'].size)
1971 parSchema.addField(
'compAperCorrRange', type=
'ArrayD', doc=
'Aperture correction range',
1972 size=pars[
'COMPAPERCORRRANGE'].size)
1973 parSchema.addField(
'compModelErrExptimePivot', type=
'ArrayD', doc=
'Model error exptime pivot',
1974 size=pars[
'COMPMODELERREXPTIMEPIVOT'].size)
1975 parSchema.addField(
'compModelErrFwhmPivot', type=
'ArrayD', doc=
'Model error fwhm pivot',
1976 size=pars[
'COMPMODELERRFWHMPIVOT'].size)
1977 parSchema.addField(
'compModelErrSkyPivot', type=
'ArrayD', doc=
'Model error sky pivot',
1978 size=pars[
'COMPMODELERRSKYPIVOT'].size)
1979 parSchema.addField(
'compModelErrPars', type=
'ArrayD', doc=
'Model error parameters',
1980 size=pars[
'COMPMODELERRPARS'].size)
1981 parSchema.addField(
'compExpGray', type=
'ArrayD', doc=
'Computed exposure gray',
1982 size=pars[
'COMPEXPGRAY'].size)
1983 parSchema.addField(
'compVarGray', type=
'ArrayD', doc=
'Computed exposure variance',
1984 size=pars[
'COMPVARGRAY'].size)
1985 parSchema.addField(
'compExpDeltaMagBkg', type=
'ArrayD',
1986 doc=
'Computed exposure offset due to background',
1987 size=pars[
'COMPEXPDELTAMAGBKG'].size)
1988 parSchema.addField(
'compNGoodStarPerExp', type=
'ArrayI',
1989 doc=
'Computed number of good stars per exposure',
1990 size=pars[
'COMPNGOODSTARPEREXP'].size)
1991 parSchema.addField(
'compExpRefOffset', type=
'ArrayD',
1992 doc=
'Computed per-visit median offset between standard stars and ref stars.',
1993 size=pars[
'COMPEXPREFOFFSET'].size)
1994 parSchema.addField(
'compSigFgcm', type=
'ArrayD', doc=
'Computed sigma_fgcm (intrinsic repeatability)',
1995 size=pars[
'COMPSIGFGCM'].size)
1996 parSchema.addField(
'compSigmaCal', type=
'ArrayD', doc=
'Computed sigma_cal (systematic error floor)',
1997 size=pars[
'COMPSIGMACAL'].size)
1998 parSchema.addField(
'compRetrievedLnPwv', type=
'ArrayD', doc=
'Retrieved ln(pwv) (smoothed)',
1999 size=pars[
'COMPRETRIEVEDLNPWV'].size)
2000 parSchema.addField(
'compRetrievedLnPwvRaw', type=
'ArrayD', doc=
'Retrieved ln(pwv) (raw)',
2001 size=pars[
'COMPRETRIEVEDLNPWVRAW'].size)
2002 parSchema.addField(
'compRetrievedLnPwvFlag', type=
'ArrayI', doc=
'Retrieved ln(pwv) Flag',
2003 size=pars[
'COMPRETRIEVEDLNPWVFLAG'].size)
2004 parSchema.addField(
'compRetrievedTauNight', type=
'ArrayD', doc=
'Retrieved tau (per night)',
2005 size=pars[
'COMPRETRIEVEDTAUNIGHT'].size)
2006 parSchema.addField(
'compEpsilon', type=
'ArrayD',
2007 doc=
'Computed epsilon background offset per visit (nJy/arcsec2)',
2008 size=pars[
'COMPEPSILON'].size)
2009 parSchema.addField(
'compMedDeltaAper', type=
'ArrayD',
2010 doc=
'Median delta mag aper per visit',
2011 size=pars[
'COMPMEDDELTAAPER'].size)
2012 parSchema.addField(
'compGlobalEpsilon', type=
'ArrayD',
2013 doc=
'Computed epsilon bkg offset (global) (nJy/arcsec2)',
2014 size=pars[
'COMPGLOBALEPSILON'].size)
2015 parSchema.addField(
'compEpsilonMap', type=
'ArrayD',
2016 doc=
'Computed epsilon maps (nJy/arcsec2)',
2017 size=pars[
'COMPEPSILONMAP'].size)
2018 parSchema.addField(
'compEpsilonNStarMap', type=
'ArrayI',
2019 doc=
'Number of stars per pixel in computed epsilon maps',
2020 size=pars[
'COMPEPSILONNSTARMAP'].size)
2021 parSchema.addField(
'compEpsilonCcdMap', type=
'ArrayD',
2022 doc=
'Computed epsilon ccd maps (nJy/arcsec2)',
2023 size=pars[
'COMPEPSILONCCDMAP'].size)
2024 parSchema.addField(
'compEpsilonCcdNStarMap', type=
'ArrayI',
2025 doc=
'Number of stars per ccd bin in epsilon ccd maps',
2026 size=pars[
'COMPEPSILONCCDNSTARMAP'].size)
2028 parSchema.addField(
'superstarSize', type=
'ArrayI', doc=
'Superstar matrix size',
2030 parSchema.addField(
'superstar', type=
'ArrayD', doc=
'Superstar matrix (flattened)',
2031 size=parSuperStarFlat.size)
2035 def _makeParCatalog(self, parSchema, parInfo, pars, parSuperStarFlat,
2036 lutFilterNameString, fitBandString):
2038 Make the FGCM parameter catalog for persistence
2042 parSchema: `lsst.afw.table.Schema`
2043 Parameter catalog schema
2044 pars: `numpy.ndarray`
2045 FGCM parameters to put into parCat
2046 parSuperStarFlat: `numpy.array`
2047 FGCM superstar flat array to put into parCat
2048 lutFilterNameString: `str`
2049 Combined string of all the lutFilterNames
2050 fitBandString: `str`
2051 Combined string of all the fitBands
2055 parCat: `afwTable.BasicCatalog`
2056 Atmosphere and instrumental model parameter catalog for persistence
2064 rec = parCat.addNew()
2067 rec[
'nCcd'] = parInfo[
'NCCD'][0]
2068 rec[
'lutFilterNames'] = lutFilterNameString
2069 rec[
'fitBands'] = fitBandString
2071 rec[
'hasExternalPwv'] = 0
2072 rec[
'hasExternalTau'] = 0
2076 scalarNames = [
'parRetrievedLnPwvScale',
'parRetrievedLnPwvOffset']
2078 arrNames = [
'parAlpha',
'parO3',
'parLnTauIntercept',
'parLnTauSlope',
2079 'parLnPwvIntercept',
'parLnPwvSlope',
'parLnPwvQuadratic',
2080 'parQeSysIntercept',
'compQeSysSlope',
2081 'parRetrievedLnPwvNightlyOffset',
'compAperCorrPivot',
2082 'parFilterOffset',
'parFilterOffsetFitFlag',
2083 'compAbsThroughput',
'compRefOffset',
'compRefSigma',
2084 'compMirrorChromaticity',
'mirrorChromaticityPivot',
'compCcdChromaticity',
2085 'compAperCorrSlope',
'compAperCorrSlopeErr',
'compAperCorrRange',
2086 'compModelErrExptimePivot',
'compModelErrFwhmPivot',
2087 'compModelErrSkyPivot',
'compModelErrPars',
2088 'compExpGray',
'compVarGray',
'compNGoodStarPerExp',
'compSigFgcm',
2089 'compSigmaCal',
'compExpDeltaMagBkg',
'compMedianSedSlope',
2090 'compRetrievedLnPwv',
'compRetrievedLnPwvRaw',
'compRetrievedLnPwvFlag',
2091 'compRetrievedTauNight',
'compEpsilon',
'compMedDeltaAper',
2092 'compGlobalEpsilon',
'compEpsilonMap',
'compEpsilonNStarMap',
2093 'compEpsilonCcdMap',
'compEpsilonCcdNStarMap',
'compExpRefOffset']
2095 for scalarName
in scalarNames:
2096 rec[scalarName] = pars[scalarName.upper()][0]
2098 for arrName
in arrNames:
2099 rec[arrName][:] = np.atleast_1d(pars[0][arrName.upper()])[:]
2102 rec[
'superstarSize'][:] = parSuperStarFlat.shape
2103 rec[
'superstar'][:] = parSuperStarFlat.ravel()
2107 def _makeFlagStarSchema(self):
2109 Make the flagged-stars schema
2113 flagStarSchema: `lsst.afw.table.Schema`
2118 flagStarSchema.addField(
'objId', type=np.int32, doc=
'FGCM object id')
2119 flagStarSchema.addField(
'objFlag', type=np.int32, doc=
'FGCM object flag')
2121 return flagStarSchema
2123 def _makeFlagStarCat(self, flagStarSchema, flagStarStruct):
2125 Make the flagged star catalog for persistence
2129 flagStarSchema: `lsst.afw.table.Schema`
2131 flagStarStruct: `numpy.ndarray`
2132 Flagged star structure from fgcm
2136 flagStarCat: `lsst.afw.table.BaseCatalog`
2137 Flagged star catalog for persistence
2141 flagStarCat.resize(flagStarStruct.size)
2143 flagStarCat[
'objId'][:] = flagStarStruct[
'OBJID']
2144 flagStarCat[
'objFlag'][:] = flagStarStruct[
'OBJFLAG']
Defines the fields and offsets for a table.