1 from __future__
import absolute_import, division, print_function
9 from lsst.pex.config import Config, Field, ConfigurableField, ConfigField
19 """Make and write an image of an entire focal plane 23 camera : `lsst.afw.cameraGeom.Camera` 25 exposures : `list` of `tuple` of `int` and `lsst.afw.image.Exposure` 26 List of detector ID and CCD exposures (binned by `binning`). 27 filename : `str`, optional 30 Binning size that has been applied to images. 32 image = visualizeVisit.makeCameraImage(camera, dict(exp
for exp
in exposures
if exp
is not None), binning)
33 if filename
is not None:
34 image.writeFits(filename)
39 """Configuration for SkyCorrectionTask""" 40 bgModel = ConfigField(dtype=FocalPlaneBackgroundConfig, doc=
"Background model")
41 sky = ConfigurableField(target=SkyMeasurementTask, doc=
"Sky measurement")
42 detection = ConfigurableField(target=measAlg.SourceDetectionTask, doc=
"Detection configuration")
43 doDetection = Field(dtype=bool, default=
True, doc=
"Detect sources (to find good sky)?")
44 detectSigma = Field(dtype=float, default=5.0, doc=
"Detection PSF gaussian sigma")
45 doBgModel = Field(dtype=bool, default=
True, doc=
"Do background model subtraction?")
46 doSky = Field(dtype=bool, default=
True, doc=
"Do sky frame subtraction?")
47 binning = Field(dtype=int, default=8, doc=
"Binning factor for constructing focal-plane images")
50 Config.setDefaults(self)
51 self.
detection.reEstimateBackground =
False 53 self.
detection.doTempLocalBackground =
False 54 self.
detection.thresholdType =
"pixel_stdev" 59 """Correct sky over entire focal plane""" 60 ConfigClass = SkyCorrectionConfig
61 _DefaultName =
"skyCorr" 64 BatchPoolTask.__init__(self, *args, **kwargs)
65 self.makeSubtask(
"sky")
67 self.makeSubtask(
"detection", schema=afwTable.Schema())
70 def _makeArgumentParser(cls, *args, **kwargs):
71 kwargs.pop(
"doBatch",
False)
72 parser = ArgumentParser(name=
"skyCorr", *args, **kwargs)
73 parser.add_id_argument(
"--id", datasetType=
"calexp", level=
"visit",
74 help=
"data ID, e.g. --id visit=12345")
79 """Return walltime request for batch job 81 Subclasses should override if the walltime should be calculated 82 differently (e.g., addition of some serial time). 87 Requested time per iteration. 88 parsedCmd : `argparse.Namespace` 89 Results of argument parsing. 93 numTargets = len(cls.RunnerClass.getTargetList(parsedCmd))
94 return time*numTargets
97 """Perform sky correction on an exposure 99 We restore the original sky, and remove it again using multiple 100 algorithms. We optionally apply: 102 1. A large-scale background model. 105 Only the master node executes this method. The data is held on 106 the slave nodes, which do all the hard work. 110 expRef : `lsst.daf.persistence.ButlerDataRef` 111 Data reference for exposure. 114 extension =
"-%(visit)d.fits" % expRef.dataId
116 with self.
logOperation(
"processing %s" % (expRef.dataId,)):
119 pool.storeSet(butler=expRef.getButler())
120 camera = expRef.get(
"camera")
122 dataIdList = [ccdRef.dataId
for ccdRef
in expRef.subItems(
"ccd")
if 123 ccdRef.datasetExists(
"calexp")]
125 exposures = pool.map(self.
loadImage, dataIdList)
130 exposures = pool.mapToPrevious(self.
collectMask, dataIdList)
133 if self.config.doBgModel:
134 bgModel = FocalPlaneBackground.fromCamera(self.config.bgModel, camera)
135 data = [Struct(dataId=dataId, bgModel=bgModel.clone())
for dataId
in dataIdList]
137 for ii, bg
in enumerate(bgModelList):
138 self.log.info(
"Background %d: %d pixels", ii, bg._numbers.getArray().sum())
142 bgModel.getStatsImage().writeFits(
"bgModel" + extension)
143 bgImages = pool.mapToPrevious(self.
realiseModel, dataIdList, bgModel)
146 exposures = pool.mapToPrevious(self.
subtractModel, dataIdList, bgModel)
150 if self.config.doSky:
152 scale = self.sky.solveScales(measScales)
153 self.log.info(
"Sky frame scale: %s" % (scale,))
157 calibs = pool.mapToPrevious(self.
collectSky, dataIdList)
162 expRef.put(image,
"calexp_camera")
164 pool.mapToPrevious(self.
write, dataIdList)
167 """Load original image and restore the sky 169 This method runs on the slave nodes. 173 cache : `lsst.pipe.base.Struct` 180 exposure : `lsst.afw.image.Exposure` 183 cache.dataId = dataId
184 cache.exposure = cache.butler.get(
"calexp", dataId, immediate=
True).clone()
185 bgOld = cache.butler.get(
"calexpBackground", dataId, immediate=
True)
186 image = cache.exposure.getMaskedImage()
188 if self.config.doDetection:
191 results = self.detection.detectFootprints(cache.exposure, doSmooth=
True,
192 sigma=self.config.detectSigma, clearMask=
True)
193 if hasattr(results,
"background")
and results.background:
195 image += results.background.getImage()
199 statsImage = bgData[0].getStatsImage()
202 image -= bgOld.getImage()
203 cache.bgList = afwMath.BackgroundList()
205 cache.bgList.append(bgData)
210 """Measure scale for sky frame 212 This method runs on the slave nodes. 216 cache : `lsst.pipe.base.Struct` 226 assert cache.dataId == dataId
227 cache.sky = self.sky.getSkyData(cache.butler, dataId)
228 scale = self.sky.measureScale(cache.exposure.getMaskedImage(), cache.sky)
232 """Subtract sky frame 234 This method runs on the slave nodes. 238 cache : `lsst.pipe.base.Struct` 247 exposure : `lsst.afw.image.Exposure` 250 assert cache.dataId == dataId
251 self.sky.
subtractSkyFrame(cache.exposure.getMaskedImage(), cache.sky, scale, cache.bgList)
255 """Fit background model for CCD 257 This method runs on the slave nodes. 261 cache : `lsst.pipe.base.Struct` 263 data : `lsst.pipe.base.Struct` 264 Data identifier, with `dataId` (data identifier) and `bgModel` 265 (background model) elements. 269 bgModel : `lsst.pipe.drivers.background.FocalPlaneBackground` 272 assert cache.dataId == data.dataId
273 data.bgModel.addCcd(cache.exposure)
277 """Subtract background model 279 This method runs on the slave nodes. 283 cache : `lsst.pipe.base.Struct` 287 bgModel : `lsst.pipe.drivers.background.FocalPlaneBackround` 292 exposure : `lsst.afw.image.Exposure` 295 assert cache.dataId == dataId
296 exposure = cache.exposure
297 image = exposure.getMaskedImage()
298 detector = exposure.getDetector()
299 bbox = image.getBBox()
300 cache.bgModel = bgModel.toCcdBackground(detector, bbox)
301 image -= cache.bgModel.getImage()
302 cache.bgList.append(cache.bgModel[0])
306 """Generate an image of the background model for visualisation 308 Useful for debugging. 312 cache : `lsst.pipe.base.Struct` 316 bgModel : `lsst.pipe.drivers.background.FocalPlaneBackround` 323 image : `lsst.afw.image.MaskedImage` 324 Binned background model image. 326 assert cache.dataId == dataId
327 exposure = cache.exposure
328 detector = exposure.getDetector()
329 bbox = exposure.getMaskedImage().getBBox()
330 image = bgModel.toCcdBackground(detector, bbox).getImage()
334 """Return the binned image required for visualization 336 This method just helps to cut down on boilerplate. 340 image : `lsst.afw.image.MaskedImage` 341 Image to go into visualisation. 347 image : `lsst.afw.image.MaskedImage` 350 return (exposure.getDetector().getId(), afwMath.binImage(image, self.config.binning))
353 """Collect exposure for potential visualisation 355 This method runs on the slave nodes. 359 cache : `lsst.pipe.base.Struct` 366 image : `lsst.afw.image.MaskedImage` 372 """Collect original image for visualisation 374 This method runs on the slave nodes. 378 cache : `lsst.pipe.base.Struct` 387 image : `lsst.afw.image.MaskedImage` 390 exposure = cache.butler.get(
"calexp", dataId, immediate=
True)
394 """Collect original image for visualisation 396 This method runs on the slave nodes. 400 cache : `lsst.pipe.base.Struct` 409 image : `lsst.afw.image.MaskedImage` 415 """Collect mask for visualisation 417 This method runs on the slave nodes. 421 cache : `lsst.pipe.base.Struct` 430 image : `lsst.afw.image.Image` 434 image = afwImage.ImageF(cache.exposure.maskedImage.getBBox())
435 image.array[:] = cache.exposure.maskedImage.mask.array
439 """Write resultant background list 441 This method runs on the slave nodes. 445 cache : `lsst.pipe.base.Struct` 450 cache.butler.put(cache.bgList,
"skyCorr", dataId)
452 def _getMetadataName(self):
453 """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)