22__all__ = [
"MakeWarpTask",
"MakeWarpConfig"]
24from deprecated.sphinx
import deprecated
32import lsst.pipe.base.connectionTypes
as connectionTypes
33import lsst.utils
as utils
35from lsst.daf.butler
import DeferredDatasetHandle
39from lsst.utils.timer
import timeMethod
40from .coaddBase
import CoaddBaseTask, makeSkyInfo, reorderAndPadList
41from .warpAndPsfMatch
import WarpAndPsfMatchTask
42from collections.abc
import Iterable
44log = logging.getLogger(__name__)
48 dimensions=(
"tract",
"patch",
"skymap",
"instrument",
"visit"),
49 defaultTemplates={
"coaddName":
"deep",
50 "skyWcsName":
"gbdesAstrometricFit",
51 "photoCalibName":
"fgcm",
53 calExpList = connectionTypes.Input(
54 doc=
"Input exposures to be resampled and optionally PSF-matched onto a SkyMap projection/patch",
55 name=
"{calexpType}calexp",
56 storageClass=
"ExposureF",
57 dimensions=(
"instrument",
"visit",
"detector"),
61 backgroundList = connectionTypes.Input(
62 doc=
"Input backgrounds to be added back into the calexp if bgSubtracted=False",
63 name=
"calexpBackground",
64 storageClass=
"Background",
65 dimensions=(
"instrument",
"visit",
"detector"),
68 skyCorrList = connectionTypes.Input(
69 doc=
"Input Sky Correction to be subtracted from the calexp if doApplySkyCorr=True",
71 storageClass=
"Background",
72 dimensions=(
"instrument",
"visit",
"detector"),
75 skyMap = connectionTypes.Input(
76 doc=
"Input definition of geometry/bbox and projection/wcs for warped exposures",
77 name=BaseSkyMap.SKYMAP_DATASET_TYPE_NAME,
78 storageClass=
"SkyMap",
79 dimensions=(
"skymap",),
81 externalSkyWcsTractCatalog = connectionTypes.Input(
82 doc=(
"Per-tract, per-visit wcs calibrations. These catalogs use the detector "
83 "id for the catalog id, sorted on id for fast lookup."),
84 name=
"{skyWcsName}SkyWcsCatalog",
85 storageClass=
"ExposureCatalog",
86 dimensions=(
"instrument",
"visit",
"tract"),
88 externalSkyWcsGlobalCatalog = connectionTypes.Input(
89 doc=(
"Per-visit wcs calibrations computed globally (with no tract information). "
90 "These catalogs use the detector id for the catalog id, sorted on id for "
92 name=
"finalVisitSummary",
93 storageClass=
"ExposureCatalog",
94 dimensions=(
"instrument",
"visit"),
96 externalPhotoCalibTractCatalog = connectionTypes.Input(
97 doc=(
"Per-tract, per-visit photometric calibrations. These catalogs use the "
98 "detector id for the catalog id, sorted on id for fast lookup."),
99 name=
"{photoCalibName}PhotoCalibCatalog",
100 storageClass=
"ExposureCatalog",
101 dimensions=(
"instrument",
"visit",
"tract"),
103 externalPhotoCalibGlobalCatalog = connectionTypes.Input(
104 doc=(
"Per-visit photometric calibrations computed globally (with no tract "
105 "information). These catalogs use the detector id for the catalog id, "
106 "sorted on id for fast lookup."),
107 name=
"finalVisitSummary",
108 storageClass=
"ExposureCatalog",
109 dimensions=(
"instrument",
"visit"),
111 finalizedPsfApCorrCatalog = connectionTypes.Input(
112 doc=(
"Per-visit finalized psf models and aperture correction maps. "
113 "These catalogs use the detector id for the catalog id, "
114 "sorted on id for fast lookup."),
115 name=
"finalVisitSummary",
116 storageClass=
"ExposureCatalog",
117 dimensions=(
"instrument",
"visit"),
119 direct = connectionTypes.Output(
120 doc=(
"Output direct warped exposure (previously called CoaddTempExp), produced by resampling ",
121 "calexps onto the skyMap patch geometry."),
122 name=
"{coaddName}Coadd_directWarp",
123 storageClass=
"ExposureF",
124 dimensions=(
"tract",
"patch",
"skymap",
"visit",
"instrument"),
126 psfMatched = connectionTypes.Output(
127 doc=(
"Output PSF-Matched warped exposure (previously called CoaddTempExp), produced by resampling ",
128 "calexps onto the skyMap patch geometry and PSF-matching to a model PSF."),
129 name=
"{coaddName}Coadd_psfMatchedWarp",
130 storageClass=
"ExposureF",
131 dimensions=(
"tract",
"patch",
"skymap",
"visit",
"instrument"),
135 wcsList = connectionTypes.Input(
136 doc=
"WCSs of calexps used by SelectImages subtask to determine if the calexp overlaps the patch",
137 name=
"{calexpType}calexp.wcs",
139 dimensions=(
"instrument",
"visit",
"detector"),
142 bboxList = connectionTypes.Input(
143 doc=
"BBoxes of calexps used by SelectImages subtask to determine if the calexp overlaps the patch",
144 name=
"{calexpType}calexp.bbox",
145 storageClass=
"Box2I",
146 dimensions=(
"instrument",
"visit",
"detector"),
149 visitSummary = connectionTypes.Input(
150 doc=
"Consolidated exposure metadata",
151 name=
"finalVisitSummary",
152 storageClass=
"ExposureCatalog",
153 dimensions=(
"instrument",
"visit",),
156 def __init__(self, *, config=None):
157 super().__init__(config=config)
158 if config.bgSubtracted:
159 self.inputs.remove(
"backgroundList")
160 if not config.doApplySkyCorr:
161 self.inputs.remove(
"skyCorrList")
162 if config.doApplyExternalSkyWcs:
163 if config.useGlobalExternalSkyWcs:
164 self.inputs.remove(
"externalSkyWcsTractCatalog")
166 self.inputs.remove(
"externalSkyWcsGlobalCatalog")
168 self.inputs.remove(
"externalSkyWcsTractCatalog")
169 self.inputs.remove(
"externalSkyWcsGlobalCatalog")
170 if config.doApplyExternalPhotoCalib:
171 if config.useGlobalExternalPhotoCalib:
172 self.inputs.remove(
"externalPhotoCalibTractCatalog")
174 self.inputs.remove(
"externalPhotoCalibGlobalCatalog")
176 self.inputs.remove(
"externalPhotoCalibTractCatalog")
177 self.inputs.remove(
"externalPhotoCalibGlobalCatalog")
178 if not config.doApplyFinalizedPsf:
179 self.inputs.remove(
"finalizedPsfApCorrCatalog")
180 if not config.makeDirect:
181 self.outputs.remove(
"direct")
182 if not config.makePsfMatched:
183 self.outputs.remove(
"psfMatched")
185 if config.select.target != lsst.pipe.tasks.selectImages.PsfWcsSelectImagesTask:
186 self.inputs.remove(
"visitSummary")
189class MakeWarpConfig(pipeBase.PipelineTaskConfig, CoaddBaseTask.ConfigClass,
190 pipelineConnections=MakeWarpConnections):
191 """Config for MakeWarpTask."""
193 warpAndPsfMatch = pexConfig.ConfigurableField(
194 target=WarpAndPsfMatchTask,
195 doc=
"Task to warp and PSF-match calexp",
197 doWrite = pexConfig.Field(
198 doc=
"persist <coaddName>Coadd_<warpType>Warp",
202 bgSubtracted = pexConfig.Field(
203 doc=
"Work with a background subtracted calexp?",
207 coaddPsf = pexConfig.ConfigField(
208 doc=
"Configuration for CoaddPsf",
209 dtype=CoaddPsfConfig,
211 makeDirect = pexConfig.Field(
212 doc=
"Make direct Warp/Coadds",
216 makePsfMatched = pexConfig.Field(
217 doc=
"Make Psf-Matched Warp/Coadd?",
221 doWriteEmptyWarps = pexConfig.Field(
224 doc=
"Write out warps even if they are empty"
226 hasFakes = pexConfig.Field(
227 doc=
"Should be set to True if fake sources have been inserted into the input data.",
231 doApplySkyCorr = pexConfig.Field(
234 doc=
"Apply sky correction?",
236 doApplyFinalizedPsf = pexConfig.Field(
237 doc=
"Whether to apply finalized psf models and aperture correction map.",
241 idGenerator = DetectorVisitIdGeneratorConfig.make_field()
244 CoaddBaseTask.ConfigClass.validate(self)
246 if not self.makePsfMatched
and not self.makeDirect:
247 raise RuntimeError(
"At least one of config.makePsfMatched and config.makeDirect must be True")
250 log.warning(
"Config doPsfMatch deprecated. Setting makePsfMatched=True and makeDirect=False")
251 self.makePsfMatched =
True
252 self.makeDirect =
False
254 def setDefaults(self):
255 CoaddBaseTask.ConfigClass.setDefaults(self)
256 self.warpAndPsfMatch.psfMatch.kernel.active.kernelSize = self.matchingKernelSize
260 """Warp and optionally PSF-Match calexps onto an a common projection.
262 Warp and optionally PSF-Match calexps onto a common projection, by
263 performing the following operations:
264 - Group calexps by visit/run
265 - For each visit, generate a Warp by calling method
@ref run.
266 `run` loops over the visit
's calexps calling
270 ConfigClass = MakeWarpConfig
271 _DefaultName = "makeWarp"
273 def __init__(self, **kwargs):
274 CoaddBaseTask.__init__(self, **kwargs)
275 self.makeSubtask(
"warpAndPsfMatch")
276 if self.config.hasFakes:
277 self.calexpType =
"fakes_calexp"
279 self.calexpType =
"calexp"
281 @utils.inheritDoc(pipeBase.PipelineTask)
282 def runQuantum(self, butlerQC, inputRefs, outputRefs):
286 detectorOrder = [ref.datasetRef.dataId[
'detector']
for ref
in inputRefs.calExpList]
288 inputRefs = reorderRefs(inputRefs, detectorOrder, dataIdKey=
'detector')
291 inputs = butlerQC.get(inputRefs)
295 skyMap = inputs.pop(
"skyMap")
296 quantumDataId = butlerQC.quantum.dataId
297 skyInfo = makeSkyInfo(skyMap, tractId=quantumDataId[
'tract'], patchId=quantumDataId[
'patch'])
300 dataIdList = [ref.datasetRef.dataId
for ref
in inputRefs.calExpList]
303 self.config.idGenerator.apply(dataId).catalog_id
304 for dataId
in dataIdList
307 if self.config.doApplyExternalSkyWcs:
308 if self.config.useGlobalExternalSkyWcs:
309 externalSkyWcsCatalog = inputs.pop(
"externalSkyWcsGlobalCatalog")
311 externalSkyWcsCatalog = inputs.pop(
"externalSkyWcsTractCatalog")
313 externalSkyWcsCatalog =
None
315 if self.config.doApplyExternalPhotoCalib:
316 if self.config.useGlobalExternalPhotoCalib:
317 externalPhotoCalibCatalog = inputs.pop(
"externalPhotoCalibGlobalCatalog")
319 externalPhotoCalibCatalog = inputs.pop(
"externalPhotoCalibTractCatalog")
321 externalPhotoCalibCatalog =
None
323 if self.config.doApplyFinalizedPsf:
324 finalizedPsfApCorrCatalog = inputs.pop(
"finalizedPsfApCorrCatalog")
326 finalizedPsfApCorrCatalog =
None
330 completeIndices = self._prepareCalibratedExposures(
332 externalSkyWcsCatalog=externalSkyWcsCatalog,
333 externalPhotoCalibCatalog=externalPhotoCalibCatalog,
334 finalizedPsfApCorrCatalog=finalizedPsfApCorrCatalog)
335 inputs = self.filterInputs(indices=completeIndices, inputs=inputs)
341 coordList = [skyInfo.wcs.pixelToSky(pos)
for pos
in cornerPosList]
342 goodIndices = self.select.run(**inputs, coordList=coordList, dataIds=dataIdList)
343 inputs = self.filterInputs(indices=goodIndices, inputs=inputs)
346 visitId = dataIdList[0][
"visit"]
348 results = self.run(**inputs, visitId=visitId,
349 ccdIdList=[ccdIdList[i]
for i
in goodIndices],
350 dataIdList=[dataIdList[i]
for i
in goodIndices],
352 if self.config.makeDirect
and results.exposures[
"direct"]
is not None:
353 butlerQC.put(results.exposures[
"direct"], outputRefs.direct)
354 if self.config.makePsfMatched
and results.exposures[
"psfMatched"]
is not None:
355 butlerQC.put(results.exposures[
"psfMatched"], outputRefs.psfMatched)
358 def run(self, calExpList, ccdIdList, skyInfo, visitId=0, dataIdList=None, **kwargs):
359 """Create a Warp from inputs.
361 We iterate over the multiple calexps in a single exposure to construct
362 the warp (previously called a coaddTempExp) of that exposure to the
363 supplied tract/patch.
365 Pixels that receive no pixels are set to NAN; this
is not correct
366 (violates LSST algorithms group policy), but will be fixed up by
367 interpolating after the coaddition.
369 calexpRefList : `list`
370 List of data references
for calexps that (may)
371 overlap the patch of interest.
372 skyInfo : `lsst.pipe.base.Struct`
373 Struct
from `~lsst.pipe.base.coaddBase.makeSkyInfo()`
with
374 geometric information about the patch.
376 Integer identifier
for visit,
for the table that will
377 produce the CoaddPsf.
381 result : `lsst.pipe.base.Struct`
382 Results
as a struct
with attributes:
385 A dictionary containing the warps requested:
386 "direct": direct warp
if ``config.makeDirect``
387 "psfMatched": PSF-matched warp
if ``config.makePsfMatched``
390 warpTypeList = self.getWarpTypeList()
392 totGoodPix = {warpType: 0 for warpType
in warpTypeList}
393 didSetMetadata = {warpType:
False for warpType
in warpTypeList}
394 warps = {warpType: self._prepareEmptyExposure(skyInfo)
for warpType
in warpTypeList}
395 inputRecorder = {warpType: self.inputRecorder.makeCoaddTempExpRecorder(visitId, len(calExpList))
396 for warpType
in warpTypeList}
398 modelPsf = self.config.modelPsf.apply()
if self.config.makePsfMatched
else None
399 if dataIdList
is None:
400 dataIdList = ccdIdList
402 for calExpInd, (calExp, ccdId, dataId)
in enumerate(zip(calExpList, ccdIdList, dataIdList)):
403 self.log.info(
"Processing calexp %d of %d for this Warp: id=%s",
404 calExpInd+1, len(calExpList), dataId)
409 if isinstance(calExp, DeferredDatasetHandle):
410 calExp = calExp.get()
412 warpedAndMatched = self.warpAndPsfMatch.run(calExp, modelPsf=modelPsf,
413 wcs=skyInfo.wcs, maxBBox=skyInfo.bbox,
414 makeDirect=self.config.makeDirect,
415 makePsfMatched=self.config.makePsfMatched)
416 except Exception
as e:
417 self.log.warning(
"WarpAndPsfMatch failed for calexp %s; skipping it: %s", dataId, e)
420 numGoodPix = {warpType: 0
for warpType
in warpTypeList}
421 for warpType
in warpTypeList:
422 exposure = warpedAndMatched.getDict()[warpType]
425 warp = warps[warpType]
426 if didSetMetadata[warpType]:
427 mimg = exposure.getMaskedImage()
428 mimg *= (warp.getPhotoCalib().getInstFluxAtZeroMagnitude()
429 / exposure.getPhotoCalib().getInstFluxAtZeroMagnitude())
431 numGoodPix[warpType] = coaddUtils.copyGoodPixels(
432 warp.getMaskedImage(), exposure.getMaskedImage(), self.getBadPixelMask())
433 totGoodPix[warpType] += numGoodPix[warpType]
434 self.log.debug(
"Calexp %s has %d good pixels in this patch (%.1f%%) for %s",
435 dataId, numGoodPix[warpType],
436 100.0*numGoodPix[warpType]/skyInfo.bbox.getArea(), warpType)
437 if numGoodPix[warpType] > 0
and not didSetMetadata[warpType]:
438 warp.info.id = exposure.info.id
439 warp.setPhotoCalib(exposure.getPhotoCalib())
440 warp.setFilter(exposure.getFilter())
441 warp.getInfo().setVisitInfo(exposure.getInfo().getVisitInfo())
444 warp.setPsf(exposure.getPsf())
445 didSetMetadata[warpType] =
True
449 inputRecorder[warpType].addCalExp(calExp, ccdId, numGoodPix[warpType])
451 except Exception
as e:
452 self.log.warning(
"Error processing calexp %s; skipping it: %s", dataId, e)
455 for warpType
in warpTypeList:
456 self.log.info(
"%sWarp has %d good pixels (%.1f%%)",
457 warpType, totGoodPix[warpType], 100.0*totGoodPix[warpType]/skyInfo.bbox.getArea())
459 if totGoodPix[warpType] > 0
and didSetMetadata[warpType]:
460 inputRecorder[warpType].finish(warps[warpType], totGoodPix[warpType])
461 if warpType ==
"direct":
462 warps[warpType].setPsf(
463 CoaddPsf(inputRecorder[warpType].coaddInputs.ccds, skyInfo.wcs,
464 self.config.coaddPsf.makeControl()))
466 if not self.config.doWriteEmptyWarps:
468 warps[warpType] =
None
472 result = pipeBase.Struct(exposures=warps)
475 def filterInputs(self, indices, inputs):
476 """Filter task inputs by their indices.
480 indices : `list` [`int`]
481 inputs : `dict` [`list`]
482 A dictionary of input connections to be passed to run.
486 inputs : `dict` [`list`]
487 Task inputs with their lists filtered by indices.
489 for key
in inputs.keys():
491 if isinstance(inputs[key], list):
492 inputs[key] = [inputs[key][ind]
for ind
in indices]
495 @deprecated(reason=
"This method is deprecated in favor of its leading underscore version, "
496 "_prepareCalibratedfExposures(). Will be removed after v25.",
497 version=
"v25.0", category=FutureWarning)
498 def prepareCalibratedExposures(self, calExpList, backgroundList=None, skyCorrList=None,
499 externalSkyWcsCatalog=None, externalPhotoCalibCatalog=None,
500 finalizedPsfApCorrCatalog=None,
502 """Deprecated function.
504 Please use _prepareCalibratedExposure(), which this delegates to and
505 noting its slightly updated API, instead.
508 calExpList = [ref.get()
for ref
in calExpList]
510 wcsList = [calexp.getWcs()
for calexp
in calExpList]
512 indices = self._prepareCalibratedExposures(calExpList=calExpList, wcsList=wcsList,
513 backgroundList=backgroundList, skyCorrList=skyCorrList,
514 externalSkyWcsCatalog=externalSkyWcsCatalog,
515 externalPhotoCalibCatalog=externalPhotoCalibCatalog,
516 finalizedPsfApCorrCatalog=finalizedPsfApCorrCatalog)
519 def _prepareCalibratedExposures(self, calExpList=[], wcsList=None, backgroundList=None, skyCorrList=None,
520 externalSkyWcsCatalog=None, externalPhotoCalibCatalog=None,
521 finalizedPsfApCorrCatalog=None, **kwargs):
522 """Calibrate and add backgrounds to input calExpList in place.
527 `lsst.daf.butler.DeferredDatasetHandle`]
528 Sequence of calexps to be modified
in place.
530 The WCSs of the calexps
in ``calExpList``. When
531 ``externalSkyCatalog``
is `
None`, these are used to determine
if
532 the calexp should be included
in the warp, namely checking that it
533 is not `
None`. If ``externalSkyCatalog``
is not `
None`, this list
534 will be dynamically updated
with the external sky WCS.
535 backgroundList : `list` [`lsst.afw.math.backgroundList`], optional
536 Sequence of backgrounds to be added back
in if bgSubtracted=
False.
537 skyCorrList : `list` [`lsst.afw.math.backgroundList`], optional
538 Sequence of background corrections to be subtracted
if
541 Exposure catalog
with external skyWcs to be applied
542 if config.doApplyExternalSkyWcs=
True. Catalog uses the detector id
543 for the catalog id, sorted on id
for fast lookup.
545 Exposure catalog
with external photoCalib to be applied
546 if config.doApplyExternalPhotoCalib=
True. Catalog uses the
547 detector id
for the catalog id, sorted on id
for fast lookup.
549 Exposure catalog
with finalized psf models
and aperture correction
550 maps to be applied
if config.doApplyFinalizedPsf=
True. Catalog
551 uses the detector id
for the catalog id, sorted on id
for fast
554 Additional keyword arguments.
558 indices : `list` [`int`]
559 Indices of ``calExpList``
and friends that have valid
562 wcsList = len(calExpList)*[None]
if wcsList
is None else wcsList
563 backgroundList = len(calExpList)*[
None]
if backgroundList
is None else backgroundList
564 skyCorrList = len(calExpList)*[
None]
if skyCorrList
is None else skyCorrList
566 includeCalibVar = self.config.includeCalibVar
569 for index, (calexp, wcs, background, skyCorr)
in enumerate(zip(calExpList,
573 if externalSkyWcsCatalog
is None and wcs
is None:
574 self.log.warning(
"Detector id %d for visit %d has None for skyWcs and will not be "
575 "used in the warp", calexp.dataId[
"detector"], calexp.dataId[
"visit"])
578 if isinstance(calexp, DeferredDatasetHandle):
579 calexp = calexp.get()
581 if not self.config.bgSubtracted:
582 calexp.maskedImage += background.getImage()
584 detectorId = calexp.info.getDetector().getId()
587 if externalPhotoCalibCatalog
is not None:
588 row = externalPhotoCalibCatalog.find(detectorId)
590 self.log.warning(
"Detector id %s not found in externalPhotoCalibCatalog "
591 "and will not be used in the warp.", detectorId)
593 photoCalib = row.getPhotoCalib()
594 if photoCalib
is None:
595 self.log.warning(
"Detector id %s has None for photoCalib in externalPhotoCalibCatalog "
596 "and will not be used in the warp.", detectorId)
598 calexp.setPhotoCalib(photoCalib)
600 photoCalib = calexp.getPhotoCalib()
601 if photoCalib
is None:
602 self.log.warning(
"Detector id %s has None for photoCalib in the calexp "
603 "and will not be used in the warp.", detectorId)
607 if externalSkyWcsCatalog
is not None:
608 row = externalSkyWcsCatalog.find(detectorId)
610 self.log.warning(
"Detector id %s not found in externalSkyWcsCatalog "
611 "and will not be used in the warp.", detectorId)
613 skyWcs = row.getWcs()
614 wcsList[index] = skyWcs
616 self.log.warning(
"Detector id %s has None for skyWcs in externalSkyWcsCatalog "
617 "and will not be used in the warp.", detectorId)
619 calexp.setWcs(skyWcs)
621 skyWcs = calexp.getWcs()
622 wcsList[index] = skyWcs
624 self.log.warning(
"Detector id %s has None for skyWcs in the calexp "
625 "and will not be used in the warp.", detectorId)
629 if finalizedPsfApCorrCatalog
is not None:
630 row = finalizedPsfApCorrCatalog.find(detectorId)
632 self.log.warning(
"Detector id %s not found in finalizedPsfApCorrCatalog "
633 "and will not be used in the warp.", detectorId)
637 self.log.warning(
"Detector id %s has None for psf in finalizedPsfApCorrCatalog "
638 "and will not be used in the warp.", detectorId)
641 apCorrMap = row.getApCorrMap()
642 if apCorrMap
is None:
643 self.log.warning(
"Detector id %s has None for ApCorrMap in finalizedPsfApCorrCatalog "
644 "and will not be used in the warp.", detectorId)
646 calexp.info.setApCorrMap(apCorrMap)
649 if calexp.info.getApCorrMap()
is None:
650 self.log.warning(
"Detector id %s has None for ApCorrMap in the calexp "
651 "and will not be used in the warp.", detectorId)
655 calexp.maskedImage = photoCalib.calibrateImage(calexp.maskedImage,
656 includeScaleUncertainty=includeCalibVar)
657 calexp.maskedImage /= photoCalib.getCalibrationMean()
663 if self.config.doApplySkyCorr:
664 calexp.maskedImage -= skyCorr.getImage()
666 indices.append(index)
667 calExpList[index] = calexp
672 def _prepareEmptyExposure(skyInfo):
673 """Produce an empty exposure for a given patch.
677 skyInfo : `lsst.pipe.base.Struct`
678 Struct from `~lsst.pipe.base.coaddBase.makeSkyInfo()`
with
679 geometric information about the patch.
683 exp : `lsst.afw.image.exposure.ExposureF`
684 An empty exposure
for a given patch.
686 exp = afwImage.ExposureF(skyInfo.bbox, skyInfo.wcs)
687 exp.getMaskedImage().set(numpy.nan, afwImage.Mask
688 .getPlaneBitMask("NO_DATA"), numpy.inf)
691 def getWarpTypeList(self):
692 """Return list of requested warp types per the config.
695 if self.config.makeDirect:
696 warpTypeList.append(
"direct")
697 if self.config.makePsfMatched:
698 warpTypeList.append(
"psfMatched")
702def reorderRefs(inputRefs, outputSortKeyOrder, dataIdKey):
703 """Reorder inputRefs per outputSortKeyOrder.
705 Any inputRefs which are lists will be resorted per specified key e.g.,
706 'detector.' Only iterables will be reordered,
and values can be of type
707 `lsst.pipe.base.connections.DeferredDatasetRef`
or
708 `lsst.daf.butler.core.datasets.ref.DatasetRef`.
710 Returned lists of refs have the same length
as the outputSortKeyOrder.
711 If an outputSortKey
not in the inputRef, then it will be padded
with None.
712 If an inputRef contains an inputSortKey that
is not in the
713 outputSortKeyOrder it will be removed.
717 inputRefs : `lsst.pipe.base.connections.QuantizedConnection`
718 Input references to be reordered
and padded.
719 outputSortKeyOrder : `iterable`
720 Iterable of values to be compared
with inputRef
's dataId[dataIdKey].
722 The data ID key in the dataRefs to compare
with the outputSortKeyOrder.
726 inputRefs : `lsst.pipe.base.connections.QuantizedConnection`
727 Quantized Connection
with sorted DatasetRef values sorted
if iterable.
729 for connectionName, refs
in inputRefs:
730 if isinstance(refs, Iterable):
731 if hasattr(refs[0],
"dataId"):
732 inputSortKeyOrder = [ref.dataId[dataIdKey]
for ref
in refs]
734 inputSortKeyOrder = [ref.datasetRef.dataId[dataIdKey]
for ref
in refs]
735 if inputSortKeyOrder != outputSortKeyOrder:
736 setattr(inputRefs, connectionName,
737 reorderAndPadList(refs, inputSortKeyOrder, outputSortKeyOrder))