23 import astropy.units
as units
24 from astropy.time
import Time
25 from astropy.coordinates
import AltAz, SkyCoord, EarthLocation
33 from lsst.utils.timer
import timeMethod
36 __all__ = (
"ComputeExposureSummaryStatsTask",
"ComputeExposureSummaryStatsConfig")
40 """Config for ComputeExposureSummaryTask"""
41 sigmaClip = pexConfig.Field(
43 doc=
"Sigma for outlier rejection for sky noise.",
46 clipIter = pexConfig.Field(
48 doc=
"Number of iterations of outlier rejection for sky noise.",
51 badMaskPlanes = pexConfig.ListField(
53 doc=
"Mask planes that, if set, the associated pixel should not be included sky noise calculation.",
54 default=(
"NO_DATA",
"SUSPECT"),
59 """Task to compute exposure summary statistics.
61 This task computes various quantities suitable for DPDD and other
62 downstream processing at the detector centers, including:
80 ConfigClass = ComputeExposureSummaryStatsConfig
81 _DefaultName =
"computeExposureSummaryStats"
84 def run(self, exposure, sources, background):
85 """Measure exposure statistics from the exposure, sources, and background.
89 exposure : `lsst.afw.image.ExposureF`
90 sources : `lsst.afw.table.SourceCatalog`
91 background : `lsst.afw.math.BackgroundList`
95 summary : `lsst.afw.image.ExposureSummary`
97 self.log.info(
"Measuring exposure statistics")
99 bbox = exposure.getBBox()
101 psf = exposure.getPsf()
103 shape = psf.computeShape(bbox.getCenter())
104 psfSigma = shape.getDeterminantRadius()
105 psfIxx = shape.getIxx()
106 psfIyy = shape.getIyy()
107 psfIxy = shape.getIxy()
108 im = psf.computeKernelImage(bbox.getCenter())
113 psfArea = np.sum(im.array)/np.sum(im.array**2.)
121 wcs = exposure.getWcs()
124 raCorners = [float(sph.getRa().asDegrees())
for sph
in sph_pts]
125 decCorners = [float(sph.getDec().asDegrees())
for sph
in sph_pts]
127 sph_pt = wcs.pixelToSky(bbox.getCenter())
128 ra = sph_pt.getRa().asDegrees()
129 decl = sph_pt.getDec().asDegrees()
131 raCorners = [float(np.nan)]*4
132 decCorners = [float(np.nan)]*4
136 photoCalib = exposure.getPhotoCalib()
137 if photoCalib
is not None:
138 zeroPoint = 2.5*np.log10(photoCalib.getInstFluxAtZeroMagnitude())
142 visitInfo = exposure.getInfo().getVisitInfo()
143 date = visitInfo.getDate()
149 observatory = visitInfo.getObservatory()
150 loc = EarthLocation(lat=observatory.getLatitude().asDegrees()*units.deg,
151 lon=observatory.getLongitude().asDegrees()*units.deg,
152 height=observatory.getElevation()*units.m)
153 obstime = Time(visitInfo.getDate().get(system=DateTime.MJD),
154 location=loc, format=
'mjd')
155 coord = SkyCoord(ra*units.degree, decl*units.degree, obstime=obstime, location=loc)
156 with warnings.catch_warnings():
157 warnings.simplefilter(
'ignore')
158 altaz = coord.transform_to(AltAz)
160 zenithDistance = 90.0 - altaz.alt.degree
162 zenithDistance = np.nan
164 if background
is not None:
165 bgStats = (bg[0].getStatsImage().getImage().array
166 for bg
in background)
167 skyBg = sum(np.median(bg[np.isfinite(bg)])
for bg
in bgStats)
171 statsCtrl = afwMath.StatisticsControl()
172 statsCtrl.setNumSigmaClip(self.config.sigmaClip)
173 statsCtrl.setNumIter(self.config.clipIter)
174 statsCtrl.setAndMask(afwImage.Mask.getPlaneBitMask(self.config.badMaskPlanes))
175 statsCtrl.setNanSafe(
True)
177 statObj = afwMath.makeStatistics(exposure.getMaskedImage(), afwMath.STDEVCLIP,
179 skyNoise, _ = statObj.getResult(afwMath.STDEVCLIP)
181 statObj = afwMath.makeStatistics(exposure.getMaskedImage().getVariance(),
182 exposure.getMaskedImage().getMask(),
183 afwMath.MEANCLIP, statsCtrl)
184 meanVar, _ = statObj.getResult(afwMath.MEANCLIP)
186 md = exposure.getMetadata()
187 if 'SFM_ASTROM_OFFSET_MEAN' in md:
188 astromOffsetMean = md[
'SFM_ASTROM_OFFSET_MEAN']
189 astromOffsetStd = md[
'SFM_ASTROM_OFFSET_STD']
191 astromOffsetMean = np.nan
192 astromOffsetStd = np.nan
194 summary = afwImage.ExposureSummaryStats(psfSigma=float(psfSigma),
195 psfArea=float(psfArea),
196 psfIxx=float(psfIxx),
197 psfIyy=float(psfIyy),
198 psfIxy=float(psfIxy),
201 zenithDistance=float(zenithDistance),
202 zeroPoint=float(zeroPoint),
204 skyNoise=float(skyNoise),
205 meanVar=float(meanVar),
207 decCorners=decCorners,
208 astromOffsetMean=astromOffsetMean,
209 astromOffsetStd=astromOffsetStd)
def run(self, exposure, sources, background)