1 from __future__
import absolute_import, division, print_function
12 from lsst.pex.config import Config, Field, ConfigurableField, ConfigField
22 """Make and write an image of an entire focal plane 26 camera : `lsst.afw.cameraGeom.Camera` 28 exposures : `list` of `tuple` of `int` and `lsst.afw.image.Exposure` 29 List of detector ID and CCD exposures (binned by `binning`). 30 filename : `str`, optional 33 Binning size that has been applied to images. 35 image = visualizeVisit.makeCameraImage(camera, dict(exp
for exp
in exposures
if exp
is not None), binning)
36 if filename
is not None:
37 image.writeFits(filename)
42 """Configuration for SkyCorrectionTask""" 43 bgModel = ConfigField(dtype=FocalPlaneBackgroundConfig, doc=
"Background model")
44 sky = ConfigurableField(target=SkyMeasurementTask, doc=
"Sky measurement")
45 detection = ConfigurableField(target=measAlg.SourceDetectionTask, doc=
"Detection configuration")
46 doDetection = Field(dtype=bool, default=
True, doc=
"Detect sources (to find good sky)?")
47 detectSigma = Field(dtype=float, default=5.0, doc=
"Detection PSF gaussian sigma")
48 doBgModel = Field(dtype=bool, default=
True, doc=
"Do background model subtraction?")
49 doSky = Field(dtype=bool, default=
True, doc=
"Do sky frame subtraction?")
50 binning = Field(dtype=int, default=8, doc=
"Binning factor for constructing focal-plane images")
53 Config.setDefaults(self)
54 self.
detection.reEstimateBackground =
False 56 self.
detection.doTempLocalBackground =
False 57 self.
detection.thresholdType =
"pixel_stdev" 61 """Correct sky over entire focal plane""" 62 ConfigClass = SkyCorrectionConfig
63 _DefaultName =
"skyCorr" 66 BatchPoolTask.__init__(self, *args, **kwargs)
67 self.makeSubtask(
"sky")
69 self.makeSubtask(
"detection", schema=afwTable.Schema())
72 def _makeArgumentParser(cls, *args, **kwargs):
73 kwargs.pop(
"doBatch",
False)
74 parser = ArgumentParser(name=
"skyCorr", *args, **kwargs)
75 parser.add_id_argument(
"--id", datasetType=
"calexp", level=
"visit",
76 help=
"data ID, e.g. --id visit=12345")
81 """Return walltime request for batch job 83 Subclasses should override if the walltime should be calculated 84 differently (e.g., addition of some serial time). 89 Requested time per iteration. 90 parsedCmd : `argparse.Namespace` 91 Results of argument parsing. 95 numTargets = len(cls.RunnerClass.getTargetList(parsedCmd))
96 return time*numTargets
99 """Perform sky correction on an exposure 101 We restore the original sky, and remove it again using multiple 102 algorithms. We optionally apply: 104 1. A large-scale background model. 107 Only the master node executes this method. The data is held on 108 the slave nodes, which do all the hard work. 112 expRef : `lsst.daf.persistence.ButlerDataRef` 113 Data reference for exposure. 116 extension =
"-%(visit)d.fits" % expRef.dataId
118 with self.
logOperation(
"processing %s" % (expRef.dataId,)):
121 pool.storeSet(butler=expRef.getButler())
122 camera = expRef.get(
"camera")
124 dataIdList = [ccdRef.dataId
for ccdRef
in expRef.subItems(
"ccd")
if 125 ccdRef.datasetExists(
"calexp")]
127 exposures = pool.map(self.
loadImage, dataIdList)
132 exposures = pool.mapToPrevious(self.
collectMask, dataIdList)
135 if self.config.doBgModel:
136 bgModel = FocalPlaneBackground.fromCamera(self.config.bgModel, camera)
137 data = [Struct(dataId=dataId, bgModel=bgModel.clone())
for dataId
in dataIdList]
139 for ii, bg
in enumerate(bgModelList):
140 self.log.info(
"Background %d: %d pixels", ii, bg._numbers.getArray().sum())
144 bgModel.getStatsImage().writeFits(
"bgModel" + extension)
145 bgImages = pool.mapToPrevious(self.
realiseModel, dataIdList, bgModel)
148 exposures = pool.mapToPrevious(self.
subtractModel, dataIdList, bgModel)
152 if self.config.doSky:
154 scale = self.sky.solveScales(measScales)
155 self.log.info(
"Sky frame scale: %s" % (scale,))
159 calibs = pool.mapToPrevious(self.
collectSky, dataIdList)
164 expRef.put(image,
"calexp_camera")
166 pool.mapToPrevious(self.
write, dataIdList)
169 """Load original image and restore the sky 171 This method runs on the slave nodes. 175 cache : `lsst.pipe.base.Struct` 182 exposure : `lsst.afw.image.Exposure` 185 cache.dataId = dataId
186 cache.exposure = cache.butler.get(
"calexp", dataId, immediate=
True).clone()
187 bgOld = cache.butler.get(
"calexpBackground", dataId, immediate=
True)
188 image = cache.exposure.getMaskedImage()
190 if self.config.doDetection:
193 results = self.detection.detectFootprints(cache.exposure, doSmooth=
True,
194 sigma=self.config.detectSigma, clearMask=
True)
195 if hasattr(results,
"background")
and results.background:
197 maskedImage += results.background.getImage()
201 statsImage = bgData[0].getStatsImage()
204 image -= bgOld.getImage()
205 cache.bgList = afwMath.BackgroundList()
207 cache.bgList.append(bgData)
212 """Measure scale for sky frame 214 This method runs on the slave nodes. 218 cache : `lsst.pipe.base.Struct` 228 assert cache.dataId == dataId
229 cache.sky = self.sky.getSkyData(cache.butler, dataId)
230 scale = self.sky.measureScale(cache.exposure.getMaskedImage(), cache.sky)
234 """Subtract sky frame 236 This method runs on the slave nodes. 240 cache : `lsst.pipe.base.Struct` 249 exposure : `lsst.afw.image.Exposure` 252 assert cache.dataId == dataId
253 self.sky.
subtractSkyFrame(cache.exposure.getMaskedImage(), cache.sky, scale, cache.bgList)
257 """Fit background model for CCD 259 This method runs on the slave nodes. 263 cache : `lsst.pipe.base.Struct` 265 data : `lsst.pipe.base.Struct` 266 Data identifier, with `dataId` (data identifier) and `bgModel` 267 (background model) elements. 271 bgModel : `lsst.pipe.drivers.background.FocalPlaneBackground` 274 assert cache.dataId == data.dataId
275 data.bgModel.addCcd(cache.exposure)
279 """Subtract background model 281 This method runs on the slave nodes. 285 cache : `lsst.pipe.base.Struct` 289 bgModel : `lsst.pipe.drivers.background.FocalPlaneBackround` 294 exposure : `lsst.afw.image.Exposure` 297 assert cache.dataId == dataId
298 exposure = cache.exposure
299 image = exposure.getMaskedImage()
300 detector = exposure.getDetector()
301 bbox = image.getBBox()
302 cache.bgModel = bgModel.toCcdBackground(detector, bbox)
303 image -= cache.bgModel.getImage()
304 cache.bgList.append(cache.bgModel[0])
308 """Generate an image of the background model for visualisation 310 Useful for debugging. 314 cache : `lsst.pipe.base.Struct` 318 bgModel : `lsst.pipe.drivers.background.FocalPlaneBackround` 325 image : `lsst.afw.image.MaskedImage` 326 Binned background model image. 328 assert cache.dataId == dataId
329 exposure = cache.exposure
330 detector = exposure.getDetector()
331 bbox = exposure.getMaskedImage().getBBox()
332 image = bgModel.toCcdBackground(detector, bbox).getImage()
336 """Return the binned image required for visualization 338 This method just helps to cut down on boilerplate. 342 image : `lsst.afw.image.MaskedImage` 343 Image to go into visualisation. 349 image : `lsst.afw.image.MaskedImage` 352 return (exposure.getDetector().getId(), afwMath.binImage(image, self.config.binning))
355 """Collect exposure for potential visualisation 357 This method runs on the slave nodes. 361 cache : `lsst.pipe.base.Struct` 368 image : `lsst.afw.image.MaskedImage` 374 """Collect original image for visualisation 376 This method runs on the slave nodes. 380 cache : `lsst.pipe.base.Struct` 389 image : `lsst.afw.image.MaskedImage` 392 exposure = cache.butler.get(
"calexp", dataId, immediate=
True)
396 """Collect original image for visualisation 398 This method runs on the slave nodes. 402 cache : `lsst.pipe.base.Struct` 411 image : `lsst.afw.image.MaskedImage` 417 """Collect mask for visualisation 419 This method runs on the slave nodes. 423 cache : `lsst.pipe.base.Struct` 432 image : `lsst.afw.image.Image` 436 image = afwImage.ImageF(cache.exposure.maskedImage.getBBox())
437 image.array[:] = cache.exposure.maskedImage.mask.array
441 """Write resultant background list 443 This method runs on the slave nodes. 447 cache : `lsst.pipe.base.Struct` 452 cache.butler.put(cache.bgList,
"skyCorr", dataId)
454 def _getMetadataName(self):
455 """There's no metadata to write out"""
def subtractModel(self, cache, dataId, bgModel)
def batchWallTime(cls, time, parsedCmd, numCores)
def runDataRef(self, expRef)
def makeCameraImage(camera, exposures, filename=None, binning=8)
def accumulateModel(self, cache, data)
def loadImage(self, cache, dataId)
def collectBinnedImage(self, exposure, image)
def realiseModel(self, cache, dataId, bgModel)
def collectOriginal(self, cache, dataId)
def subtractSkyFrame(self, cache, dataId, scale)
def write(self, cache, dataId)
def logOperation(self, operation, catch=False, trace=True)
def __init__(self, args, kwargs)
def collectSky(self, cache, dataId)
def collectMask(self, cache, dataId)
def measureSkyFrame(self, cache, dataId)