22__all__ = [
"MakeWarpTask",
"MakeWarpConfig"]
24from deprecated.sphinx
import deprecated
32import lsst.pipe.base.connectionTypes
as connectionTypes
35from lsst.daf.butler
import DeferredDatasetHandle
38from lsst.utils.timer
import timeMethod
39from .coaddBase
import CoaddBaseTask, makeSkyInfo, reorderAndPadList
40from .warpAndPsfMatch
import WarpAndPsfMatchTask
43log = logging.getLogger(__name__)
47 dimensions=(
"tract",
"patch",
"skymap",
"instrument",
"visit"),
48 defaultTemplates={
"coaddName":
"deep",
49 "skyWcsName":
"jointcal",
50 "photoCalibName":
"fgcm",
52 calExpList = connectionTypes.Input(
53 doc=
"Input exposures to be resampled and optionally PSF-matched onto a SkyMap projection/patch",
54 name=
"{calexpType}calexp",
55 storageClass=
"ExposureF",
56 dimensions=(
"instrument",
"visit",
"detector"),
60 backgroundList = connectionTypes.Input(
61 doc=
"Input backgrounds to be added back into the calexp if bgSubtracted=False",
62 name=
"calexpBackground",
63 storageClass=
"Background",
64 dimensions=(
"instrument",
"visit",
"detector"),
67 skyCorrList = connectionTypes.Input(
68 doc=
"Input Sky Correction to be subtracted from the calexp if doApplySkyCorr=True",
70 storageClass=
"Background",
71 dimensions=(
"instrument",
"visit",
"detector"),
74 skyMap = connectionTypes.Input(
75 doc=
"Input definition of geometry/bbox and projection/wcs for warped exposures",
76 name=BaseSkyMap.SKYMAP_DATASET_TYPE_NAME,
77 storageClass=
"SkyMap",
78 dimensions=(
"skymap",),
80 externalSkyWcsTractCatalog = connectionTypes.Input(
81 doc=(
"Per-tract, per-visit wcs calibrations. These catalogs use the detector "
82 "id for the catalog id, sorted on id for fast lookup."),
83 name=
"{skyWcsName}SkyWcsCatalog",
84 storageClass=
"ExposureCatalog",
85 dimensions=(
"instrument",
"visit",
"tract"),
87 externalSkyWcsGlobalCatalog = connectionTypes.Input(
88 doc=(
"Per-visit wcs calibrations computed globally (with no tract information). "
89 "These catalogs use the detector id for the catalog id, sorted on id for "
91 name=
"{skyWcsName}SkyWcsCatalog",
92 storageClass=
"ExposureCatalog",
93 dimensions=(
"instrument",
"visit"),
95 externalPhotoCalibTractCatalog = connectionTypes.Input(
96 doc=(
"Per-tract, per-visit photometric calibrations. These catalogs use the "
97 "detector id for the catalog id, sorted on id for fast lookup."),
98 name=
"{photoCalibName}PhotoCalibCatalog",
99 storageClass=
"ExposureCatalog",
100 dimensions=(
"instrument",
"visit",
"tract"),
102 externalPhotoCalibGlobalCatalog = connectionTypes.Input(
103 doc=(
"Per-visit photometric calibrations computed globally (with no tract "
104 "information). These catalogs use the detector id for the catalog id, "
105 "sorted on id for fast lookup."),
106 name=
"{photoCalibName}PhotoCalibCatalog",
107 storageClass=
"ExposureCatalog",
108 dimensions=(
"instrument",
"visit"),
110 finalizedPsfApCorrCatalog = connectionTypes.Input(
111 doc=(
"Per-visit finalized psf models and aperture correction maps. "
112 "These catalogs use the detector id for the catalog id, "
113 "sorted on id for fast lookup."),
114 name=
"finalized_psf_ap_corr_catalog",
115 storageClass=
"ExposureCatalog",
116 dimensions=(
"instrument",
"visit"),
118 direct = connectionTypes.Output(
119 doc=(
"Output direct warped exposure (previously called CoaddTempExp), produced by resampling ",
120 "calexps onto the skyMap patch geometry."),
121 name=
"{coaddName}Coadd_directWarp",
122 storageClass=
"ExposureF",
123 dimensions=(
"tract",
"patch",
"skymap",
"visit",
"instrument"),
125 psfMatched = connectionTypes.Output(
126 doc=(
"Output PSF-Matched warped exposure (previously called CoaddTempExp), produced by resampling ",
127 "calexps onto the skyMap patch geometry and PSF-matching to a model PSF."),
128 name=
"{coaddName}Coadd_psfMatchedWarp",
129 storageClass=
"ExposureF",
130 dimensions=(
"tract",
"patch",
"skymap",
"visit",
"instrument"),
134 wcsList = connectionTypes.Input(
135 doc=
"WCSs of calexps used by SelectImages subtask to determine if the calexp overlaps the patch",
136 name=
"{calexpType}calexp.wcs",
138 dimensions=(
"instrument",
"visit",
"detector"),
141 bboxList = connectionTypes.Input(
142 doc=
"BBoxes of calexps used by SelectImages subtask to determine if the calexp overlaps the patch",
143 name=
"{calexpType}calexp.bbox",
144 storageClass=
"Box2I",
145 dimensions=(
"instrument",
"visit",
"detector"),
148 visitSummary = connectionTypes.Input(
149 doc=
"Consolidated exposure metadata from ConsolidateVisitSummaryTask",
150 name=
"{calexpType}visitSummary",
151 storageClass=
"ExposureCatalog",
152 dimensions=(
"instrument",
"visit",),
155 def __init__(self, *, config=None):
156 super().__init__(config=config)
157 if config.bgSubtracted:
158 self.inputs.remove(
"backgroundList")
159 if not config.doApplySkyCorr:
160 self.inputs.remove(
"skyCorrList")
161 if config.doApplyExternalSkyWcs:
162 if config.useGlobalExternalSkyWcs:
163 self.inputs.remove(
"externalSkyWcsTractCatalog")
165 self.inputs.remove(
"externalSkyWcsGlobalCatalog")
167 self.inputs.remove(
"externalSkyWcsTractCatalog")
168 self.inputs.remove(
"externalSkyWcsGlobalCatalog")
169 if config.doApplyExternalPhotoCalib:
170 if config.useGlobalExternalPhotoCalib:
171 self.inputs.remove(
"externalPhotoCalibTractCatalog")
173 self.inputs.remove(
"externalPhotoCalibGlobalCatalog")
175 self.inputs.remove(
"externalPhotoCalibTractCatalog")
176 self.inputs.remove(
"externalPhotoCalibGlobalCatalog")
177 if not config.doApplyFinalizedPsf:
178 self.inputs.remove(
"finalizedPsfApCorrCatalog")
179 if not config.makeDirect:
180 self.outputs.remove(
"direct")
181 if not config.makePsfMatched:
182 self.outputs.remove(
"psfMatched")
184 if config.select.target != lsst.pipe.tasks.selectImages.PsfWcsSelectImagesTask:
185 self.inputs.remove(
"visitSummary")
188class MakeWarpConfig(pipeBase.PipelineTaskConfig, CoaddBaseTask.ConfigClass,
189 pipelineConnections=MakeWarpConnections):
190 """Config for MakeWarpTask."""
192 warpAndPsfMatch = pexConfig.ConfigurableField(
193 target=WarpAndPsfMatchTask,
194 doc=
"Task to warp and PSF-match calexp",
196 doWrite = pexConfig.Field(
197 doc=
"persist <coaddName>Coadd_<warpType>Warp",
201 bgSubtracted = pexConfig.Field(
202 doc=
"Work with a background subtracted calexp?",
206 coaddPsf = pexConfig.ConfigField(
207 doc=
"Configuration for CoaddPsf",
208 dtype=CoaddPsfConfig,
210 makeDirect = pexConfig.Field(
211 doc=
"Make direct Warp/Coadds",
215 makePsfMatched = pexConfig.Field(
216 doc=
"Make Psf-Matched Warp/Coadd?",
220 doWriteEmptyWarps = pexConfig.Field(
223 doc=
"Write out warps even if they are empty"
225 hasFakes = pexConfig.Field(
226 doc=
"Should be set to True if fake sources have been inserted into the input data.",
230 doApplySkyCorr = pexConfig.Field(
233 doc=
"Apply sky correction?",
235 doApplyFinalizedPsf = pexConfig.Field(
236 doc=
"Whether to apply finalized psf models and aperture correction map.",
242 CoaddBaseTask.ConfigClass.validate(self)
244 if not self.makePsfMatched
and not self.makeDirect:
245 raise RuntimeError(
"At least one of config.makePsfMatched and config.makeDirect must be True")
248 log.warning(
"Config doPsfMatch deprecated. Setting makePsfMatched=True and makeDirect=False")
249 self.makePsfMatched =
True
250 self.makeDirect =
False
252 def setDefaults(self):
253 CoaddBaseTask.ConfigClass.setDefaults(self)
254 self.warpAndPsfMatch.psfMatch.kernel.active.kernelSize = self.matchingKernelSize
258 """Warp and optionally PSF-Match calexps onto an a common projection.
260 Warp and optionally PSF-Match calexps onto a common projection, by
261 performing the following operations:
262 - Group calexps by visit/run
263 - For each visit, generate a Warp by calling method
@ref run.
264 `run` loops over the visit
's calexps calling
269 WarpType identifies the types of convolutions applied to Warps
270 (previously CoaddTempExps). Only two types are available: direct
271 (for regular Warps/Coadds)
and psfMatched(
for Warps/Coadds
with
272 homogenized PSFs). We expect to add a third type, likelihood,
for
273 generating likelihood Coadds
with Warps that have been correlated
with
276 To make `psfMatchedWarps`, select `config.makePsfMatched=
True`. The subtask
278 is responsible
for the PSF-Matching,
and its config
is accessed via
279 `config.warpAndPsfMatch.psfMatch`.
281 The optimal configuration depends on aspects of dataset: the pixel scale,
282 average PSF FWHM
and dimensions of the PSF kernel. These configs include
283 the requested model PSF, the matching kernel size, padding of the science
284 PSF thumbnail
and spatial sampling frequency of the PSF.
286 *Config Guidelines*: The user must specify the size of the model PSF to
287 which to match by setting `config.modelPsf.defaultFwhm`
in units of pixels.
288 The appropriate values depends on science case. In general,
for a set of
289 input images, this config should equal the FWHM of the visit
with the worst
290 seeing. The smallest it should be set to
is the median FWHM. The defaults
291 of the other config options offer a reasonable starting point.
293 The following list presents the most common problems that arise
from a
295 @link ip::diffim::modelPsfMatch::ModelPsfMatchTask ModelPsfMatchTask
297 and corresponding solutions. All assume the default Alard-Lupton kernel,
298 with configs accessed via
299 ```config.warpAndPsfMatch.psfMatch.kernel[
'AL']```. Each item
in the list
301 Problem: Explanation. *Solution*
303 *Troublshooting PSF-Matching Configuration:*
304 - Matched PSFs look boxy: The matching kernel
is too small.
305 _Increase the matching kernel size.
307 config.warpAndPsfMatch.psfMatch.kernel[
'AL'].kernelSize=27
309 Note that increasing the kernel size also increases runtime.
310 - Matched PSFs look ugly (dipoles, quadropoles, donuts): unable to find
311 good solution
for matching kernel.
312 _Provide the matcher
with more data by either increasing
313 the spatial sampling by decreasing the spatial cell size,_
314 config.warpAndPsfMatch.psfMatch.kernel[
'AL'].sizeCellX = 64
316 config.warpAndPsfMatch.psfMatch.kernel[
'AL'].sizeCellY = 64
318 _or increasing the padding around the Science PSF,
for example:_
319 config.warpAndPsfMatch.psfMatch.autoPadPsfTo=1.6
320 Increasing `autoPadPsfTo` increases the minimum ratio of input PSF
321 dimensions to the matching kernel dimensions, thus increasing the
322 number of pixels available to fit after convolving the PSF
with the
323 matching kernel. Optionally,
for debugging the effects of padding, the
324 level of padding may be manually controlled by setting turning off the
325 automatic padding
and setting the number of pixels by which to pad the
327 config.warpAndPsfMatch.psfMatch.doAutoPadPsf =
False
329 config.warpAndPsfMatch.psfMatch.padPsfBy = 6
331 - Deconvolution: Matching a large PSF to a smaller PSF produces
332 a telltale noise pattern which looks like ripples
or a brain.
333 _Increase the size of the requested model PSF. For example:_
334 config.modelPsf.defaultFwhm = 11
336 - High frequency (sometimes checkered) noise: The matching basis functions
338 _Increase the width of the Gaussian basis functions. For example:_
339 config.warpAndPsfMatch.psfMatch.kernel[
'AL'].alardSigGauss=
342 ConfigClass = MakeWarpConfig
343 _DefaultName = "makeWarp"
345 def __init__(self, **kwargs):
346 CoaddBaseTask.__init__(self, **kwargs)
347 self.makeSubtask(
"warpAndPsfMatch")
348 if self.config.hasFakes:
349 self.calexpType =
"fakes_calexp"
351 self.calexpType =
"calexp"
353 @utils.inheritDoc(pipeBase.PipelineTask)
354 def runQuantum(self, butlerQC, inputRefs, outputRefs):
358 detectorOrder = [ref.datasetRef.dataId[
'detector']
for ref
in inputRefs.calExpList]
360 inputRefs = reorderRefs(inputRefs, detectorOrder, dataIdKey=
'detector')
363 inputs = butlerQC.get(inputRefs)
367 skyMap = inputs.pop(
"skyMap")
368 quantumDataId = butlerQC.quantum.dataId
369 skyInfo = makeSkyInfo(skyMap, tractId=quantumDataId[
'tract'], patchId=quantumDataId[
'patch'])
372 dataIdList = [ref.datasetRef.dataId
for ref
in inputRefs.calExpList]
374 ccdIdList = [dataId.pack(
"visit_detector")
for dataId
in dataIdList]
376 if self.config.doApplyExternalSkyWcs:
377 if self.config.useGlobalExternalSkyWcs:
378 externalSkyWcsCatalog = inputs.pop(
"externalSkyWcsGlobalCatalog")
380 externalSkyWcsCatalog = inputs.pop(
"externalSkyWcsTractCatalog")
382 externalSkyWcsCatalog =
None
384 if self.config.doApplyExternalPhotoCalib:
385 if self.config.useGlobalExternalPhotoCalib:
386 externalPhotoCalibCatalog = inputs.pop(
"externalPhotoCalibGlobalCatalog")
388 externalPhotoCalibCatalog = inputs.pop(
"externalPhotoCalibTractCatalog")
390 externalPhotoCalibCatalog =
None
392 if self.config.doApplyFinalizedPsf:
393 finalizedPsfApCorrCatalog = inputs.pop(
"finalizedPsfApCorrCatalog")
395 finalizedPsfApCorrCatalog =
None
399 completeIndices = self._prepareCalibratedExposures(
401 externalSkyWcsCatalog=externalSkyWcsCatalog,
402 externalPhotoCalibCatalog=externalPhotoCalibCatalog,
403 finalizedPsfApCorrCatalog=finalizedPsfApCorrCatalog)
404 inputs = self.filterInputs(indices=completeIndices, inputs=inputs)
410 coordList = [skyInfo.wcs.pixelToSky(pos)
for pos
in cornerPosList]
411 goodIndices = self.select.run(**inputs, coordList=coordList, dataIds=dataIdList)
412 inputs = self.filterInputs(indices=goodIndices, inputs=inputs)
415 visitId = dataIdList[0][
"visit"]
417 results = self.run(**inputs, visitId=visitId,
418 ccdIdList=[ccdIdList[i]
for i
in goodIndices],
419 dataIdList=[dataIdList[i]
for i
in goodIndices],
421 if self.config.makeDirect
and results.exposures[
"direct"]
is not None:
422 butlerQC.put(results.exposures[
"direct"], outputRefs.direct)
423 if self.config.makePsfMatched
and results.exposures[
"psfMatched"]
is not None:
424 butlerQC.put(results.exposures[
"psfMatched"], outputRefs.psfMatched)
427 def run(self, calExpList, ccdIdList, skyInfo, visitId=0, dataIdList=None, **kwargs):
428 """Create a Warp from inputs.
430 We iterate over the multiple calexps in a single exposure to construct
431 the warp (previously called a coaddTempExp) of that exposure to the
432 supplied tract/patch.
434 Pixels that receive no pixels are set to NAN; this
is not correct
435 (violates LSST algorithms group policy), but will be fixed up by
436 interpolating after the coaddition.
438 calexpRefList : `list`
439 List of data references
for calexps that (may)
440 overlap the patch of interest.
441 skyInfo : `lsst.pipe.base.Struct`
442 Struct
from CoaddBaseTask.getSkyInfo()
with geometric
443 information about the patch.
445 Integer identifier
for visit,
for the table that will
446 produce the CoaddPsf.
450 result : `lsst.pipe.base.Struct`
451 Results
as a struct
with attributes:
454 A dictionary containing the warps requested:
455 "direct": direct warp
if ``config.makeDirect``
456 "psfMatched": PSF-matched warp
if ``config.makePsfMatched``
459 warpTypeList = self.getWarpTypeList()
461 totGoodPix = {warpType: 0 for warpType
in warpTypeList}
462 didSetMetadata = {warpType:
False for warpType
in warpTypeList}
463 warps = {warpType: self._prepareEmptyExposure(skyInfo)
for warpType
in warpTypeList}
464 inputRecorder = {warpType: self.inputRecorder.makeCoaddTempExpRecorder(visitId, len(calExpList))
465 for warpType
in warpTypeList}
467 modelPsf = self.config.modelPsf.apply()
if self.config.makePsfMatched
else None
468 if dataIdList
is None:
469 dataIdList = ccdIdList
471 for calExpInd, (calExp, ccdId, dataId)
in enumerate(zip(calExpList, ccdIdList, dataIdList)):
472 self.log.info(
"Processing calexp %d of %d for this Warp: id=%s",
473 calExpInd+1, len(calExpList), dataId)
478 if isinstance(calExp, DeferredDatasetHandle):
479 calExp = calExp.get()
481 warpedAndMatched = self.warpAndPsfMatch.run(calExp, modelPsf=modelPsf,
482 wcs=skyInfo.wcs, maxBBox=skyInfo.bbox,
483 makeDirect=self.config.makeDirect,
484 makePsfMatched=self.config.makePsfMatched)
485 except Exception
as e:
486 self.log.warning(
"WarpAndPsfMatch failed for calexp %s; skipping it: %s", dataId, e)
489 numGoodPix = {warpType: 0
for warpType
in warpTypeList}
490 for warpType
in warpTypeList:
491 exposure = warpedAndMatched.getDict()[warpType]
494 warp = warps[warpType]
495 if didSetMetadata[warpType]:
496 mimg = exposure.getMaskedImage()
497 mimg *= (warp.getPhotoCalib().getInstFluxAtZeroMagnitude()
498 / exposure.getPhotoCalib().getInstFluxAtZeroMagnitude())
501 warp.getMaskedImage(), exposure.getMaskedImage(), self.getBadPixelMask())
502 totGoodPix[warpType] += numGoodPix[warpType]
503 self.log.debug(
"Calexp %s has %d good pixels in this patch (%.1f%%) for %s",
504 dataId, numGoodPix[warpType],
505 100.0*numGoodPix[warpType]/skyInfo.bbox.getArea(), warpType)
506 if numGoodPix[warpType] > 0
and not didSetMetadata[warpType]:
507 warp.info.id = exposure.info.id
508 warp.setPhotoCalib(exposure.getPhotoCalib())
509 warp.setFilter(exposure.getFilter())
510 warp.getInfo().setVisitInfo(exposure.getInfo().getVisitInfo())
513 warp.setPsf(exposure.getPsf())
514 didSetMetadata[warpType] =
True
518 inputRecorder[warpType].addCalExp(calExp, ccdId, numGoodPix[warpType])
520 except Exception
as e:
521 self.log.warning(
"Error processing calexp %s; skipping it: %s", dataId, e)
524 for warpType
in warpTypeList:
525 self.log.info(
"%sWarp has %d good pixels (%.1f%%)",
526 warpType, totGoodPix[warpType], 100.0*totGoodPix[warpType]/skyInfo.bbox.getArea())
528 if totGoodPix[warpType] > 0
and didSetMetadata[warpType]:
529 inputRecorder[warpType].finish(warps[warpType], totGoodPix[warpType])
530 if warpType ==
"direct":
531 warps[warpType].setPsf(
532 CoaddPsf(inputRecorder[warpType].coaddInputs.ccds, skyInfo.wcs,
533 self.config.coaddPsf.makeControl()))
535 if not self.config.doWriteEmptyWarps:
537 warps[warpType] =
None
541 result = pipeBase.Struct(exposures=warps)
544 def filterInputs(self, indices, inputs):
545 """Filter task inputs by their indices.
549 indices : `list` [`int`]
550 inputs : `dict` [`list`]
551 A dictionary of input connections to be passed to run.
555 inputs : `dict` [`list`]
556 Task inputs with their lists filtered by indices.
558 for key
in inputs.keys():
560 if isinstance(inputs[key], list):
561 inputs[key] = [inputs[key][ind]
for ind
in indices]
564 @deprecated(reason=
"This method is deprecated in favor of its leading underscore version, "
565 "_prepareCalibratedfExposures(). Will be removed after v25.",
566 version=
"v25.0", category=FutureWarning)
567 def prepareCalibratedExposures(self, calExpList, backgroundList=None, skyCorrList=None,
568 externalSkyWcsCatalog=None, externalPhotoCalibCatalog=None,
569 finalizedPsfApCorrCatalog=None,
571 """Deprecated function.
573 Please use _prepareCalibratedExposure(), which this delegates to and
574 noting its slightly updated API, instead.
577 calExpList = [ref.get()
for ref
in calExpList]
579 wcsList = [calexp.getWcs()
for calexp
in calExpList]
581 indices = self._prepareCalibratedExposures(calExpList=calExpList, wcsList=wcsList,
582 backgroundList=backgroundList, skyCorrList=skyCorrList,
583 externalSkyWcsCatalog=externalSkyWcsCatalog,
584 externalPhotoCalibCatalog=externalPhotoCalibCatalog,
585 finalizedPsfApCorrCatalog=finalizedPsfApCorrCatalog)
588 def _prepareCalibratedExposures(self, calExpList=[], wcsList=None, backgroundList=None, skyCorrList=None,
589 externalSkyWcsCatalog=None, externalPhotoCalibCatalog=None,
590 finalizedPsfApCorrCatalog=None, **kwargs):
591 """Calibrate and add backgrounds to input calExpList in place.
596 `lsst.daf.butler.DeferredDatasetHandle`]
597 Sequence of calexps to be modified
in place.
599 The WCSs of the calexps
in ``calExpList``. When
600 ``externalSkyCatalog``
is `
None`, these are used to determine
if
601 the calexp should be included
in the warp, namely checking that it
602 is not `
None`. If ``externalSkyCatalog``
is not `
None`, this list
603 will be dynamically updated
with the external sky WCS.
604 backgroundList : `list` [`lsst.afw.math.backgroundList`], optional
605 Sequence of backgrounds to be added back
in if bgSubtracted=
False.
606 skyCorrList : `list` [`lsst.afw.math.backgroundList`], optional
607 Sequence of background corrections to be subtracted
if
610 Exposure catalog
with external skyWcs to be applied
611 if config.doApplyExternalSkyWcs=
True. Catalog uses the detector id
612 for the catalog id, sorted on id
for fast lookup.
614 Exposure catalog
with external photoCalib to be applied
615 if config.doApplyExternalPhotoCalib=
True. Catalog uses the
616 detector id
for the catalog id, sorted on id
for fast lookup.
618 Exposure catalog
with finalized psf models
and aperture correction
619 maps to be applied
if config.doApplyFinalizedPsf=
True. Catalog
620 uses the detector id
for the catalog id, sorted on id
for fast
623 Additional keyword arguments.
627 indices : `list` [`int`]
628 Indices of ``calExpList``
and friends that have valid
631 wcsList = len(calExpList)*[None]
if wcsList
is None else wcsList
632 backgroundList = len(calExpList)*[
None]
if backgroundList
is None else backgroundList
633 skyCorrList = len(calExpList)*[
None]
if skyCorrList
is None else skyCorrList
635 includeCalibVar = self.config.includeCalibVar
638 for index, (calexp, wcs, background, skyCorr)
in enumerate(zip(calExpList,
642 if externalSkyWcsCatalog
is None and wcs
is None:
643 self.log.warning(
"Detector id %d for visit %d has None for skyWcs and will not be "
644 "used in the warp", calexp.dataId[
"detector"], calexp.dataId[
"visit"])
647 if isinstance(calexp, DeferredDatasetHandle):
648 calexp = calexp.get()
650 if not self.config.bgSubtracted:
651 calexp.maskedImage += background.getImage()
653 detectorId = calexp.getInfo().getDetector().getId()
656 if externalPhotoCalibCatalog
is not None:
657 row = externalPhotoCalibCatalog.find(detectorId)
659 self.log.warning(
"Detector id %s not found in externalPhotoCalibCatalog "
660 "and will not be used in the warp.", detectorId)
662 photoCalib = row.getPhotoCalib()
663 if photoCalib
is None:
664 self.log.warning(
"Detector id %s has None for photoCalib in externalPhotoCalibCatalog "
665 "and will not be used in the warp.", detectorId)
667 calexp.setPhotoCalib(photoCalib)
669 photoCalib = calexp.getPhotoCalib()
670 if photoCalib
is None:
671 self.log.warning(
"Detector id %s has None for photoCalib in the calexp "
672 "and will not be used in the warp.", detectorId)
676 if externalSkyWcsCatalog
is not None:
677 row = externalSkyWcsCatalog.find(detectorId)
679 self.log.warning(
"Detector id %s not found in externalSkyWcsCatalog "
680 "and will not be used in the warp.", detectorId)
682 skyWcs = row.getWcs()
683 wcsList[index] = skyWcs
685 self.log.warning(
"Detector id %s has None for skyWcs in externalSkyWcsCatalog "
686 "and will not be used in the warp.", detectorId)
688 calexp.setWcs(skyWcs)
690 skyWcs = calexp.getWcs()
691 wcsList[index] = skyWcs
693 self.log.warning(
"Detector id %s has None for skyWcs in the calexp "
694 "and will not be used in the warp.", detectorId)
698 if finalizedPsfApCorrCatalog
is not None:
699 row = finalizedPsfApCorrCatalog.find(detectorId)
701 self.log.warning(
"Detector id %s not found in finalizedPsfApCorrCatalog "
702 "and will not be used in the warp.", detectorId)
706 self.log.warning(
"Detector id %s has None for psf in finalizedPsfApCorrCatalog "
707 "and will not be used in the warp.", detectorId)
710 apCorrMap = row.getApCorrMap()
711 if apCorrMap
is None:
712 self.log.warning(
"Detector id %s has None for ApCorrMap in finalizedPsfApCorrCatalog "
713 "and will not be used in the warp.", detectorId)
715 calexp.info.setApCorrMap(apCorrMap)
718 calexp.maskedImage = photoCalib.calibrateImage(calexp.maskedImage,
719 includeScaleUncertainty=includeCalibVar)
720 calexp.maskedImage /= photoCalib.getCalibrationMean()
726 if self.config.doApplySkyCorr:
727 calexp.maskedImage -= skyCorr.getImage()
729 indices.append(index)
730 calExpList[index] = calexp
735 def _prepareEmptyExposure(skyInfo):
736 """Produce an empty exposure for a given patch.
740 skyInfo : `lsst.pipe.base.Struct`
741 Struct from CoaddBaseTask.getSkyInfo()
with geometric
742 information about the patch.
746 exp : `lsst.afw.image.exposure.ExposureF`
747 An empty exposure
for a given patch.
749 exp = afwImage.ExposureF(skyInfo.bbox, skyInfo.wcs)
751 .getPlaneBitMask("NO_DATA"), numpy.inf)
754 def getWarpTypeList(self):
755 """Return list of requested warp types per the config.
758 if self.config.makeDirect:
759 warpTypeList.append(
"direct")
760 if self.config.makePsfMatched:
761 warpTypeList.append(
"psfMatched")
765def reorderRefs(inputRefs, outputSortKeyOrder, dataIdKey):
766 """Reorder inputRefs per outputSortKeyOrder.
768 Any inputRefs which are lists will be resorted per specified key e.g.,
769 'detector.' Only iterables will be reordered,
and values can be of type
770 `lsst.pipe.base.connections.DeferredDatasetRef`
or
771 `lsst.daf.butler.core.datasets.ref.DatasetRef`.
773 Returned lists of refs have the same length
as the outputSortKeyOrder.
774 If an outputSortKey
not in the inputRef, then it will be padded
with None.
775 If an inputRef contains an inputSortKey that
is not in the
776 outputSortKeyOrder it will be removed.
780 inputRefs : `lsst.pipe.base.connections.QuantizedConnection`
781 Input references to be reordered
and padded.
782 outputSortKeyOrder : `iterable`
783 Iterable of values to be compared
with inputRef
's dataId[dataIdKey].
785 The data ID key in the dataRefs to compare
with the outputSortKeyOrder.
789 inputRefs : `lsst.pipe.base.connections.QuantizedConnection`
790 Quantized Connection
with sorted DatasetRef values sorted
if iterable.
792 for connectionName, refs
in inputRefs:
793 if isinstance(refs, Iterable):
794 if hasattr(refs[0],
"dataId"):
795 inputSortKeyOrder = [ref.dataId[dataIdKey]
for ref
in refs]
797 inputSortKeyOrder = [ref.datasetRef.dataId[dataIdKey]
for ref
in refs]
798 if inputSortKeyOrder != outputSortKeyOrder:
799 setattr(inputRefs, connectionName,
800 reorderAndPadList(refs, inputSortKeyOrder, outputSortKeyOrder))
A 2-dimensional celestial WCS that transform pixels to ICRS RA/Dec, using the LSST standard for pixel...
A class to contain the data, WCS, and other information needed to describe an image of the sky.
Represent a 2-dimensional array of bitmask pixels.
Custom catalog class for ExposureRecord/Table.
A floating-point coordinate rectangle geometry.
CoaddPsf is the Psf derived to be used for non-PSF-matched Coadd images.
daf::base::PropertySet * set
int copyGoodPixels(lsst::afw::image::Image< ImagePixelT > &destImage, lsst::afw::image::Image< ImagePixelT > const &srcImage)
copy good pixels from one image to another