lsst.pipe.tasks gcd254cd47f+c028490dc5
Loading...
Searching...
No Matches
skyCorrection.py
Go to the documentation of this file.
1# This file is part of pipe_tasks.
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
22__all__ = ["SkyCorrectionTask", "SkyCorrectionConfig"]
23
24import warnings
25
26import lsst.afw.image as afwImage
27import lsst.afw.math as afwMath
28import lsst.pipe.base.connectionTypes as cT
29import numpy as np
30from lsst.daf.butler import DimensionGraph
31from lsst.pex.config import Config, ConfigField, ConfigurableField, Field, FieldValidationError
32from lsst.pipe.base import PipelineTask, PipelineTaskConfig, PipelineTaskConnections, Struct
34 FocalPlaneBackground,
35 FocalPlaneBackgroundConfig,
36 MaskObjectsTask,
37 SkyMeasurementTask,
38)
39from lsst.pipe.tasks.visualizeVisit import VisualizeMosaicExpConfig, VisualizeMosaicExpTask
40
41
42def _skyFrameLookup(datasetType, registry, quantumDataId, collections):
43 """Lookup function to identify sky frames.
44
45 Parameters
46 ----------
47 datasetType : `lsst.daf.butler.DatasetType`
48 Dataset to lookup.
49 registry : `lsst.daf.butler.Registry`
50 Butler registry to query.
51 quantumDataId : `lsst.daf.butler.DataCoordinate`
52 Data id to transform to find sky frames.
53 The ``detector`` entry will be stripped.
54 collections : `lsst.daf.butler.CollectionSearch`
55 Collections to search through.
56
57 Returns
58 -------
59 results : `list` [`lsst.daf.butler.DatasetRef`]
60 List of datasets that will be used as sky calibration frames.
61 """
62 newDataId = quantumDataId.subset(DimensionGraph(registry.dimensions, names=["instrument", "visit"]))
63 skyFrames = []
64 for dataId in registry.queryDataIds(["visit", "detector"], dataId=newDataId).expanded():
65 skyFrame = registry.findDataset(
66 datasetType, dataId, collections=collections, timespan=dataId.timespan
67 )
68 skyFrames.append(skyFrame)
69 return skyFrames
70
71
72def _reorderAndPadList(inputList, inputKeys, outputKeys, padWith=None):
73 """Match the order of one list to another, padding if necessary.
74
75 Parameters
76 ----------
77 inputList : `list`
78 List to be reordered and padded. Elements can be any type.
79 inputKeys : iterable
80 Iterable of values to be compared with outputKeys.
81 Length must match `inputList`.
82 outputKeys : iterable
83 Iterable of values to be compared with inputKeys.
84 padWith :
85 Any value to be inserted where one of inputKeys is not in outputKeys.
86
87 Returns
88 -------
89 outputList : `list`
90 Copy of inputList reordered per outputKeys and padded with `padWith`
91 so that the length matches length of outputKeys.
92 """
93 outputList = []
94 for outputKey in outputKeys:
95 if outputKey in inputKeys:
96 outputList.append(inputList[inputKeys.index(outputKey)])
97 else:
98 outputList.append(padWith)
99 return outputList
100
101
102class SkyCorrectionConnections(PipelineTaskConnections, dimensions=("instrument", "visit")):
103 rawLinker = cT.Input(
104 doc="Raw data to provide exp-visit linkage to connect calExp inputs to camera/sky calibs.",
105 name="raw",
106 multiple=True,
107 deferLoad=True,
108 storageClass="Exposure",
109 dimensions=["instrument", "exposure", "detector"],
110 )
111 calExps = cT.Input(
112 doc="Background-subtracted calibrated exposures.",
113 name="calexp",
114 multiple=True,
115 storageClass="ExposureF",
116 dimensions=["instrument", "visit", "detector"],
117 )
118 calBkgs = cT.Input(
119 doc="Subtracted backgrounds for input calibrated exposures.",
120 multiple=True,
121 name="calexpBackground",
122 storageClass="Background",
123 dimensions=["instrument", "visit", "detector"],
124 )
125 skyFrames = cT.PrerequisiteInput(
126 doc="Calibration sky frames.",
127 name="sky",
128 multiple=True,
129 storageClass="ExposureF",
130 dimensions=["instrument", "physical_filter", "detector"],
131 isCalibration=True,
132 lookupFunction=_skyFrameLookup,
133 )
134 camera = cT.PrerequisiteInput(
135 doc="Input camera.",
136 name="camera",
137 storageClass="Camera",
138 dimensions=["instrument"],
139 isCalibration=True,
140 )
141 skyCorr = cT.Output(
142 doc="Sky correction data, to be subtracted from the calibrated exposures.",
143 name="skyCorr",
144 multiple=True,
145 storageClass="Background",
146 dimensions=["instrument", "visit", "detector"],
147 )
148 calExpMosaic = cT.Output(
149 doc="Full focal plane mosaicked image of the sky corrected calibrated exposures.",
150 name="calexp_skyCorr_visit_mosaic",
151 storageClass="ImageF",
152 dimensions=["instrument", "visit"],
153 )
154 calBkgMosaic = cT.Output(
155 doc="Full focal plane mosaicked image of the sky corrected calibrated exposure backgrounds.",
156 name="calexpBackground_skyCorr_visit_mosaic",
157 storageClass="ImageF",
158 dimensions=["instrument", "visit"],
159 )
160
161
162class SkyCorrectionConfig(PipelineTaskConfig, pipelineConnections=SkyCorrectionConnections):
163 maskObjects = ConfigurableField(
164 target=MaskObjectsTask,
165 doc="Mask Objects",
166 )
167 doMaskObjects = Field(
168 dtype=bool,
169 default=True,
170 doc="Iteratively mask objects to find good sky?",
171 )
172 bgModel = ConfigField(
173 dtype=Config,
174 doc="Initial background model, prior to sky frame subtraction",
175 deprecated="This field is deprecated and will be removed after v26. Please use bgModel1 instead.",
176 )
177 doBgModel = Field(
178 dtype=bool,
179 default=None,
180 doc="Do initial background model subtraction (prior to sky frame subtraction)?",
181 optional=True,
182 deprecated="This field is deprecated and will be removed after v26. See RFC-898 for further details.",
183 )
184 bgModel1 = ConfigField(
185 dtype=FocalPlaneBackgroundConfig,
186 doc="Initial background model, prior to sky frame subtraction",
187 )
188 doBgModel1 = Field(
189 dtype=bool,
190 default=True,
191 doc="Do initial background model subtraction (prior to sky frame subtraction)?",
192 deprecated="This field is deprecated and will be removed after v26. See RFC-898 for further details.",
193 )
194 sky = ConfigurableField(
195 target=SkyMeasurementTask,
196 doc="Sky measurement",
197 )
198 doSky = Field(
199 dtype=bool,
200 default=True,
201 doc="Do sky frame subtraction?",
202 )
203 bgModel2 = ConfigField(
204 dtype=FocalPlaneBackgroundConfig,
205 doc="Final (cleanup) background model, after sky frame subtraction",
206 )
207 doBgModel2 = Field(
208 dtype=bool,
209 default=True,
210 doc="Do final (cleanup) background model subtraction, after sky frame subtraction?",
211 )
212 binning = Field(
213 dtype=int,
214 default=8,
215 doc="Binning factor for constructing full focal plane '*_camera' output datasets",
216 )
217
218 def setDefaults(self):
219 Config.setDefaults(self)
220 self.bgModel2.doSmooth = True
221 self.bgModel2.minFrac = 0.5
222 self.bgModel2.xSize = 256
223 self.bgModel2.ySize = 256
224 self.bgModel2.smoothScale = 1.0
225
226 def validate(self):
227 # TODO: Entire validate method may be removed after v26 (a la DM-37242)
228 super().validate()
229 if self.doBgModel is not None and self.doBgModel != self.doBgModel1:
230 msg = "The doBgModel field will be removed after v26."
231 raise FieldValidationError(self.__class__.doBgModel, self, msg)
232
233
234class SkyCorrectionTask(PipelineTask):
235 """Perform a full focal plane sky correction."""
236
237 ConfigClass = SkyCorrectionConfig
238 _DefaultName = "skyCorr"
239
240 def __init__(self, *args, **kwargs):
241 super().__init__(**kwargs)
242 self.makeSubtask("sky")
243 self.makeSubtask("maskObjects")
244
245 def runQuantum(self, butlerQC, inputRefs, outputRefs):
246 # Sort the calExps, calBkgs and skyFrames inputRefs and the
247 # skyCorr outputRef by detector ID to ensure reproducibility.
248 detectorOrder = [ref.dataId["detector"] for ref in inputRefs.calExps]
249 detectorOrder.sort()
250 inputRefs.calExps = _reorderAndPadList(
251 inputRefs.calExps, [ref.dataId["detector"] for ref in inputRefs.calExps], detectorOrder
252 )
253 inputRefs.calBkgs = _reorderAndPadList(
254 inputRefs.calBkgs, [ref.dataId["detector"] for ref in inputRefs.calBkgs], detectorOrder
255 )
256 inputRefs.skyFrames = _reorderAndPadList(
257 inputRefs.skyFrames, [ref.dataId["detector"] for ref in inputRefs.skyFrames], detectorOrder
258 )
259 outputRefs.skyCorr = _reorderAndPadList(
260 outputRefs.skyCorr, [ref.dataId["detector"] for ref in outputRefs.skyCorr], detectorOrder
261 )
262 inputs = butlerQC.get(inputRefs)
263 inputs.pop("rawLinker", None)
264 outputs = self.run(**inputs)
265 butlerQC.put(outputs, outputRefs)
266
267 def run(self, calExps, calBkgs, skyFrames, camera):
268 """Perform sky correction on a visit.
269
270 The original visit-level background is first restored to the calibrated
271 exposure and the existing background model is inverted in-place. If
272 doMaskObjects is True, the mask map associated with this exposure will
273 be iteratively updated (over nIter loops) by re-estimating the
274 background each iteration and redetecting footprints.
275
276 If doBgModel1 is True, an initial full focal plane sky subtraction will
277 take place prior to scaling and subtracting the sky frame.
278
279 If doSky is True, the sky frame will be scaled to the flux in the input
280 visit.
281
282 If doBgModel2 is True, a final full focal plane sky subtraction will
283 take place after the sky frame has been subtracted.
284
285 The first N elements of the returned skyCorr will consist of inverted
286 elements of the calexpBackground model (i.e., subtractive). All
287 subsequent elements appended to skyCorr thereafter will be additive
288 such that, when skyCorr is subtracted from a calexp, the net result
289 will be to undo the initial per-detector background solution and then
290 apply the skyCorr model thereafter. Adding skyCorr to a
291 calexpBackground will effectively negate the calexpBackground,
292 returning only the additive background components of the skyCorr
293 background model.
294
295 Parameters
296 ----------
297 calExps : `list` [`lsst.afw.image.exposure.ExposureF`]
298 Detector calibrated exposure images for the visit.
299 calBkgs : `list` [`lsst.afw.math.BackgroundList`]
300 Detector background lists matching the calibrated exposures.
301 skyFrames : `list` [`lsst.afw.image.exposure.ExposureF`]
302 Sky frame calibration data for the input detectors.
303 camera : `lsst.afw.cameraGeom.Camera`
304 Camera matching the input data to process.
305
306 Returns
307 -------
308 results : `Struct` containing:
309 skyCorr : `list` [`lsst.afw.math.BackgroundList`]
310 Detector-level sky correction background lists.
311 calExpMosaic : `lsst.afw.image.exposure.ExposureF`
312 Visit-level mosaic of the sky corrected data, binned.
313 Analogous to `calexp - skyCorr`.
314 calBkgMosaic : `lsst.afw.image.exposure.ExposureF`
315 Visit-level mosaic of the sky correction background, binned.
316 Analogous to `calexpBackground + skyCorr`.
317 """
318 # Restore original backgrounds in-place; optionally refine mask maps
319 numOrigBkgElements = [len(calBkg) for calBkg in calBkgs]
320 _ = self._restoreBackgroundRefineMask(calExps, calBkgs)
321
322 # Bin exposures, generate full-fp bg, map to CCDs and subtract in-place
323 if self.config.doBgModel1:
324 _ = self._subtractVisitBackground(calExps, calBkgs, camera, self.config.bgModel1)
325
326 # Subtract a scaled sky frame from all input exposures
327 if self.config.doSky:
328 self._subtractSkyFrame(calExps, skyFrames, calBkgs)
329
330 # Bin exposures, generate full-fp bg, map to CCDs and subtract in-place
331 if self.config.doBgModel2:
332 _ = self._subtractVisitBackground(calExps, calBkgs, camera, self.config.bgModel2)
333
334 # Make camera-level images of bg subtracted calexps and subtracted bgs
335 calExpIds = [exp.getDetector().getId() for exp in calExps]
336 skyCorrExtras = []
337 for calBkg, num in zip(calBkgs, numOrigBkgElements):
338 skyCorrExtra = calBkg.clone()
339 skyCorrExtra._backgrounds = skyCorrExtra._backgrounds[num:]
340 skyCorrExtras.append(skyCorrExtra)
341 calExpMosaic = self._binAndMosaic(calExps, camera, self.config.binning, ids=calExpIds, refExps=None)
342 calBkgMosaic = self._binAndMosaic(
343 skyCorrExtras, camera, self.config.binning, ids=calExpIds, refExps=calExps
344 )
345
346 return Struct(skyCorr=calBkgs, calExpMosaic=calExpMosaic, calBkgMosaic=calBkgMosaic)
347
348 def _restoreBackgroundRefineMask(self, calExps, calBkgs):
349 """Restore original background to each calexp and invert the related
350 background model; optionally refine the mask plane.
351
352 The original visit-level background is restored to each calibrated
353 exposure and the existing background model is inverted in-place. If
354 doMaskObjects is True, the mask map associated with the exposure will
355 be iteratively updated (over nIter loops) by re-estimating the
356 background each iteration and redetecting footprints.
357
358 The background model modified in-place in this method will comprise the
359 first N elements of the skyCorr dataset type, i.e., these N elements
360 are the inverse of the calexpBackground model. All subsequent elements
361 appended to skyCorr will be additive such that, when skyCorr is
362 subtracted from a calexp, the net result will be to undo the initial
363 per-detector background solution and then apply the skyCorr model
364 thereafter. Adding skyCorr to a calexpBackground will effectively
365 negate the calexpBackground, returning only the additive background
366 components of the skyCorr background model.
367
368 Parameters
369 ----------
370 calExps : `lsst.afw.image.exposure.ExposureF`
371 Detector level calexp images to process.
372 calBkgs : `lsst.afw.math._backgroundList.BackgroundList`
373 Detector level background lists associated with the calexps.
374
375 Returns
376 -------
377 calExps : `lsst.afw.image.exposure.ExposureF`
378 The calexps with the initially subtracted background restored.
379 skyCorrBases : `lsst.afw.math._backgroundList.BackgroundList`
380 The inverted initial background models; the genesis for skyCorrs.
381 """
382 skyCorrBases = []
383 for calExp, calBkg in zip(calExps, calBkgs):
384 image = calExp.getMaskedImage()
385
386 # Invert all elements of the existing bg model; restore in calexp
387 for calBkgElement in calBkg:
388 statsImage = calBkgElement[0].getStatsImage()
389 statsImage *= -1
390 skyCorrBase = calBkg.getImage()
391 image -= skyCorrBase
392
393 # Iteratively subtract bg, re-detect sources, and add bg back on
394 if self.config.doMaskObjects:
395 self.maskObjects.findObjects(calExp)
396
397 stats = np.nanpercentile(skyCorrBase.array, [50, 75, 25])
398 self.log.info(
399 "Detector %d: Initial background restored; BG median = %.1f counts, BG IQR = %.1f counts",
400 calExp.getDetector().getId(),
401 -stats[0],
402 np.subtract(*stats[1:]),
403 )
404 skyCorrBases.append(skyCorrBase)
405 return calExps, skyCorrBases
406
407 def _subtractVisitBackground(self, calExps, calBkgs, camera, config):
408 """Perform a full focal-plane background subtraction for a visit.
409
410 Generate a full focal plane background model, binning all masked
411 detectors into bins of [bgModelN.xSize, bgModelN.ySize]. After,
412 subtract the resultant background model (translated back into CCD
413 coordinates) from the original detector exposure.
414
415 Return a list of background subtracted images and a list of full focal
416 plane background parameters.
417
418 Parameters
419 ----------
420 calExps : `list` [`lsst.afw.image.exposure.ExposureF`]
421 Calibrated exposures to be background subtracted.
422 calBkgs : `list` [`lsst.afw.math._backgroundList.BackgroundList`]
423 Background lists associated with the input calibrated exposures.
424 camera : `lsst.afw.cameraGeom.Camera`
425 Camera description.
426 config : `lsst.pipe.tasks.background.FocalPlaneBackgroundConfig`
427 Configuration to use for background subtraction.
428
429 Returns
430 -------
431 calExps : `list` [`lsst.afw.image.maskedImage.MaskedImageF`]
432 Background subtracted exposures for creating a focal plane image.
433 calBkgs : `list` [`lsst.afw.math._backgroundList.BackgroundList`]
434 Updated background lists with a visit-level model appended.
435 """
436 # Set up empty full focal plane background model object
437 bgModelBase = FocalPlaneBackground.fromCamera(config, camera)
438
439 # Loop over each detector, bin into [xSize, ySize] bins, and update
440 # summed flux (_values) and number of contributing pixels (_numbers)
441 # in focal plane coordinates. Append outputs to bgModels.
442 bgModels = []
443 for calExp in calExps:
444 bgModel = bgModelBase.clone()
445 bgModel.addCcd(calExp)
446 bgModels.append(bgModel)
447
448 # Merge detector models to make a single full focal plane bg model
449 for bgModel, calExp in zip(bgModels, calExps):
450 msg = (
451 "Detector %d: Merging %d unmasked pixels (%.1f%s of detector area) into focal plane "
452 "background model"
453 )
454 self.log.debug(
455 msg,
456 calExp.getDetector().getId(),
457 bgModel._numbers.getArray().sum(),
458 100 * bgModel._numbers.getArray().sum() / calExp.getBBox().getArea(),
459 "%",
460 )
461 bgModelBase.merge(bgModel)
462
463 # Map full focal plane bg solution to detector; subtract from exposure
464 calBkgElements = []
465 for calExp in calExps:
466 _, calBkgElement = self._subtractDetectorBackground(calExp, bgModelBase)
467 calBkgElements.append(calBkgElement)
468
469 msg = (
470 "Focal plane background model constructed using %.2f x %.2f mm (%d x %d pixel) superpixels; "
471 "FP BG median = %.1f counts, FP BG IQR = %.1f counts"
472 )
473 with warnings.catch_warnings():
474 warnings.filterwarnings("ignore", r"invalid value encountered")
475 stats = np.nanpercentile(bgModelBase.getStatsImage().array, [50, 75, 25])
476 self.log.info(
477 msg,
478 config.xSize,
479 config.ySize,
480 int(config.xSize / config.pixelSize),
481 int(config.ySize / config.pixelSize),
482 stats[0],
483 np.subtract(*stats[1:]),
484 )
485
486 for calBkg, calBkgElement in zip(calBkgs, calBkgElements):
487 calBkg.append(calBkgElement[0])
488 return calExps, calBkgs
489
490 def _subtractDetectorBackground(self, calExp, bgModel):
491 """Generate CCD background model and subtract from image.
492
493 Translate the full focal plane background into CCD coordinates and
494 subtract from the original science exposure image.
495
496 Parameters
497 ----------
498 calExp : `lsst.afw.image.exposure.ExposureF`
499 Exposure to subtract the background model from.
500 bgModel : `lsst.pipe.tasks.background.FocalPlaneBackground`
501 Full focal plane camera-level background model.
502
503 Returns
504 -------
505 calExp : `lsst.afw.image.exposure.ExposureF`
506 Background subtracted input exposure.
507 calBkgElement : `lsst.afw.math._backgroundList.BackgroundList`
508 Detector level realization of the full focal plane bg model.
509 """
510 image = calExp.getMaskedImage()
511 with warnings.catch_warnings():
512 warnings.filterwarnings("ignore", r"invalid value encountered")
513 calBkgElement = bgModel.toCcdBackground(calExp.getDetector(), image.getBBox())
514 image -= calBkgElement.getImage()
515 return calExp, calBkgElement
516
517 def _subtractSkyFrame(self, calExps, skyFrames, calBkgs):
518 """Determine the full focal plane sky frame scale factor relative to
519 an input list of calibrated exposures and subtract.
520
521 This method measures the sky frame scale on all inputs, resulting in
522 values equal to the background method solveScales(). The sky frame is
523 then subtracted as in subtractSkyFrame() using the appropriate scale.
524
525 Input calExps and calBkgs are updated in-place, returning sky frame
526 subtracted calExps and sky frame updated calBkgs, respectively.
527
528 Parameters
529 ----------
530 calExps : `list` [`lsst.afw.image.exposure.ExposureF`]
531 Calibrated exposures to be background subtracted.
532 skyFrames : `list` [`lsst.afw.image.exposure.ExposureF`]
533 Sky frame calibration data for the input detectors.
534 calBkgs : `list` [`lsst.afw.math._backgroundList.BackgroundList`]
535 Background lists associated with the input calibrated exposures.
536 """
537 skyFrameBgModels = []
538 scales = []
539 for calExp, skyFrame in zip(calExps, skyFrames):
540 skyFrameBgModel = self.sky.exposureToBackground(skyFrame)
541 skyFrameBgModels.append(skyFrameBgModel)
542 # return a tuple of gridded image and sky frame clipped means
543 samples = self.sky.measureScale(calExp.getMaskedImage(), skyFrameBgModel)
544 scales.append(samples)
545 scale = self.sky.solveScales(scales)
546 for calExp, skyFrameBgModel, calBkg in zip(calExps, skyFrameBgModels, calBkgs):
547 # subtract the scaled sky frame model from each calExp in-place,
548 # also updating the calBkg list in-place
549 self.sky.subtractSkyFrame(calExp.getMaskedImage(), skyFrameBgModel, scale, calBkg)
550 self.log.info("Sky frame subtracted with a scale factor of %.5f", scale)
551
552 def _binAndMosaic(self, exposures, camera, binning, ids=None, refExps=None):
553 """Bin input exposures and mosaic across the entire focal plane.
554
555 Input exposures are binned and then mosaicked at the position of
556 the detector in the focal plane of the camera.
557
558 Parameters
559 ----------
560 exposures : `list`
561 Detector level list of either calexp `ExposureF` types or
562 calexpBackground `BackgroundList` types.
563 camera : `lsst.afw.cameraGeom.Camera`
564 Camera matching the input data to process.
565 binning : `int`
566 Binning size to be applied to input images.
567 ids : `list` [`int`], optional
568 List of detector ids to iterate over.
569 refExps : `list` [`lsst.afw.image.exposure.ExposureF`], optional
570 If supplied, mask planes from these reference images will be used.
571 Returns
572 -------
573 mosaicImage : `lsst.afw.image.exposure.ExposureF`
574 Mosaicked full focal plane image.
575 """
576 refExps = np.resize(refExps, len(exposures)) # type: ignore
577 binnedImages = []
578 for exp, refExp in zip(exposures, refExps):
579 try:
580 nativeImage = exp.getMaskedImage()
581 except AttributeError:
582 nativeImage = afwImage.makeMaskedImage(exp.getImage())
583 if refExp:
584 nativeImage.setMask(refExp.getMask())
585 binnedImage = afwMath.binImage(nativeImage, binning)
586 binnedImages.append(binnedImage)
587 mosConfig = VisualizeMosaicExpConfig()
588 mosConfig.binning = binning
589 mosTask = VisualizeMosaicExpTask(config=mosConfig)
590 imageStruct = mosTask.run(binnedImages, camera, inputIds=ids)
591 mosaicImage = imageStruct.outputData
592 return mosaicImage
_subtractVisitBackground(self, calExps, calBkgs, camera, config)
run(self, calExps, calBkgs, skyFrames, camera)
_subtractSkyFrame(self, calExps, skyFrames, calBkgs)
runQuantum(self, butlerQC, inputRefs, outputRefs)
_binAndMosaic(self, exposures, camera, binning, ids=None, refExps=None)
_reorderAndPadList(inputList, inputKeys, outputKeys, padWith=None)
_skyFrameLookup(datasetType, registry, quantumDataId, collections)