lsst.pipe.drivers  21.0.0-2-ga63a54e+3d2c655db6
skyCorrection.py
Go to the documentation of this file.
1 # This file is part of pipe_drivers.
2 #
3 # Developed for the LSST Data Management System.
4 # This product includes software developed by the LSST Project
5 # (https://www.lsst.org).
6 # See the COPYRIGHT file at the top-level directory of this distribution
7 # for details of code ownership.
8 #
9 # This program is free software: you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation, either version 3 of the License, or
12 # (at your option) any later version.
13 #
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
18 #
19 # You should have received a copy of the GNU General Public License
20 # along with this program. If not, see <https://www.gnu.org/licenses/>.
21 import lsst.afw.math as afwMath
22 import lsst.afw.image as afwImage
23 import lsst.pipe.base as pipeBase
24 
25 from lsst.pipe.base import ArgumentParser, ConfigDatasetType
26 from lsst.pex.config import Config, Field, ConfigurableField, ConfigField
27 from lsst.ctrl.pool.pool import Pool
28 from lsst.ctrl.pool.parallel import BatchPoolTask
29 from lsst.pipe.drivers.background import (SkyMeasurementTask, FocalPlaneBackground,
30  FocalPlaneBackgroundConfig, MaskObjectsTask)
31 import lsst.pipe.drivers.visualizeVisit as visualizeVisit
33 
34 __all__ = ["SkyCorrectionConfig", "SkyCorrectionTask"]
35 
36 DEBUG = False # Debugging outputs?
37 
38 
39 def makeCameraImage(camera, exposures, filename=None, binning=8):
40  """Make and write an image of an entire focal plane
41 
42  Parameters
43  ----------
44  camera : `lsst.afw.cameraGeom.Camera`
45  Camera description.
46  exposures : `list` of `tuple` of `int` and `lsst.afw.image.Exposure`
47  List of detector ID and CCD exposures (binned by `binning`).
48  filename : `str`, optional
49  Output filename.
50  binning : `int`
51  Binning size that has been applied to images.
52  """
53  image = visualizeVisit.makeCameraImage(camera, dict(exp for exp in exposures if exp is not None), binning)
54  if filename is not None:
55  image.writeFits(filename)
56  return image
57 
58 
59 class SkyCorrectionConnections(pipeBase.PipelineTaskConnections, dimensions=("instrument", "visit")):
60  rawLinker = cT.Input(
61  doc="Raw data to provide exp-visit linkage to connect calExp inputs to camera/sky calibs.",
62  name="raw",
63  multiple=True,
64  deferLoad=True,
65  storageClass="ExposureU",
66  dimensions=["instrument", "exposure", "detector"],
67  )
68  calExpArray = cT.Input(
69  doc="Input exposures to process",
70  name="calexp",
71  multiple=True,
72  storageClass="ExposureF",
73  dimensions=["instrument", "visit", "detector"],
74  )
75  calBkgArray = cT.Input(
76  doc="Input background files to use",
77  multiple=True,
78  name="calexpBackground",
79  storageClass="Background",
80  dimensions=["instrument", "visit", "detector"],
81  )
82  camera = cT.PrerequisiteInput(
83  doc="Input camera to use.",
84  name="camera",
85  storageClass="Camera",
86  dimensions=["instrument", "calibration_label"],
87  )
88  skyCalibs = cT.PrerequisiteInput(
89  doc="Input sky calibrations to use.",
90  name="sky",
91  multiple=True,
92  storageClass="ExposureF",
93  dimensions=["instrument", "physical_filter", "detector", "calibration_label"],
94  )
95  calExpCamera = cT.Output(
96  doc="Output camera image.",
97  name='calexp_camera',
98  storageClass="ImageF",
99  dimensions=["instrument", "visit"],
100  )
101  skyCorr = cT.Output(
102  doc="Output sky corrected images.",
103  name='skyCorr',
104  multiple=True,
105  storageClass="Background",
106  dimensions=["instrument", "visit", "detector"],
107  )
108 
109 
110 class SkyCorrectionConfig(pipeBase.PipelineTaskConfig, pipelineConnections=SkyCorrectionConnections):
111  """Configuration for SkyCorrectionTask"""
112  bgModel = ConfigField(dtype=FocalPlaneBackgroundConfig, doc="Background model")
113  bgModel2 = ConfigField(dtype=FocalPlaneBackgroundConfig, doc="2nd Background model")
114  sky = ConfigurableField(target=SkyMeasurementTask, doc="Sky measurement")
115  maskObjects = ConfigurableField(target=MaskObjectsTask, doc="Mask Objects")
116  doMaskObjects = Field(dtype=bool, default=True, doc="Mask objects to find good sky?")
117  doBgModel = Field(dtype=bool, default=True, doc="Do background model subtraction?")
118  doBgModel2 = Field(dtype=bool, default=True, doc="Do cleanup background model subtraction?")
119  doSky = Field(dtype=bool, default=True, doc="Do sky frame subtraction?")
120  binning = Field(dtype=int, default=8, doc="Binning factor for constructing focal-plane images")
121  calexpType = Field(dtype=str, default="calexp",
122  doc="Should be set to fakes_calexp if you want to process calexps with fakes in.")
123 
124  def setDefaults(self):
125  Config.setDefaults(self)
126  self.bgModel2.doSmooth = True
127  self.bgModel2.minFrac = 0.5
128  self.bgModel2.xSize = 256
129  self.bgModel2.ySize = 256
130  self.bgModel2.smoothScale = 1.0
131 
132 
133 class SkyCorrectionTask(pipeBase.PipelineTask, BatchPoolTask):
134  """Correct sky over entire focal plane"""
135  ConfigClass = SkyCorrectionConfig
136  _DefaultName = "skyCorr"
137 
138  def runQuantum(self, butlerQC, inputRefs, outputRefs):
139  inputs = butlerQC.get(inputRefs)
140  inputs.pop("rawLinker", None)
141  outputs = self.run(**inputs)
142  butlerQC.put(outputs, outputRefs)
143 
144  def __init__(self, *args, **kwargs):
145  super().__init__(**kwargs)
146 
147  self.makeSubtask("sky")
148  self.makeSubtask("maskObjects")
149 
150  @classmethod
151  def _makeArgumentParser(cls, *args, **kwargs):
152  kwargs.pop("doBatch", False)
153  datasetType = ConfigDatasetType(name="calexpType")
154  parser = ArgumentParser(name="skyCorr", *args, **kwargs)
155  parser.add_id_argument("--id", datasetType=datasetType, level="visit",
156  help="data ID, e.g. --id visit=12345")
157  return parser
158 
159  @classmethod
160  def batchWallTime(cls, time, parsedCmd, numCores):
161  """Return walltime request for batch job
162 
163  Subclasses should override if the walltime should be calculated
164  differently (e.g., addition of some serial time).
165 
166  Parameters
167  ----------
168  time : `float`
169  Requested time per iteration.
170  parsedCmd : `argparse.Namespace`
171  Results of argument parsing.
172  numCores : `int`
173  Number of cores.
174  """
175  numTargets = len(cls.RunnerClass.getTargetList(parsedCmd))
176  return time*numTargets
177 
178  def runDataRef(self, expRef):
179  """Perform sky correction on an exposure
180 
181  We restore the original sky, and remove it again using multiple
182  algorithms. We optionally apply:
183 
184  1. A large-scale background model.
185  This step removes very-large-scale sky such as moonlight.
186  2. A sky frame.
187  3. A medium-scale background model.
188  This step removes residual sky (This is smooth on the focal plane).
189 
190  Only the master node executes this method. The data is held on
191  the slave nodes, which do all the hard work.
192 
193  Parameters
194  ----------
195  expRef : `lsst.daf.persistence.ButlerDataRef`
196  Data reference for exposure.
197 
198  See Also
199  --------
200  ~lsst.pipe.drivers.SkyCorrectionTask.run
201  """
202  if DEBUG:
203  extension = "-%(visit)d.fits" % expRef.dataId
204 
205  with self.logOperation("processing %s" % (expRef.dataId,)):
206  pool = Pool()
207  pool.cacheClear()
208  pool.storeSet(butler=expRef.getButler())
209  camera = expRef.get("camera")
210 
211  dataIdList = [ccdRef.dataId for ccdRef in expRef.subItems("ccd") if
212  ccdRef.datasetExists(self.config.calexpType)]
213 
214  exposures = pool.map(self.loadImage, dataIdList)
215  if DEBUG:
216  makeCameraImage(camera, exposures, "restored" + extension)
217  exposures = pool.mapToPrevious(self.collectOriginal, dataIdList)
218  makeCameraImage(camera, exposures, "original" + extension)
219  exposures = pool.mapToPrevious(self.collectMask, dataIdList)
220  makeCameraImage(camera, exposures, "mask" + extension)
221 
222  if self.config.doBgModel:
223  exposures = self.focalPlaneBackground(camera, pool, dataIdList, self.config.bgModel)
224 
225  if self.config.doSky:
226  measScales = pool.mapToPrevious(self.measureSkyFrame, dataIdList)
227  scale = self.sky.solveScales(measScales)
228  self.log.info("Sky frame scale: %s" % (scale,))
229 
230  exposures = pool.mapToPrevious(self.subtractSkyFrame, dataIdList, scale)
231  if DEBUG:
232  makeCameraImage(camera, exposures, "skysub" + extension)
233  calibs = pool.mapToPrevious(self.collectSky, dataIdList)
234  makeCameraImage(camera, calibs, "sky" + extension)
235 
236  if self.config.doBgModel2:
237  exposures = self.focalPlaneBackground(camera, pool, dataIdList, self.config.bgModel2)
238 
239  # Persist camera-level image of calexp
240  image = makeCameraImage(camera, exposures)
241  expRef.put(image, "calexp_camera")
242 
243  pool.mapToPrevious(self.write, dataIdList)
244 
245  def focalPlaneBackground(self, camera, pool, dataIdList, config):
246  """Perform full focal-plane background subtraction
247 
248  This method runs on the master node.
249 
250  Parameters
251  ----------
252  camera : `lsst.afw.cameraGeom.Camera`
253  Camera description.
254  pool : `lsst.ctrl.pool.Pool`
255  Process pool.
256  dataIdList : iterable of `dict`
257  List of data identifiers for the CCDs.
258  config : `lsst.pipe.drivers.background.FocalPlaneBackgroundConfig`
259  Configuration to use for background subtraction.
260 
261  Returns
262  -------
263  exposures : `list` of `lsst.afw.image.Image`
264  List of binned images, for creating focal plane image.
265  """
266  bgModel = FocalPlaneBackground.fromCamera(config, camera)
267  data = [pipeBase.Struct(dataId=dataId, bgModel=bgModel.clone()) for dataId in dataIdList]
268  bgModelList = pool.mapToPrevious(self.accumulateModel, data)
269  for ii, bg in enumerate(bgModelList):
270  self.log.info("Background %d: %d pixels", ii, bg._numbers.array.sum())
271  bgModel.merge(bg)
272  return pool.mapToPrevious(self.subtractModel, dataIdList, bgModel)
273 
274  def focalPlaneBackgroundRun(self, camera, cacheExposures, idList, config):
275  """Perform full focal-plane background subtraction
276 
277  This method runs on the master node.
278 
279  Parameters
280  ----------
281  camera : `lsst.afw.cameraGeom.Camera`
282  Camera description.
283  cacheExposures : `list` of `lsst.afw.image.Exposures`
284  List of loaded and processed input calExp.
285  idList : `list` of `int`
286  List of detector ids to iterate over.
287  config : `lsst.pipe.drivers.background.FocalPlaneBackgroundConfig`
288  Configuration to use for background subtraction.
289 
290  Returns
291  -------
292  exposures : `list` of `lsst.afw.image.Image`
293  List of binned images, for creating focal plane image.
294  newCacheBgList : `list` of `lsst.afwMath.backgroundList`
295  Background lists generated.
296  cacheBgModel : `FocalPlaneBackground`
297  Full focal plane background model.
298  """
299  bgModel = FocalPlaneBackground.fromCamera(config, camera)
300  data = [pipeBase.Struct(id=id, bgModel=bgModel.clone()) for id in idList]
301 
302  bgModelList = []
303  for nodeData, cacheExp in zip(data, cacheExposures):
304  nodeData.bgModel.addCcd(cacheExp)
305  bgModelList.append(nodeData.bgModel)
306 
307  for ii, bg in enumerate(bgModelList):
308  self.log.info("Background %d: %d pixels", ii, bg._numbers.getArray().sum())
309  bgModel.merge(bg)
310 
311  exposures = []
312  newCacheBgList = []
313  cacheBgModel = []
314  for cacheExp in cacheExposures:
315  nodeExp, nodeBgModel, nodeBgList = self.subtractModelRun(cacheExp, bgModel)
316  exposures.append(afwMath.binImage(nodeExp.getMaskedImage(), self.config.binning))
317  cacheBgModel.append(nodeBgModel)
318  newCacheBgList.append(nodeBgList)
319 
320  return exposures, newCacheBgList, cacheBgModel
321 
322  def run(self, calExpArray, calBkgArray, skyCalibs, camera):
323  """Duplicate runDataRef method without ctrl_pool for Gen3.
324 
325  Parameters
326  ----------
327  calExpArray : `list` of `lsst.afw.image.Exposure`
328  Array of detector input calExp images for the exposure to
329  process.
330  calBkgArray : `list` of `lsst.afw.math.BackgroundList`
331  Array of detector input background lists matching the
332  calExps to process.
333  skyCalibs : `list` of `lsst.afw.image.Exposure`
334  Array of SKY calibrations for the input detectors to be
335  processed.
336  camera : `lsst.afw.cameraGeom.Camera`
337  Camera matching the input data to process.
338 
339  Returns
340  -------
341  results : `pipeBase.Struct` containing
342  calExpCamera : `lsst.afw.image.Exposure`
343  Full camera image of the sky-corrected data.
344  skyCorr : `list` of `lsst.afw.math.BackgroundList`
345  Detector-level sky-corrected background lists.
346 
347  See Also
348  --------
349  ~lsst.pipe.drivers.SkyCorrectionTask.runDataRef()
350  """
351  # To allow SkyCorrectionTask to run in the Gen3 butler
352  # environment, a new run() method was added that performs the
353  # same operations in a serial environment (pipetask processing
354  # does not support MPI processing as of 2019-05-03). Methods
355  # used in runDataRef() are used as appropriate in run(), but
356  # some have been rewritten in serial form. Please ensure that
357  # any updates to runDataRef() or the methods it calls with
358  # pool.mapToPrevious() are duplicated in run() and its
359  # methods.
360  #
361  # Variable names here should match those in runDataRef() as
362  # closely as possible. Variables matching data stored in the
363  # pool cache have a prefix indicating this. Variables that
364  # would be local to an MPI processing client have a prefix
365  # "node".
366  idList = [exp.getDetector().getId() for exp in calExpArray]
367 
368  # Construct arrays that match the cache in self.runDataRef() after
369  # self.loadImage() is map/reduced.
370  cacheExposures = []
371  cacheBgList = []
372  exposures = []
373  for calExp, calBgModel in zip(calExpArray, calBkgArray):
374  nodeExp, nodeBgList = self.loadImageRun(calExp, calBgModel)
375  cacheExposures.append(nodeExp)
376  cacheBgList.append(nodeBgList)
377  exposures.append(afwMath.binImage(nodeExp.getMaskedImage(), self.config.binning))
378 
379  if self.config.doBgModel:
380  # Generate focal plane background, updating backgrounds in the "cache".
381  exposures, newCacheBgList, cacheBgModel = self.focalPlaneBackgroundRun(
382  camera, cacheExposures, idList, self.config.bgModel
383  )
384  for cacheBg, newBg in zip(cacheBgList, newCacheBgList):
385  cacheBg.append(newBg)
386 
387  if self.config.doSky:
388  # Measure the sky frame scale on all inputs. Results in
389  # values equal to self.measureSkyFrame() and
390  # self.sky.solveScales() in runDataRef().
391  cacheSky = []
392  measScales = []
393  for cacheExp, skyCalib in zip(cacheExposures, skyCalibs):
394  skyExp = self.sky.exposureToBackground(skyCalib)
395  cacheSky.append(skyExp)
396  scale = self.sky.measureScale(cacheExp.getMaskedImage(), skyExp)
397  measScales.append(scale)
398 
399  scale = self.sky.solveScales(measScales)
400  self.log.info("Sky frame scale: %s" % (scale, ))
401 
402  # Subtract sky frame, as in self.subtractSkyFrame(), with
403  # appropriate scale from the "cache".
404  exposures = []
405  newBgList = []
406  for cacheExp, nodeSky, nodeBgList in zip(cacheExposures, cacheSky, cacheBgList):
407  self.sky.subtractSkyFrame(cacheExp.getMaskedImage(), nodeSky, scale, nodeBgList)
408  exposures.append(afwMath.binImage(cacheExp.getMaskedImage(), self.config.binning))
409 
410  if self.config.doBgModel2:
411  # As above, generate a focal plane background model and
412  # update the cache models.
413  exposures, newBgList, cacheBgModel = self.focalPlaneBackgroundRun(
414  camera, cacheExposures, idList, self.config.bgModel2
415  )
416  for cacheBg, newBg in zip(cacheBgList, newBgList):
417  cacheBg.append(newBg)
418 
419  # Generate camera-level image of calexp and return it along
420  # with the list of sky corrected background models.
421  image = makeCameraImage(camera, zip(idList, exposures))
422 
423  return pipeBase.Struct(
424  calExpCamera=image,
425  skyCorr=cacheBgList,
426  )
427 
428  def loadImage(self, cache, dataId):
429  """Load original image and restore the sky
430 
431  This method runs on the slave nodes.
432 
433  Parameters
434  ----------
435  cache : `lsst.pipe.base.Struct`
436  Process pool cache.
437  dataId : `dict`
438  Data identifier.
439 
440  Returns
441  -------
442  exposure : `lsst.afw.image.Exposure`
443  Resultant exposure.
444  """
445  cache.dataId = dataId
446  cache.exposure = cache.butler.get(self.config.calexpType, dataId, immediate=True).clone()
447  bgOld = cache.butler.get("calexpBackground", dataId, immediate=True)
448  image = cache.exposure.getMaskedImage()
449 
450  # We're removing the old background, so change the sense of all its components
451  for bgData in bgOld:
452  statsImage = bgData[0].getStatsImage()
453  statsImage *= -1
454 
455  image -= bgOld.getImage()
456  cache.bgList = afwMath.BackgroundList()
457  for bgData in bgOld:
458  cache.bgList.append(bgData)
459 
460  if self.config.doMaskObjects:
461  self.maskObjects.findObjects(cache.exposure)
462 
463  return self.collect(cache)
464 
465  def loadImageRun(self, calExp, calExpBkg):
466  """Serial implementation of self.loadImage() for Gen3.
467 
468  Load and restore background to calExp and calExpBkg.
469 
470  Parameters
471  ----------
472  calExp : `lsst.afw.image.Exposure`
473  Detector level calExp image to process.
474  calExpBkg : `lsst.afw.math.BackgroundList`
475  Detector level background list associated with the calExp.
476 
477  Returns
478  -------
479  calExp : `lsst.afw.image.Exposure`
480  Background restored calExp.
481  bgList : `lsst.afw.math.BackgroundList`
482  New background list containing the restoration background.
483  """
484  image = calExp.getMaskedImage()
485 
486  for bgOld in calExpBkg:
487  statsImage = bgOld[0].getStatsImage()
488  statsImage *= -1
489 
490  image -= calExpBkg.getImage()
491  bgList = afwMath.BackgroundList()
492  for bgData in calExpBkg:
493  bgList.append(bgData)
494 
495  if self.config.doMaskObjects:
496  self.maskObjects.findObjects(calExp)
497 
498  return (calExp, bgList)
499 
500  def measureSkyFrame(self, cache, dataId):
501  """Measure scale for sky frame
502 
503  This method runs on the slave nodes.
504 
505  Parameters
506  ----------
507  cache : `lsst.pipe.base.Struct`
508  Process pool cache.
509  dataId : `dict`
510  Data identifier.
511 
512  Returns
513  -------
514  scale : `float`
515  Scale for sky frame.
516  """
517  assert cache.dataId == dataId
518  cache.sky = self.sky.getSkyData(cache.butler, dataId)
519  scale = self.sky.measureScale(cache.exposure.getMaskedImage(), cache.sky)
520  return scale
521 
522  def subtractSkyFrame(self, cache, dataId, scale):
523  """Subtract sky frame
524 
525  This method runs on the slave nodes.
526 
527  Parameters
528  ----------
529  cache : `lsst.pipe.base.Struct`
530  Process pool cache.
531  dataId : `dict`
532  Data identifier.
533  scale : `float`
534  Scale for sky frame.
535 
536  Returns
537  -------
538  exposure : `lsst.afw.image.Exposure`
539  Resultant exposure.
540  """
541  assert cache.dataId == dataId
542  self.sky.subtractSkyFrame(cache.exposure.getMaskedImage(), cache.sky, scale, cache.bgList)
543  return self.collect(cache)
544 
545  def accumulateModel(self, cache, data):
546  """Fit background model for CCD
547 
548  This method runs on the slave nodes.
549 
550  Parameters
551  ----------
552  cache : `lsst.pipe.base.Struct`
553  Process pool cache.
554  data : `lsst.pipe.base.Struct`
555  Data identifier, with `dataId` (data identifier) and `bgModel`
556  (background model) elements.
557 
558  Returns
559  -------
560  bgModel : `lsst.pipe.drivers.background.FocalPlaneBackground`
561  Background model.
562  """
563  assert cache.dataId == data.dataId
564  data.bgModel.addCcd(cache.exposure)
565  return data.bgModel
566 
567  def subtractModel(self, cache, dataId, bgModel):
568  """Subtract background model
569 
570  This method runs on the slave nodes.
571 
572  Parameters
573  ----------
574  cache : `lsst.pipe.base.Struct`
575  Process pool cache.
576  dataId : `dict`
577  Data identifier.
578  bgModel : `lsst.pipe.drivers.background.FocalPlaneBackround`
579  Background model.
580 
581  Returns
582  -------
583  exposure : `lsst.afw.image.Exposure`
584  Resultant exposure.
585  """
586  assert cache.dataId == dataId
587  exposure = cache.exposure
588  image = exposure.getMaskedImage()
589  detector = exposure.getDetector()
590  bbox = image.getBBox()
591  try:
592  cache.bgModel = bgModel.toCcdBackground(detector, bbox)
593  image -= cache.bgModel.getImage()
594  except RuntimeError:
595  self.log.error(f"There was an error processing {dataId}, no calib file produced")
596  return
597  cache.bgList.append(cache.bgModel[0])
598  return self.collect(cache)
599 
600  def subtractModelRun(self, exposure, bgModel):
601  """Serial implementation of self.subtractModel() for Gen3.
602 
603  Load and restore background to calExp and calExpBkg.
604 
605  Parameters
606  ----------
607  exposure : `lsst.afw.image.Exposure`
608  Exposure to subtract the background model from.
609  bgModel : `lsst.pipe.drivers.background.FocalPlaneBackground`
610  Full camera level background model.
611 
612  Returns
613  -------
614  exposure : `lsst.afw.image.Exposure`
615  Background subtracted input exposure.
616  bgModelCcd : `lsst.afw.math.BackgroundList`
617  Detector level realization of the full background model.
618  bgModelMaskedImage : `lsst.afw.image.MaskedImage`
619  Background model from the bgModelCcd realization.
620  """
621  image = exposure.getMaskedImage()
622  detector = exposure.getDetector()
623  bbox = image.getBBox()
624  bgModelCcd = bgModel.toCcdBackground(detector, bbox)
625  image -= bgModelCcd.getImage()
626 
627  return (exposure, bgModelCcd, bgModelCcd[0])
628 
629  def realiseModel(self, cache, dataId, bgModel):
630  """Generate an image of the background model for visualisation
631 
632  Useful for debugging.
633 
634  Parameters
635  ----------
636  cache : `lsst.pipe.base.Struct`
637  Process pool cache.
638  dataId : `dict`
639  Data identifier.
640  bgModel : `lsst.pipe.drivers.background.FocalPlaneBackround`
641  Background model.
642 
643  Returns
644  -------
645  detId : `int`
646  Detector identifier.
647  image : `lsst.afw.image.MaskedImage`
648  Binned background model image.
649  """
650  assert cache.dataId == dataId
651  exposure = cache.exposure
652  detector = exposure.getDetector()
653  bbox = exposure.getMaskedImage().getBBox()
654  image = bgModel.toCcdBackground(detector, bbox).getImage()
655  return self.collectBinnedImage(exposure, image)
656 
657  def collectBinnedImage(self, exposure, image):
658  """Return the binned image required for visualization
659 
660  This method just helps to cut down on boilerplate.
661 
662  Parameters
663  ----------
664  image : `lsst.afw.image.MaskedImage`
665  Image to go into visualisation.
666 
667  Returns
668  -------
669  detId : `int`
670  Detector identifier.
671  image : `lsst.afw.image.MaskedImage`
672  Binned image.
673  """
674  return (exposure.getDetector().getId(), afwMath.binImage(image, self.config.binning))
675 
676  def collect(self, cache):
677  """Collect exposure for potential visualisation
678 
679  This method runs on the slave nodes.
680 
681  Parameters
682  ----------
683  cache : `lsst.pipe.base.Struct`
684  Process pool cache.
685 
686  Returns
687  -------
688  detId : `int`
689  Detector identifier.
690  image : `lsst.afw.image.MaskedImage`
691  Binned image.
692  """
693  return self.collectBinnedImage(cache.exposure, cache.exposure.maskedImage)
694 
695  def collectOriginal(self, cache, dataId):
696  """Collect original image for visualisation
697 
698  This method runs on the slave nodes.
699 
700  Parameters
701  ----------
702  cache : `lsst.pipe.base.Struct`
703  Process pool cache.
704  dataId : `dict`
705  Data identifier.
706 
707  Returns
708  -------
709  detId : `int`
710  Detector identifier.
711  image : `lsst.afw.image.MaskedImage`
712  Binned image.
713  """
714  exposure = cache.butler.get("calexp", dataId, immediate=True)
715  return self.collectBinnedImage(exposure, exposure.maskedImage)
716 
717  def collectSky(self, cache, dataId):
718  """Collect original image for visualisation
719 
720  This method runs on the slave nodes.
721 
722  Parameters
723  ----------
724  cache : `lsst.pipe.base.Struct`
725  Process pool cache.
726  dataId : `dict`
727  Data identifier.
728 
729  Returns
730  -------
731  detId : `int`
732  Detector identifier.
733  image : `lsst.afw.image.MaskedImage`
734  Binned image.
735  """
736  return self.collectBinnedImage(cache.exposure, cache.sky.getImage())
737 
738  def collectMask(self, cache, dataId):
739  """Collect mask for visualisation
740 
741  This method runs on the slave nodes.
742 
743  Parameters
744  ----------
745  cache : `lsst.pipe.base.Struct`
746  Process pool cache.
747  dataId : `dict`
748  Data identifier.
749 
750  Returns
751  -------
752  detId : `int`
753  Detector identifier.
754  image : `lsst.afw.image.Image`
755  Binned image.
756  """
757  # Convert Mask to floating-point image, because that's what's required for focal plane construction
758  image = afwImage.ImageF(cache.exposure.maskedImage.getBBox())
759  image.array[:] = cache.exposure.maskedImage.mask.array
760  return self.collectBinnedImage(cache.exposure, image)
761 
762  def write(self, cache, dataId):
763  """Write resultant background list
764 
765  This method runs on the slave nodes.
766 
767  Parameters
768  ----------
769  cache : `lsst.pipe.base.Struct`
770  Process pool cache.
771  dataId : `dict`
772  Data identifier.
773  """
774  cache.butler.put(cache.bgList, "skyCorr", dataId)
775 
776  def _getMetadataName(self):
777  """There's no metadata to write out"""
778  return None
lsst::afw::image
lsst.pipe.drivers.skyCorrection.SkyCorrectionTask.runDataRef
def runDataRef(self, expRef)
Definition: skyCorrection.py:178
lsst.pipe.drivers.skyCorrection.SkyCorrectionTask.loadImageRun
def loadImageRun(self, calExp, calExpBkg)
Definition: skyCorrection.py:465
lsst.pipe.drivers.skyCorrection.SkyCorrectionTask.runQuantum
def runQuantum(self, butlerQC, inputRefs, outputRefs)
Definition: skyCorrection.py:138
lsst.pipe.drivers.skyCorrection.SkyCorrectionTask.subtractModelRun
def subtractModelRun(self, exposure, bgModel)
Definition: skyCorrection.py:600
lsst.pipe.drivers.background
Definition: background.py:1
lsst.pipe.drivers.skyCorrection.makeCameraImage
def makeCameraImage(camera, exposures, filename=None, binning=8)
Definition: skyCorrection.py:39
lsst.pipe.drivers.skyCorrection.SkyCorrectionConfig.setDefaults
def setDefaults(self)
Definition: skyCorrection.py:124
lsst.pipe.drivers.skyCorrection.SkyCorrectionTask.loadImage
def loadImage(self, cache, dataId)
Definition: skyCorrection.py:428
lsst.pipe.drivers.skyCorrection.SkyCorrectionTask.collectOriginal
def collectOriginal(self, cache, dataId)
Definition: skyCorrection.py:695
lsst.pipe.drivers.skyCorrection.SkyCorrectionTask.accumulateModel
def accumulateModel(self, cache, data)
Definition: skyCorrection.py:545
lsst::ctrl::pool::parallel
lsst.pipe.drivers.skyCorrection.SkyCorrectionTask.batchWallTime
def batchWallTime(cls, time, parsedCmd, numCores)
Definition: skyCorrection.py:160
lsst.pipe.drivers.skyCorrection.SkyCorrectionTask.collectBinnedImage
def collectBinnedImage(self, exposure, image)
Definition: skyCorrection.py:657
lsst.pipe.drivers.skyCorrection.SkyCorrectionTask.run
def run(self, calExpArray, calBkgArray, skyCalibs, camera)
Definition: skyCorrection.py:322
lsst.pipe.drivers.visualizeVisit
Definition: visualizeVisit.py:1
lsst.pipe.drivers.skyCorrection.SkyCorrectionTask.__init__
def __init__(self, *args, **kwargs)
Definition: skyCorrection.py:144
lsst::ctrl::pool::parallel::BatchCmdLineTask::logOperation
def logOperation(self, operation, catch=False, trace=True)
lsst.pipe.drivers.skyCorrection.SkyCorrectionTask.measureSkyFrame
def measureSkyFrame(self, cache, dataId)
Definition: skyCorrection.py:500
lsst::pex::config
lsst.pipe.drivers.skyCorrection.SkyCorrectionTask.subtractSkyFrame
def subtractSkyFrame(self, cache, dataId, scale)
Definition: skyCorrection.py:522
lsst.pipe.drivers.skyCorrection.SkyCorrectionConfig.bgModel2
bgModel2
Definition: skyCorrection.py:113
lsst.pipe.drivers.skyCorrection.SkyCorrectionTask.focalPlaneBackgroundRun
def focalPlaneBackgroundRun(self, camera, cacheExposures, idList, config)
Definition: skyCorrection.py:274
lsst::ctrl::pool::pool
lsst.pipe.drivers.skyCorrection.SkyCorrectionTask.collectMask
def collectMask(self, cache, dataId)
Definition: skyCorrection.py:738
lsst::ctrl::pool::pool::Pool
lsst.pipe.drivers.skyCorrection.SkyCorrectionTask.collectSky
def collectSky(self, cache, dataId)
Definition: skyCorrection.py:717
lsst::ctrl::pool::parallel::BatchPoolTask
lsst::afw::math
lsst.pipe.drivers.skyCorrection.SkyCorrectionTask.subtractModel
def subtractModel(self, cache, dataId, bgModel)
Definition: skyCorrection.py:567
lsst.pipe.drivers.skyCorrection.SkyCorrectionConnections
Definition: skyCorrection.py:59
lsst.pipe::base
lsst.pipe.drivers.skyCorrection.SkyCorrectionTask.realiseModel
def realiseModel(self, cache, dataId, bgModel)
Definition: skyCorrection.py:629
lsst.pipe.drivers.skyCorrection.SkyCorrectionConfig
Definition: skyCorrection.py:110
lsst.pipe.drivers.skyCorrection.SkyCorrectionTask
Definition: skyCorrection.py:133
lsst.pipe.drivers.skyCorrection.SkyCorrectionTask.focalPlaneBackground
def focalPlaneBackground(self, camera, pool, dataIdList, config)
Definition: skyCorrection.py:245
lsst.pipe.drivers.skyCorrection.SkyCorrectionTask.collect
def collect(self, cache)
Definition: skyCorrection.py:676
lsst.pipe.drivers.skyCorrection.SkyCorrectionTask.write
def write(self, cache, dataId)
Definition: skyCorrection.py:762
lsst.pipe::base::connectionTypes