1 from __future__
import absolute_import, division, print_function
2 from builtins
import zip
3 from builtins
import range
39 from .coaddBase
import CoaddBaseTask, SelectDataIdContainer, scaleVariance
40 from .interpImage
import InterpImageTask
41 from .scaleZeroPoint
import ScaleZeroPointTask
42 from .coaddHelpers
import groupPatchExposures, getGroupDataRef
45 __all__ = [
"AssembleCoaddTask",
"SafeClipAssembleCoaddTask",
"CompareWarpAssembleCoaddTask"]
50 \anchor AssembleCoaddConfig_ 52 \brief Configuration parameters for the \ref AssembleCoaddTask_ "AssembleCoaddTask" 54 warpType = pexConfig.Field(
55 doc=
"Warp name: one of 'direct' or 'psfMatched'",
59 subregionSize = pexConfig.ListField(
61 doc=
"Width, height of stack subregion size; " 62 "make small enough that a full stack of images will fit into memory at once.",
66 statistic = pexConfig.Field(
68 doc=
"Main stacking statistic for aggregating over the epochs.",
71 doSigmaClip = pexConfig.Field(
73 doc=
"Perform sigma clipped outlier rejection with MEANCLIP statistic? (DEPRECATED)",
76 sigmaClip = pexConfig.Field(
78 doc=
"Sigma for outlier rejection; ignored if non-clipping statistic selected.",
81 clipIter = pexConfig.Field(
83 doc=
"Number of iterations of outlier rejection; ignored if non-clipping statistic selected.",
86 calcErrorFromInputVariance = pexConfig.Field(
88 doc=
"Calculate coadd variance from input variance by stacking statistic." 89 "Passed to StatisticsControl.setCalcErrorFromInputVariance()",
92 scaleZeroPoint = pexConfig.ConfigurableField(
93 target=ScaleZeroPointTask,
94 doc=
"Task to adjust the photometric zero point of the coadd temp exposures",
96 doInterp = pexConfig.Field(
97 doc=
"Interpolate over NaN pixels? Also extrapolate, if necessary, but the results are ugly.",
101 interpImage = pexConfig.ConfigurableField(
102 target=InterpImageTask,
103 doc=
"Task to interpolate (and extrapolate) over NaN pixels",
105 doWrite = pexConfig.Field(
106 doc=
"Persist coadd?",
110 doNImage = pexConfig.Field(
111 doc=
"Create image of number of contributing exposures for each pixel",
115 maskPropagationThresholds = pexConfig.DictField(
118 doc=(
"Threshold (in fractional weight) of rejection at which we propagate a mask plane to " 119 "the coadd; that is, we set the mask bit on the coadd if the fraction the rejected frames " 120 "would have contributed exceeds this value."),
121 default={
"SAT": 0.1},
123 removeMaskPlanes = pexConfig.ListField(dtype=str, default=[
"NOT_DEBLENDED"],
124 doc=
"Mask planes to remove before coadding")
133 doMaskBrightObjects = pexConfig.Field(dtype=bool, default=
False,
134 doc=
"Set mask and flag bits for bright objects?")
135 brightObjectMaskName = pexConfig.Field(dtype=str, default=
"BRIGHT_OBJECT",
136 doc=
"Name of mask bit used for bright objects")
138 coaddPsf = pexConfig.ConfigField(
139 doc=
"Configuration for CoaddPsf",
140 dtype=measAlg.CoaddPsfConfig,
144 CoaddBaseTask.ConfigClass.setDefaults(self)
148 CoaddBaseTask.ConfigClass.validate(self)
152 log.warn(
"Config doPsfMatch deprecated. Setting warpType='psfMatched'")
155 log.warn(
'doSigmaClip deprecated. To replicate behavior, setting statistic to "MEANCLIP"')
157 if self.
doInterp and self.
statistic not in [
'MEAN',
'MEDIAN',
'MEANCLIP',
'VARIANCE',
'VARIANCECLIP']:
158 raise ValueError(
"Must set doInterp=False for statistic=%s, which does not " 159 "compute and set a non-zero coadd variance estimate." % (self.
statistic))
161 unstackableStats = [
'NOTHING',
'ERROR',
'ORMASK']
162 if not hasattr(afwMath.Property, self.
statistic)
or self.
statistic in unstackableStats:
163 stackableStats = [str(k)
for k
in afwMath.Property.__members__.keys()
164 if str(k)
not in unstackableStats]
165 raise ValueError(
"statistic %s is not allowed. Please choose one of %s." 177 \anchor AssembleCoaddTask_ 179 \brief Assemble a coadded image from a set of warps (coadded temporary exposures). 181 \section pipe_tasks_assembleCoadd_Contents Contents 182 - \ref pipe_tasks_assembleCoadd_AssembleCoaddTask_Purpose 183 - \ref pipe_tasks_assembleCoadd_AssembleCoaddTask_Initialize 184 - \ref pipe_tasks_assembleCoadd_AssembleCoaddTask_Run 185 - \ref pipe_tasks_assembleCoadd_AssembleCoaddTask_Config 186 - \ref pipe_tasks_assembleCoadd_AssembleCoaddTask_Debug 187 - \ref pipe_tasks_assembleCoadd_AssembleCoaddTask_Example 189 \section pipe_tasks_assembleCoadd_AssembleCoaddTask_Purpose Description 191 \copybrief AssembleCoaddTask_ 193 We want to assemble a coadded image from a set of Warps (also called 194 coadded temporary exposures or coaddTempExps. 195 Each input Warp covers a patch on the sky and corresponds to a single run/visit/exposure of the 196 covered patch. We provide the task with a list of Warps (selectDataList) from which it selects 197 Warps that cover the specified patch (pointed at by dataRef). 198 Each Warp that goes into a coadd will typically have an independent photometric zero-point. 199 Therefore, we must scale each Warp to set it to a common photometric zeropoint. 200 WarpType may be one of 'direct' or 'psfMatched', and the boolean configs config.makeDirect and 201 config.makePsfMatched set which of the warp types will be coadded. 202 The coadd is computed as a mean with optional outlier rejection. 203 Criteria for outlier rejection are set in \ref AssembleCoaddConfig. Finally, Warps can have bad 'NaN' 204 pixels which received no input from the source calExps. We interpolate over these bad (NaN) pixels. 206 AssembleCoaddTask uses several sub-tasks. These are 208 <DT>\ref ScaleZeroPointTask_ "ScaleZeroPointTask"</DT> 209 <DD> create and use an imageScaler object to scale the photometric zeropoint for each Warp</DD> 210 <DT>\ref InterpImageTask_ "InterpImageTask"</DT> 211 <DD>interpolate across bad pixels (NaN) in the final coadd</DD> 213 You can retarget these subtasks if you wish. 215 \section pipe_tasks_assembleCoadd_AssembleCoaddTask_Initialize Task initialization 216 \copydoc \_\_init\_\_ 218 \section pipe_tasks_assembleCoadd_AssembleCoaddTask_Run Invoking the Task 221 \section pipe_tasks_assembleCoadd_AssembleCoaddTask_Config Configuration parameters 222 See \ref AssembleCoaddConfig_ 224 \section pipe_tasks_assembleCoadd_AssembleCoaddTask_Debug Debug variables 225 The \link lsst.pipe.base.cmdLineTask.CmdLineTask command line task\endlink interface supports a 226 flag \c -d to import \b debug.py from your \c PYTHONPATH; see \ref baseDebug for more about \b debug.py files. 227 AssembleCoaddTask has no debug variables of its own. Some of the subtasks may support debug variables. See 228 the documetation for the subtasks for further information. 230 \section pipe_tasks_assembleCoadd_AssembleCoaddTask_Example A complete example of using AssembleCoaddTask 232 AssembleCoaddTask assembles a set of warped images into a coadded image. The AssembleCoaddTask 233 can be invoked by running assembleCoadd.py with the flag '--legacyCoadd'. Usage of assembleCoadd.py expects 234 a data reference to the tract patch and filter to be coadded (specified using 235 '--id = [KEY=VALUE1[^VALUE2[^VALUE3...] [KEY=VALUE1[^VALUE2[^VALUE3...] ...]]') along with a list of 236 Warps to attempt to coadd (specified using 237 '--selectId [KEY=VALUE1[^VALUE2[^VALUE3...] [KEY=VALUE1[^VALUE2[^VALUE3...] ...]]'). Only the Warps 238 that cover the specified tract and patch will be coadded. A list of the available optional 239 arguments can be obtained by calling assembleCoadd.py with the --help command line argument: 241 assembleCoadd.py --help 243 To demonstrate usage of the AssembleCoaddTask in the larger context of multi-band processing, we will generate 244 the HSC-I & -R band coadds from HSC engineering test data provided in the ci_hsc package. To begin, assuming 245 that the lsst stack has been already set up, we must set up the obs_subaru and ci_hsc packages. 246 This defines the environment variable $CI_HSC_DIR and points at the location of the package. The raw HSC 247 data live in the $CI_HSC_DIR/raw directory. To begin assembling the coadds, we must first 250 <DD> process the individual ccds in $CI_HSC_RAW to produce calibrated exposures</DD> 252 <DD> create a skymap that covers the area of the sky present in the raw exposures</DD> 253 <DT>makeCoaddTempExp</DT> 254 <DD> warp the individual calibrated exposures to the tangent plane of the coadd</DD> 256 We can perform all of these steps by running 258 $CI_HSC_DIR scons warp-903986 warp-904014 warp-903990 warp-904010 warp-903988 260 This will produce warped exposures for each visit. To coadd the warped data, we call assembleCoadd.py as 263 assembleCoadd.py --legacyCoadd $CI_HSC_DIR/DATA --id patch=5,4 tract=0 filter=HSC-I \ 264 --selectId visit=903986 ccd=16 --selectId visit=903986 ccd=22 --selectId visit=903986 ccd=23 \ 265 --selectId visit=903986 ccd=100 --selectId visit=904014 ccd=1 --selectId visit=904014 ccd=6 \ 266 --selectId visit=904014 ccd=12 --selectId visit=903990 ccd=18 --selectId visit=903990 ccd=25 \ 267 --selectId visit=904010 ccd=4 --selectId visit=904010 ccd=10 --selectId visit=904010 ccd=100 \ 268 --selectId visit=903988 ccd=16 --selectId visit=903988 ccd=17 --selectId visit=903988 ccd=23 \ 269 --selectId visit=903988 ccd=24 271 that will process the HSC-I band data. The results are written in 272 `$CI_HSC_DIR/DATA/deepCoadd-results/HSC-I`. 274 You may also choose to run: 276 scons warp-903334 warp-903336 warp-903338 warp-903342 warp-903344 warp-903346 277 assembleCoadd.py --legacyCoadd $CI_HSC_DIR/DATA --id patch=5,4 tract=0 filter=HSC-R \ 278 --selectId visit=903334 ccd=16 --selectId visit=903334 ccd=22 --selectId visit=903334 ccd=23 \ 279 --selectId visit=903334 ccd=100 --selectId visit=903336 ccd=17 --selectId visit=903336 ccd=24 \ 280 --selectId visit=903338 ccd=18 --selectId visit=903338 ccd=25 --selectId visit=903342 ccd=4 \ 281 --selectId visit=903342 ccd=10 --selectId visit=903342 ccd=100 --selectId visit=903344 ccd=0 \ 282 --selectId visit=903344 ccd=5 --selectId visit=903344 ccd=11 --selectId visit=903346 ccd=1 \ 283 --selectId visit=903346 ccd=6 --selectId visit=903346 ccd=12 285 to generate the coadd for the HSC-R band if you are interested in following multiBand Coadd processing as 286 discussed in \ref pipeTasks_multiBand (but note that normally, one would use the 287 \ref SafeClipAssembleCoaddTask_ "SafeClipAssembleCoaddTask" rather than AssembleCoaddTask to make the coadd. 289 ConfigClass = AssembleCoaddConfig
290 _DefaultName =
"assembleCoadd" 294 \brief Initialize the task. Create the \ref InterpImageTask "interpImage", 295 & \ref ScaleZeroPointTask "scaleZeroPoint" subtasks. 297 CoaddBaseTask.__init__(self, *args, **kwargs)
298 self.makeSubtask(
"interpImage")
299 self.makeSubtask(
"scaleZeroPoint")
301 if self.config.doMaskBrightObjects:
302 mask = afwImage.Mask()
305 except pexExceptions.LsstCppException:
306 raise RuntimeError(
"Unable to define mask plane for bright objects; planes used are %s" %
307 mask.getMaskPlaneDict().keys())
313 def run(self, dataRef, selectDataList=[]):
315 \brief Assemble a coadd from a set of Warps 317 Coadd a set of Warps. Compute weights to be applied to each Warp and find scalings to 318 match the photometric zeropoint to a reference Warp. Assemble the Warps using 319 \ref assemble. Interpolate over NaNs and optionally write the coadd to disk. Return the coadded 323 \param[in] dataRef: Data reference defining the patch for coaddition and the reference Warp 324 (if config.autoReference=False). Used to access the following data products: 325 - [in] self.config.coaddName + "Coadd_skyMap" 326 - [in] self.config.coaddName + "Coadd_ + <warpType> + "Warp" (optionally) 327 - [out] self.config.coaddName + "Coadd" 328 \param[in] selectDataList[in]: List of data references to Warps. Data to be coadded will be 329 selected from this list based on overlap with the patch defined by dataRef. 331 \return a pipeBase.Struct with fields: 332 - coaddExposure: coadded exposure 333 - nImage: exposure count image 336 calExpRefList = self.
selectExposures(dataRef, skyInfo, selectDataList=selectDataList)
337 if len(calExpRefList) == 0:
338 self.log.warn(
"No exposures to coadd")
340 self.log.info(
"Coadding %d exposures", len(calExpRefList))
344 self.log.info(
"Found %d %s", len(inputData.tempExpRefList),
346 if len(inputData.tempExpRefList) == 0:
347 self.log.warn(
"No coadd temporary exposures found")
352 retStruct = self.
assemble(skyInfo, inputData.tempExpRefList, inputData.imageScalerList,
353 inputData.weightList, supplementaryData=supplementaryData)
355 if self.config.doInterp:
356 self.interpImage.
run(retStruct.coaddExposure.getMaskedImage(), planeName=
"NO_DATA")
358 varArray = retStruct.coaddExposure.getMaskedImage().getVariance().getArray()
359 varArray[:] = numpy.where(varArray > 0, varArray, numpy.inf)
361 if self.config.doMaskBrightObjects:
365 if self.config.doWrite:
368 if self.config.doNImage
and retStruct.nImage
is not None:
375 \brief Make additional inputs to assemble() specific to subclasses. 377 Available to be implemented by subclasses only if they need the 378 coadd dataRef for performing preliminary processing before 379 assembling the coadd. 385 \brief Generate list data references corresponding to warped exposures that lie within the 388 \param[in] patchRef: Data reference for patch 389 \param[in] calExpRefList: List of data references for input calexps 390 \return List of Warp/CoaddTempExp data references 392 butler = patchRef.getButler()
393 groupData =
groupPatchExposures(patchRef, calExpRefList, self.getCoaddDatasetName(self.warpType),
394 self.getTempExpDatasetName(self.warpType))
395 tempExpRefList = [
getGroupDataRef(butler, self.getTempExpDatasetName(self.warpType),
396 g, groupData.keys)
for 397 g
in groupData.groups.keys()]
398 return tempExpRefList
402 \brief Prepare the input warps for coaddition by measuring the weight for each warp and the scaling 403 for the photometric zero point. 405 Each Warp has its own photometric zeropoint and background variance. Before coadding these 406 Warps together, compute a scale factor to normalize the photometric zeropoint and compute the 407 weight for each Warp. 409 \param[in] refList: List of data references to tempExp 411 - tempExprefList: List of data references to tempExp 412 - weightList: List of weightings 413 - imageScalerList: List of image scalers 415 statsCtrl = afwMath.StatisticsControl()
416 statsCtrl.setNumSigmaClip(self.config.sigmaClip)
417 statsCtrl.setNumIter(self.config.clipIter)
419 statsCtrl.setNanSafe(
True)
427 for tempExpRef
in refList:
428 if not tempExpRef.datasetExists(tempExpName):
429 self.log.warn(
"Could not find %s %s; skipping it", tempExpName, tempExpRef.dataId)
432 tempExp = tempExpRef.get(tempExpName, immediate=
True)
433 maskedImage = tempExp.getMaskedImage()
434 imageScaler = self.scaleZeroPoint.computeImageScaler(
439 imageScaler.scaleMaskedImage(maskedImage)
440 except Exception
as e:
441 self.log.warn(
"Scaling failed for %s (skipping it): %s", tempExpRef.dataId, e)
443 statObj = afwMath.makeStatistics(maskedImage.getVariance(), maskedImage.getMask(),
444 afwMath.MEANCLIP, statsCtrl)
445 meanVar, meanVarErr = statObj.getResult(afwMath.MEANCLIP)
446 weight = 1.0 / float(meanVar)
447 if not numpy.isfinite(weight):
448 self.log.warn(
"Non-finite weight for %s: skipping", tempExpRef.dataId)
450 self.log.info(
"Weight of %s %s = %0.3f", tempExpName, tempExpRef.dataId, weight)
455 tempExpRefList.append(tempExpRef)
456 weightList.append(weight)
457 imageScalerList.append(imageScaler)
459 return pipeBase.Struct(tempExpRefList=tempExpRefList, weightList=weightList,
460 imageScalerList=imageScalerList)
462 def assemble(self, skyInfo, tempExpRefList, imageScalerList, weightList,
463 altMaskList=None, mask=None, supplementaryData=None):
465 \anchor AssembleCoaddTask.assemble_ 467 \brief Assemble a coadd from input warps 469 Assemble the coadd using the provided list of coaddTempExps. Since the full coadd covers a patch (a 470 large area), the assembly is performed over small areas on the image at a time in order to 471 conserve memory usage. Iterate over subregions within the outer bbox of the patch using 472 \ref assembleSubregion to stack the corresponding subregions from the coaddTempExps with the 473 statistic specified. Set the edge bits the coadd mask based on the weight map. 475 \param[in] skyInfo: Patch geometry information, from getSkyInfo 476 \param[in] tempExpRefList: List of data references to Warps (previously called CoaddTempExps) 477 \param[in] imageScalerList: List of image scalers 478 \param[in] weightList: List of weights 479 \param[in] altMaskList: List of alternate masks to use rather than those stored with tempExp, or None 480 \param[in] mask: Mask to ignore when coadding 481 \param[in] supplementaryData: pipeBase.Struct with additional data products needed to assemble coadd. 482 Only used by subclasses that implement makeSupplementaryData and override assemble. 483 \return pipeBase.Struct with coaddExposure, nImage if requested 486 self.log.info(
"Assembling %s %s", len(tempExpRefList), tempExpName)
490 statsCtrl = afwMath.StatisticsControl()
491 statsCtrl.setNumSigmaClip(self.config.sigmaClip)
492 statsCtrl.setNumIter(self.config.clipIter)
493 statsCtrl.setAndMask(mask)
494 statsCtrl.setNanSafe(
True)
495 statsCtrl.setWeighted(
True)
496 statsCtrl.setCalcErrorFromInputVariance(self.config.calcErrorFromInputVariance)
497 for plane, threshold
in self.config.maskPropagationThresholds.items():
498 bit = afwImage.Mask.getMaskPlane(plane)
499 statsCtrl.setMaskPropagationThreshold(bit, threshold)
501 statsFlags = afwMath.stringToStatisticsProperty(self.config.statistic)
503 if altMaskList
is None:
504 altMaskList = [
None]*len(tempExpRefList)
506 coaddExposure = afwImage.ExposureF(skyInfo.bbox, skyInfo.wcs)
507 coaddExposure.setCalib(self.scaleZeroPoint.getCalib())
508 coaddExposure.getInfo().setCoaddInputs(self.inputRecorder.makeCoaddInputs())
510 coaddMaskedImage = coaddExposure.getMaskedImage()
511 subregionSizeArr = self.config.subregionSize
512 subregionSize = afwGeom.Extent2I(subregionSizeArr[0], subregionSizeArr[1])
514 if self.config.doNImage:
515 nImage = afwImage.ImageU(skyInfo.bbox)
518 for subBBox
in _subBBoxIter(skyInfo.bbox, subregionSize):
521 weightList, altMaskList, statsFlags, statsCtrl,
523 except Exception
as e:
524 self.log.fatal(
"Cannot compute coadd %s: %s", subBBox, e)
526 self.
setEdge(coaddMaskedImage.getMask())
530 coaddUtils.setCoaddEdgeBits(coaddMaskedImage.getMask(), coaddMaskedImage.getVariance())
531 return pipeBase.Struct(coaddExposure=coaddExposure, nImage=nImage)
535 \brief Set the metadata for the coadd 537 This basic implementation simply sets the filter from the 540 \param[in] coaddExposure: The target image for the coadd 541 \param[in] tempExpRefList: List of data references to tempExp 542 \param[in] weightList: List of weights 544 assert len(tempExpRefList) == len(weightList),
"Length mismatch" 549 tempExpList = [tempExpRef.get(tempExpName +
"_sub",
550 bbox=afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(1, 1)),
551 imageOrigin=
"LOCAL", immediate=
True)
for tempExpRef
in tempExpRefList]
552 numCcds = sum(len(tempExp.getInfo().getCoaddInputs().ccds)
for tempExp
in tempExpList)
554 coaddExposure.setFilter(tempExpList[0].getFilter())
555 coaddInputs = coaddExposure.getInfo().getCoaddInputs()
556 coaddInputs.ccds.reserve(numCcds)
557 coaddInputs.visits.reserve(len(tempExpList))
559 for tempExp, weight
in zip(tempExpList, weightList):
560 self.inputRecorder.addVisitToCoadd(coaddInputs, tempExp, weight)
561 coaddInputs.visits.sort()
567 modelPsfList = [tempExp.getPsf()
for tempExp
in tempExpList]
568 modelPsfWidthList = [modelPsf.computeBBox().getWidth()
for modelPsf
in modelPsfList]
569 psf = modelPsfList[modelPsfWidthList.index(max(modelPsfWidthList))]
571 psf = measAlg.CoaddPsf(coaddInputs.ccds, coaddExposure.getWcs(),
572 self.config.coaddPsf.makeControl())
573 coaddExposure.setPsf(psf)
574 apCorrMap = measAlg.makeCoaddApCorrMap(coaddInputs.ccds, coaddExposure.getBBox(afwImage.PARENT),
575 coaddExposure.getWcs())
576 coaddExposure.getInfo().setApCorrMap(apCorrMap)
578 def assembleSubregion(self, coaddExposure, bbox, tempExpRefList, imageScalerList, weightList,
579 altMaskList, statsFlags, statsCtrl, nImage=None):
581 \brief Assemble the coadd for a sub-region. 583 For each coaddTempExp, check for (and swap in) an alternative mask if one is passed. Remove mask 584 planes listed in config.removeMaskPlanes, Finally, stack the actual exposures using 585 \ref afwMath.statisticsStack "statisticsStack" with the statistic specified 586 by statsFlags. Typically, the statsFlag will be one of afwMath.MEAN for a mean-stack or 587 afwMath.MEANCLIP for outlier rejection using an N-sigma clipped mean where N and iterations 588 are specified by statsCtrl. Assign the stacked subregion back to the coadd. 590 \param[in] coaddExposure: The target image for the coadd 591 \param[in] bbox: Sub-region to coadd 592 \param[in] tempExpRefList: List of data reference to tempExp 593 \param[in] imageScalerList: List of image scalers 594 \param[in] weightList: List of weights 595 \param[in] altMaskList: List of alternate masks to use rather than those stored with tempExp, or None 596 Each element is dict with keys = mask plane name to which to add the spans 597 \param[in] statsFlags: afwMath.Property object for statistic for coadd 598 \param[in] statsCtrl: Statistics control object for coadd 599 \param[in] nImage: optional ImageU keeps track of exposure count for each pixel 601 self.log.debug(
"Computing coadd over %s", bbox)
603 coaddMaskedImage = coaddExposure.getMaskedImage()
604 coaddMaskedImage.getMask().addMaskPlane(
"CLIPPED")
606 if nImage
is not None:
607 subNImage = afwImage.ImageU(bbox.getWidth(), bbox.getHeight())
608 for tempExpRef, imageScaler, altMask
in zip(tempExpRefList, imageScalerList, altMaskList):
609 exposure = tempExpRef.get(tempExpName +
"_sub", bbox=bbox)
610 maskedImage = exposure.getMaskedImage()
611 mask = maskedImage.getMask()
612 if altMask
is not None:
614 imageScaler.scaleMaskedImage(maskedImage)
618 if nImage
is not None:
619 subNImage.getArray()[maskedImage.getMask().getArray() & statsCtrl.getAndMask() == 0] += 1
620 if self.config.removeMaskPlanes:
621 mask = maskedImage.getMask()
622 for maskPlane
in self.config.removeMaskPlanes:
624 mask &= ~mask.getPlaneBitMask(maskPlane)
625 except Exception
as e:
626 self.log.warn(
"Unable to remove mask plane %s: %s", maskPlane, e.args[0])
628 maskedImageList.append(maskedImage)
630 with self.timer(
"stack"):
631 coaddSubregion = afwMath.statisticsStack(maskedImageList, statsFlags, statsCtrl, weightList,
632 coaddMaskedImage.getMask().getPlaneBitMask(
"CLIPPED"),
633 coaddMaskedImage.getMask().getPlaneBitMask(
"NO_DATA"))
634 coaddMaskedImage.assign(coaddSubregion, bbox)
635 if nImage
is not None:
636 nImage.assign(subNImage, bbox)
640 \brief Apply in place alt mask formatted as SpanSets to a mask 642 @param mask: original mask 643 @param altMaskSpans: Dictionary containing spanSet lists to apply. 644 Each element contains the new mask plane name 645 (e.g. "CLIPPED and/or "NO_DATA") as the key, 646 and list of SpanSets to apply to the mask 648 for plane, spanSetList
in altMaskSpans.items():
649 maskClipValue = mask.addMaskPlane(plane)
650 for spanSet
in spanSetList:
651 spanSet.clippedTo(mask.getBBox()).setMask(mask, 2**maskClipValue)
655 """Returns None on failure""" 657 return dataRef.get(
"brightObjectMask", immediate=
True)
658 except Exception
as e:
659 self.log.warn(
"Unable to read brightObjectMask for %s: %s", dataRef.dataId, e)
663 """Set the bright object masks 665 exposure: Exposure under consideration 666 dataId: Data identifier dict for patch 667 brightObjectMasks: afwTable of bright objects to mask 672 if brightObjectMasks
is None:
673 self.log.warn(
"Unable to apply bright object mask: none supplied")
675 self.log.info(
"Applying %d bright object masks to %s", len(brightObjectMasks), dataId)
676 md = brightObjectMasks.table.getMetadata()
679 self.log.warn(
"Expected to see %s in metadata", k)
681 if md.get(k) != dataId[k]:
682 self.log.warn(
"Expected to see %s == %s in metadata, saw %s", k, md.get(k), dataId[k])
684 mask = exposure.getMaskedImage().getMask()
685 wcs = exposure.getWcs()
686 plateScale = wcs.pixelScale().asArcseconds()
688 for rec
in brightObjectMasks:
689 center = afwGeom.PointI(wcs.skyToPixel(rec.getCoord()))
690 if rec[
"type"] ==
"box":
691 assert rec[
"angle"] == 0.0, (
"Angle != 0 for mask object %s" % rec[
"id"])
692 width = rec[
"width"].asArcseconds()/plateScale
693 height = rec[
"height"].asArcseconds()/plateScale
695 halfSize = afwGeom.ExtentI(0.5*width, 0.5*height)
696 bbox = afwGeom.Box2I(center - halfSize, center + halfSize)
698 bbox = afwGeom.BoxI(afwGeom.PointI(int(center[0] - 0.5*width), int(center[1] - 0.5*height)),
699 afwGeom.PointI(int(center[0] + 0.5*width), int(center[1] + 0.5*height)))
700 spans = afwGeom.SpanSet(bbox)
701 elif rec[
"type"] ==
"circle":
702 radius = int(rec[
"radius"].asArcseconds()/plateScale)
703 spans = afwGeom.SpanSet.fromShape(radius, offset=center)
705 self.log.warn(
"Unexpected region type %s at %s" % rec[
"type"], center)
710 """Set EDGE bits as SENSOR_EDGE 712 The EDGE pixels from the individual CCDs have printed through into the 713 coadd, but EDGE means "we couldn't search for sources in this area 714 because we couldn't convolve by the PSF near the edge of the image", 715 so this mask plane needs to be converted to something else if we want 716 to keep them. We do want to be able to identify pixels near the edge 717 of the detector because they will have an inexact `CoaddPsf`. We 718 rename EDGE pixels as SENSOR_EDGE. 722 mask : `lsst.afw.image.Mask` 723 Coadded exposure's mask, modified in-place. 725 mask.addMaskPlane(
"SENSOR_EDGE")
726 edge = mask.getPlaneBitMask(
"EDGE")
727 sensorEdge = mask.getPlaneBitMask(
"SENSOR_EDGE")
728 array = mask.getArray()
729 selected = (array & edge > 0)
730 array[selected] |= sensorEdge
731 array[selected] &= ~edge
734 """Set INEXACT_PSF mask plane 736 If any of the input images isn't represented in the coadd (due to 737 clipped pixels or chip gaps), the `CoaddPsf` will be inexact. Flag 742 mask : `lsst.afw.image.Mask` 743 Coadded exposure's mask, modified in-place. 745 mask.addMaskPlane(
"INEXACT_PSF")
746 inexactPsf = mask.getPlaneBitMask(
"INEXACT_PSF")
747 sensorEdge = mask.getPlaneBitMask(
"SENSOR_EDGE")
748 clipped = mask.getPlaneBitMask(
"CLIPPED")
749 array = mask.getArray()
750 selected = array & (sensorEdge | clipped) > 0
751 array[selected] |= inexactPsf
754 def _makeArgumentParser(cls):
756 \brief Create an argument parser 759 parser.add_id_argument(
"--id", cls.
ConfigClass().coaddName +
"Coadd_" +
761 help=
"data ID, e.g. --id tract=12345 patch=1,2",
762 ContainerClass=AssembleCoaddDataIdContainer)
763 parser.add_id_argument(
"--selectId",
"calexp", help=
"data ID, e.g. --selectId visit=6789 ccd=0..9",
764 ContainerClass=SelectDataIdContainer)
768 def _subBBoxIter(bbox, subregionSize):
770 \brief Iterate over subregions of a bbox 772 \param[in] bbox: bounding box over which to iterate: afwGeom.Box2I 773 \param[in] subregionSize: size of sub-bboxes 775 \return subBBox: next sub-bounding box of size subregionSize or smaller; 776 each subBBox is contained within bbox, so it may be smaller than subregionSize at the edges of bbox, 777 but it will never be empty 780 raise RuntimeError(
"bbox %s is empty" % (bbox,))
781 if subregionSize[0] < 1
or subregionSize[1] < 1:
782 raise RuntimeError(
"subregionSize %s must be nonzero" % (subregionSize,))
784 for rowShift
in range(0, bbox.getHeight(), subregionSize[1]):
785 for colShift
in range(0, bbox.getWidth(), subregionSize[0]):
786 subBBox = afwGeom.Box2I(bbox.getMin() + afwGeom.Extent2I(colShift, rowShift), subregionSize)
788 if subBBox.isEmpty():
789 raise RuntimeError(
"Bug: empty bbox! bbox=%s, subregionSize=%s, colShift=%s, rowShift=%s" %
790 (bbox, subregionSize, colShift, rowShift))
796 \brief A version of lsst.pipe.base.DataIdContainer specialized for assembleCoadd. 801 \brief Make self.refList from self.idList. 803 datasetType = namespace.config.coaddName +
"Coadd" 804 keysCoadd = namespace.butler.getKeys(datasetType=datasetType, level=self.level)
806 for dataId
in self.idList:
808 for key
in keysCoadd:
809 if key
not in dataId:
810 raise RuntimeError(
"--id must include " + key)
812 dataRef = namespace.butler.dataRef(
813 datasetType=datasetType,
816 self.refList.append(dataRef)
821 \brief Function to count the number of pixels with a specific mask in a footprint. 823 Find the intersection of mask & footprint. Count all pixels in the mask that are in the intersection that 824 have bitmask set but do not have ignoreMask set. Return the count. 826 \param[in] mask: mask to define intersection region by. 827 \parma[in] footprint: footprint to define the intersection region by. 828 \param[in] bitmask: specific mask that we wish to count the number of occurances of. 829 \param[in] ignoreMask: pixels to not consider. 830 \return count of number of pixels in footprint with specified mask. 832 bbox = footprint.getBBox()
833 bbox.clip(mask.getBBox(afwImage.PARENT))
834 fp = afwImage.Mask(bbox)
835 subMask = mask.Factory(mask, bbox, afwImage.PARENT)
836 footprint.spans.setMask(fp, bitmask)
837 return numpy.logical_and((subMask.getArray() & fp.getArray()) > 0,
838 (subMask.getArray() & ignoreMask) == 0).sum()
843 \anchor SafeClipAssembleCoaddConfig 845 \brief Configuration parameters for the SafeClipAssembleCoaddTask 847 clipDetection = pexConfig.ConfigurableField(
848 target=SourceDetectionTask,
849 doc=
"Detect sources on difference between unclipped and clipped coadd")
850 minClipFootOverlap = pexConfig.Field(
851 doc=
"Minimum fractional overlap of clipped footprint with visit DETECTED to be clipped",
855 minClipFootOverlapSingle = pexConfig.Field(
856 doc=
"Minimum fractional overlap of clipped footprint with visit DETECTED to be " 857 "clipped when only one visit overlaps",
861 minClipFootOverlapDouble = pexConfig.Field(
862 doc=
"Minimum fractional overlap of clipped footprints with visit DETECTED to be " 863 "clipped when two visits overlap",
867 maxClipFootOverlapDouble = pexConfig.Field(
868 doc=
"Maximum fractional overlap of clipped footprints with visit DETECTED when " 869 "considering two visits",
873 minBigOverlap = pexConfig.Field(
874 doc=
"Minimum number of pixels in footprint to use DETECTED mask from the single visits " 875 "when labeling clipped footprints",
883 AssembleCoaddConfig.setDefaults(self)
899 log.warn(
"Additional Sigma-clipping not allowed in Safe-clipped Coadds. " 900 "Ignoring doSigmaClip.")
903 raise ValueError(
"Only MEAN statistic allowed for final stacking in SafeClipAssembleCoadd " 904 "(%s chosen). Please set statistic to MEAN." 906 AssembleCoaddTask.ConfigClass.validate(self)
919 \anchor SafeClipAssembleCoaddTask_ 921 \brief Assemble a coadded image from a set of coadded temporary exposures, 922 being careful to clip & flag areas with potential artifacts. 924 \section pipe_tasks_assembleCoadd_Contents Contents 925 - \ref pipe_tasks_assembleCoadd_SafeClipAssembleCoaddTask_Purpose 926 - \ref pipe_tasks_assembleCoadd_SafeClipAssembleCoaddTask_Initialize 927 - \ref pipe_tasks_assembleCoadd_SafeClipAssembleCoaddTask_Run 928 - \ref pipe_tasks_assembleCoadd_SafeClipAssembleCoaddTask_Config 929 - \ref pipe_tasks_assembleCoadd_SafeClipAssembleCoaddTask_Debug 930 - \ref pipe_tasks_assembleCoadd_SafeClipAssembleCoaddTask_Example 932 \section pipe_tasks_assembleCoadd_SafeClipAssembleCoaddTask_Purpose Description 934 \copybrief SafeClipAssembleCoaddTask 936 Read the documentation for \ref AssembleCoaddTask_ "AssembleCoaddTask" first since 937 SafeClipAssembleCoaddTask subtasks that task. 938 In \ref AssembleCoaddTask_ "AssembleCoaddTask", we compute the coadd as an clipped mean (i.e. we clip 940 The problem with doing this is that when computing the coadd PSF at a given location, individual visit 941 PSFs from visits with outlier pixels contribute to the coadd PSF and cannot be treated correctly. 942 In this task, we correct for this behavior by creating a new badMaskPlane 'CLIPPED'. 943 We populate this plane on the input coaddTempExps and the final coadd where i. difference imaging suggests 944 that there is an outlier and ii. this outlier appears on only one or two images. 945 Such regions will not contribute to the final coadd. 946 Furthermore, any routine to determine the coadd PSF can now be cognizant of clipped regions. 947 Note that the algorithm implemented by this task is preliminary and works correctly for HSC data. 948 Parameter modifications and or considerable redesigning of the algorithm is likley required for other 951 SafeClipAssembleCoaddTask uses a \ref SourceDetectionTask_ "clipDetection" subtask and also sub-classes 952 \ref AssembleCoaddTask_ "AssembleCoaddTask". You can retarget the 953 \ref SourceDetectionTask_ "clipDetection" subtask if you wish. 955 \section pipe_tasks_assembleCoadd_SafeClipAssembleCoaddTask_Initialize Task initialization 956 \copydoc \_\_init\_\_ 958 \section pipe_tasks_assembleCoadd_SafeClipAssembleCoaddTask_Run Invoking the Task 961 \section pipe_tasks_assembleCoadd_SafeClipAssembleCoaddTask_Config Configuration parameters 962 See \ref SafeClipAssembleCoaddConfig 964 \section pipe_tasks_assembleCoadd_SafeClipAssembleCoaddTask_Debug Debug variables 965 The \link lsst.pipe.base.cmdLineTask.CmdLineTask command line task\endlink interface supports a 966 flag \c -d to import \b debug.py from your \c PYTHONPATH; see \ref baseDebug for more about \b debug.py 968 SafeClipAssembleCoaddTask has no debug variables of its own. The \ref SourceDetectionTask_ "clipDetection" 969 subtasks may support debug variables. See the documetation for \ref SourceDetectionTask_ "clipDetection" 970 for further information. 972 \section pipe_tasks_assembleCoadd_SafeClipAssembleCoaddTask_Example A complete example of using 973 SafeClipAssembleCoaddTask 975 SafeClipAssembleCoaddTask assembles a set of warped coaddTempExp images into a coadded image. 976 The SafeClipAssembleCoaddTask is invoked by running assembleCoadd.py <em>without</em> the flag 978 Usage of assembleCoadd.py expects a data reference to the tract patch and filter to be coadded 979 (specified using '--id = [KEY=VALUE1[^VALUE2[^VALUE3...] [KEY=VALUE1[^VALUE2[^VALUE3...] ...]]') along 980 with a list of coaddTempExps to attempt to coadd (specified using 981 '--selectId [KEY=VALUE1[^VALUE2[^VALUE3...] [KEY=VALUE1[^VALUE2[^VALUE3...] ...]]'). 982 Only the coaddTempExps that cover the specified tract and patch will be coadded. 983 A list of the available optional arguments can be obtained by calling assembleCoadd.py with the --help 984 command line argument: 986 assembleCoadd.py --help 988 To demonstrate usage of the SafeClipAssembleCoaddTask in the larger context of multi-band processing, we 989 will generate the HSC-I & -R band coadds from HSC engineering test data provided in the ci_hsc package. To 990 begin, assuming that the lsst stack has been already set up, we must set up the obs_subaru and ci_hsc 992 This defines the environment variable $CI_HSC_DIR and points at the location of the package. The raw HSC 993 data live in the $CI_HSC_DIR/raw directory. To begin assembling the coadds, we must first 996 <DD> process the individual ccds in $CI_HSC_RAW to produce calibrated exposures</DD> 998 <DD> create a skymap that covers the area of the sky present in the raw exposures</DD> 999 <DT>makeCoaddTempExp</DT> 1000 <DD> warp the individual calibrated exposures to the tangent plane of the coadd</DD> 1002 We can perform all of these steps by running 1004 $CI_HSC_DIR scons warp-903986 warp-904014 warp-903990 warp-904010 warp-903988 1006 This will produce warped coaddTempExps for each visit. To coadd the warped data, we call assembleCoadd.py 1009 assembleCoadd.py $CI_HSC_DIR/DATA --id patch=5,4 tract=0 filter=HSC-I \ 1010 --selectId visit=903986 ccd=16 --selectId visit=903986 ccd=22 --selectId visit=903986 ccd=23 \ 1011 --selectId visit=903986 ccd=100--selectId visit=904014 ccd=1 --selectId visit=904014 ccd=6 \ 1012 --selectId visit=904014 ccd=12 --selectId visit=903990 ccd=18 --selectId visit=903990 ccd=25 \ 1013 --selectId visit=904010 ccd=4 --selectId visit=904010 ccd=10 --selectId visit=904010 ccd=100 \ 1014 --selectId visit=903988 ccd=16 --selectId visit=903988 ccd=17 --selectId visit=903988 ccd=23 \ 1015 --selectId visit=903988 ccd=24 1017 This will process the HSC-I band data. The results are written in 1018 `$CI_HSC_DIR/DATA/deepCoadd-results/HSC-I`. 1020 You may also choose to run: 1022 scons warp-903334 warp-903336 warp-903338 warp-903342 warp-903344 warp-903346 1023 assembleCoadd.py $CI_HSC_DIR/DATA --id patch=5,4 tract=0 filter=HSC-R --selectId visit=903334 ccd=16 \ 1024 --selectId visit=903334 ccd=22 --selectId visit=903334 ccd=23 --selectId visit=903334 ccd=100 \ 1025 --selectId visit=903336 ccd=17 --selectId visit=903336 ccd=24 --selectId visit=903338 ccd=18 \ 1026 --selectId visit=903338 ccd=25 --selectId visit=903342 ccd=4 --selectId visit=903342 ccd=10 \ 1027 --selectId visit=903342 ccd=100 --selectId visit=903344 ccd=0 --selectId visit=903344 ccd=5 \ 1028 --selectId visit=903344 ccd=11 --selectId visit=903346 ccd=1 --selectId visit=903346 ccd=6 \ 1029 --selectId visit=903346 ccd=12 1031 to generate the coadd for the HSC-R band if you are interested in following multiBand Coadd processing as 1032 discussed in \ref pipeTasks_multiBand. 1034 ConfigClass = SafeClipAssembleCoaddConfig
1035 _DefaultName =
"safeClipAssembleCoadd" 1039 \brief Initialize the task and make the \ref SourceDetectionTask_ "clipDetection" subtask. 1041 AssembleCoaddTask.__init__(self, *args, **kwargs)
1042 schema = afwTable.SourceTable.makeMinimalSchema()
1043 self.makeSubtask(
"clipDetection", schema=schema)
1045 def assemble(self, skyInfo, tempExpRefList, imageScalerList, weightList, *args, **kwargs):
1047 \brief Assemble the coadd for a region 1049 Compute the difference of coadds created with and without outlier rejection to identify coadd pixels 1050 that have outlier values in some individual visits. Detect clipped regions on the difference image and 1051 mark these regions on the one or two individual coaddTempExps where they occur if there is significant 1052 overlap between the clipped region and a source. 1053 This leaves us with a set of footprints from the difference image that have been identified as having 1054 occured on just one or two individual visits. However, these footprints were generated from a 1055 difference image. It is conceivable for a large diffuse source to have become broken up into multiple 1056 footprints acrosss the coadd difference in this process. 1057 Determine the clipped region from all overlapping footprints from the detected sources in each visit - 1058 these are big footprints. 1059 Combine the small and big clipped footprints and mark them on a new bad mask plane 1060 Generate the coadd using \ref AssembleCoaddTask.assemble_ "AssembleCoaddTask.assemble" without outlier 1061 removal. Clipped footprints will no longer make it into the coadd because they are marked in the new 1064 N.b. *args and **kwargs are passed but ignored in order to match the call signature expected by the 1067 @param skyInfo: Patch geometry information, from getSkyInfo 1068 @param tempExpRefList: List of data reference to tempExp 1069 @param imageScalerList: List of image scalers 1070 @param weightList: List of weights 1071 return pipeBase.Struct with coaddExposure, nImage 1074 mask = exp.getMaskedImage().getMask()
1075 mask.addMaskPlane(
"CLIPPED")
1077 result = self.
detectClip(exp, tempExpRefList)
1079 self.log.info(
'Found %d clipped objects', len(result.clipFootprints))
1081 maskClipValue = mask.getPlaneBitMask(
"CLIPPED")
1082 maskDetValue = mask.getPlaneBitMask(
"DETECTED") | mask.getPlaneBitMask(
"DETECTED_NEGATIVE")
1084 bigFootprints = self.
detectClipBig(result.clipSpans, result.clipFootprints, result.clipIndices,
1085 result.detectionFootprints, maskClipValue, maskDetValue,
1088 maskClip = mask.Factory(mask.getBBox(afwImage.PARENT))
1089 afwDet.setMaskFromFootprintList(maskClip, result.clipFootprints, maskClipValue)
1091 maskClipBig = maskClip.Factory(mask.getBBox(afwImage.PARENT))
1092 afwDet.setMaskFromFootprintList(maskClipBig, bigFootprints, maskClipValue)
1093 maskClip |= maskClipBig
1096 badMaskPlanes = self.config.badMaskPlanes[:]
1097 badMaskPlanes.append(
"CLIPPED")
1098 badPixelMask = afwImage.Mask.getPlaneBitMask(badMaskPlanes)
1099 return AssembleCoaddTask.assemble(self, skyInfo, tempExpRefList, imageScalerList, weightList,
1100 result.clipSpans, mask=badPixelMask)
1104 \brief Return an exposure that contains the difference between and unclipped and clipped coadds. 1106 Generate a difference image between clipped and unclipped coadds. 1107 Compute the difference image by subtracting an outlier-clipped coadd from an outlier-unclipped coadd. 1108 Return the difference image. 1110 @param skyInfo: Patch geometry information, from getSkyInfo 1111 @param tempExpRefList: List of data reference to tempExp 1112 @param imageScalerList: List of image scalers 1113 @param weightList: List of weights 1114 @return Difference image of unclipped and clipped coadd wrapped in an Exposure 1119 configIntersection = {k: getattr(self.config, k)
1120 for k, v
in self.config.toDict().items()
if (k
in config.keys())}
1121 config.update(**configIntersection)
1124 config.statistic =
'MEAN' 1126 coaddMean = task.assemble(skyInfo, tempExpRefList, imageScalerList, weightList).coaddExposure
1128 config.statistic =
'MEANCLIP' 1130 coaddClip = task.assemble(skyInfo, tempExpRefList, imageScalerList, weightList).coaddExposure
1132 coaddDiff = coaddMean.getMaskedImage().Factory(coaddMean.getMaskedImage())
1133 coaddDiff -= coaddClip.getMaskedImage()
1134 exp = afwImage.ExposureF(coaddDiff)
1135 exp.setPsf(coaddMean.getPsf())
1140 \brief Detect clipped regions on an exposure and set the mask on the individual tempExp masks 1142 Detect footprints in the difference image after smoothing the difference image with a Gaussian kernal. 1143 Identify footprints that overlap with one or two input coaddTempExps by comparing the computed overlap 1144 fraction to thresholds set in the config. 1145 A different threshold is applied depending on the number of overlapping visits (restricted to one or 1147 If the overlap exceeds the thresholds, the footprint is considered "CLIPPED" and is marked as such on 1149 Return a struct with the clipped footprints, the indices of the coaddTempExps that end up overlapping 1150 with the clipped footprints and a list of new masks for the coaddTempExps. 1152 \param[in] exp: Exposure to run detection on 1153 \param[in] tempExpRefList: List of data reference to tempExp 1154 \return struct containing: 1155 - clipFootprints: list of clipped footprints 1156 - clipIndices: indices for each clippedFootprint in tempExpRefList 1157 - clipSpans: List of dictionaries containing spanSet lists to clip. Each element contains the new 1158 maskplane name ("CLIPPED")" as the key and list of SpanSets as value 1159 - detectionFootprints: List of DETECTED/DETECTED_NEGATIVE plane compressed into footprints 1161 mask = exp.getMaskedImage().getMask()
1162 maskDetValue = mask.getPlaneBitMask(
"DETECTED") | mask.getPlaneBitMask(
"DETECTED_NEGATIVE")
1163 fpSet = self.clipDetection.detectFootprints(exp, doSmooth=
True, clearMask=
True)
1165 fpSet.positive.merge(fpSet.negative)
1166 footprints = fpSet.positive
1167 self.log.info(
'Found %d potential clipped objects', len(footprints.getFootprints()))
1172 artifactSpanSets = [{
'CLIPPED': list()}
for _
in tempExpRefList]
1175 visitDetectionFootprints = []
1177 dims = [len(tempExpRefList), len(footprints.getFootprints())]
1178 overlapDetArr = numpy.zeros(dims, dtype=numpy.uint16)
1179 ignoreArr = numpy.zeros(dims, dtype=numpy.uint16)
1182 for i, warpRef
in enumerate(tempExpRefList):
1184 immediate=
True).getMaskedImage().getMask()
1185 maskVisitDet = tmpExpMask.Factory(tmpExpMask, tmpExpMask.getBBox(afwImage.PARENT),
1186 afwImage.PARENT,
True)
1187 maskVisitDet &= maskDetValue
1188 visitFootprints = afwDet.FootprintSet(maskVisitDet, afwDet.Threshold(1))
1189 visitDetectionFootprints.append(visitFootprints)
1191 for j, footprint
in enumerate(footprints.getFootprints()):
1196 for j, footprint
in enumerate(footprints.getFootprints()):
1197 nPixel = footprint.getArea()
1200 for i
in range(len(tempExpRefList)):
1201 ignore = ignoreArr[i, j]
1202 overlapDet = overlapDetArr[i, j]
1203 totPixel = nPixel - ignore
1206 if ignore > overlapDet
or totPixel <= 0.5*nPixel
or overlapDet == 0:
1208 overlap.append(overlapDet/float(totPixel))
1211 overlap = numpy.array(overlap)
1212 if not len(overlap):
1219 if len(overlap) == 1:
1220 if overlap[0] > self.config.minClipFootOverlapSingle:
1225 clipIndex = numpy.where(overlap > self.config.minClipFootOverlap)[0]
1226 if len(clipIndex) == 1:
1228 keepIndex = [clipIndex[0]]
1231 clipIndex = numpy.where(overlap > self.config.minClipFootOverlapDouble)[0]
1232 if len(clipIndex) == 2
and len(overlap) > 3:
1233 clipIndexComp = numpy.where(overlap <= self.config.minClipFootOverlapDouble)[0]
1234 if numpy.max(overlap[clipIndexComp]) <= self.config.maxClipFootOverlapDouble:
1236 keepIndex = clipIndex
1241 for index
in keepIndex:
1242 globalIndex = indexList[index]
1243 artifactSpanSets[globalIndex][
'CLIPPED'].append(footprint.spans)
1245 clipIndices.append(numpy.array(indexList)[keepIndex])
1246 clipFootprints.append(footprint)
1248 return pipeBase.Struct(clipFootprints=clipFootprints, clipIndices=clipIndices,
1249 clipSpans=artifactSpanSets, detectionFootprints=visitDetectionFootprints)
1251 def detectClipBig(self, clipList, clipFootprints, clipIndices, detectionFootprints,
1252 maskClipValue, maskDetValue, coaddBBox):
1254 \brief Return individual warp footprints for large artifacts and append them to clipList in place 1256 Identify big footprints composed of many sources in the coadd difference that may have originated in a 1257 large diffuse source in the coadd. We do this by indentifying all clipped footprints that overlap 1258 significantly with each source in all the coaddTempExps. 1259 \param[in] clipList: List of alt mask SpanSets with clipping information. Modified. 1260 \param[in] clipFootprints: List of clipped footprints 1261 \param[in] clipIndices: List of which entries in tempExpClipList each footprint belongs to 1262 \param[in] maskClipValue: Mask value of clipped pixels 1263 \param[in] maskDetValue: Mask value of detected pixels 1264 \param[in] coaddBBox: BBox of the coadd and warps 1265 \return list of big footprints 1267 bigFootprintsCoadd = []
1269 for index, (clippedSpans, visitFootprints)
in enumerate(zip(clipList, detectionFootprints)):
1270 maskVisitDet = afwImage.MaskX(coaddBBox, 0x0)
1271 for footprint
in visitFootprints.getFootprints():
1272 footprint.spans.setMask(maskVisitDet, maskDetValue)
1275 clippedFootprintsVisit = []
1276 for foot, clipIndex
in zip(clipFootprints, clipIndices):
1277 if index
not in clipIndex:
1279 clippedFootprintsVisit.append(foot)
1280 maskVisitClip = maskVisitDet.Factory(maskVisitDet.getBBox(afwImage.PARENT))
1281 afwDet.setMaskFromFootprintList(maskVisitClip, clippedFootprintsVisit, maskClipValue)
1283 bigFootprintsVisit = []
1284 for foot
in visitFootprints.getFootprints():
1285 if foot.getArea() < self.config.minBigOverlap:
1288 if nCount > self.config.minBigOverlap:
1289 bigFootprintsVisit.append(foot)
1290 bigFootprintsCoadd.append(foot)
1292 for footprint
in bigFootprintsVisit:
1293 clippedSpans[
"CLIPPED"].append(footprint.spans)
1295 return bigFootprintsCoadd
1299 assembleStaticSkyModel = pexConfig.ConfigurableField(
1300 target=AssembleCoaddTask,
1301 doc=
"Task to assemble an artifact-free, PSF-matched Coadd to serve as a" 1302 " naive/first-iteration model of the static sky.",
1304 detect = pexConfig.ConfigurableField(
1305 target=SourceDetectionTask,
1306 doc=
"Detect outlier sources on difference between each psfMatched warp and static sky model" 1308 maxNumEpochs = pexConfig.Field(
1309 doc=
"Charactistic maximum local number of epochs/visits in which an artifact candidate can appear " 1310 "and still be masked. The effective maxNumEpochs is a broken linear function of local " 1311 "number of epochs (N): min(maxFractionEpochsLow*N, maxNumEpochs + maxFractionEpochsHigh*N). " 1312 "For each footprint detected on the image difference between the psfMatched warp and static sky " 1313 "model, if a significant fraction of pixels (defined by spatialThreshold) are residuals in more " 1314 "than the computed effective maxNumEpochs, the artifact candidate is deemed persistant rather " 1315 "than transient and not masked.",
1319 maxFractionEpochsLow = pexConfig.RangeField(
1320 doc=
"Fraction of local number of epochs (N) to use as effective maxNumEpochs for low N. " 1321 "Effective maxNumEpochs = " 1322 "min(maxFractionEpochsLow * N, maxNumEpochs + maxFractionEpochsHigh * N)",
1327 maxFractionEpochsHigh = pexConfig.RangeField(
1328 doc=
"Fraction of local number of epochs (N) to use as effective maxNumEpochs for high N. " 1329 "Effective maxNumEpochs = " 1330 "min(maxFractionEpochsLow * N, maxNumEpochs + maxFractionEpochsHigh * N)",
1335 spatialThreshold = pexConfig.RangeField(
1336 doc=
"Unitless fraction of pixels defining how much of the outlier region has to meet the " 1337 "temporal criteria. If 0, clip all. If 1, clip none.",
1341 inclusiveMin=
True, inclusiveMax=
True 1343 doScaleWarpVariance = pexConfig.Field(
1344 doc=
"Rescale Warp variance plane using empirical noise?",
1348 maskScaleWarpVariance = pexConfig.ListField(
1350 default=[
"DETECTED",
"BAD",
"SAT",
"NO_DATA",
"INTRP"],
1351 doc=
"Mask planes for pixels to ignore when rescaling warp variance",
1355 AssembleCoaddConfig.setDefaults(self)
1364 self.
detect.doTempLocalBackground =
False 1365 self.
detect.reEstimateBackground =
False 1366 self.
detect.returnOriginalFootprints =
False 1367 self.
detect.thresholdPolarity =
"both" 1368 self.
detect.thresholdValue = 5
1369 self.
detect.nSigmaToGrow = 2
1370 self.
detect.minPixels = 4
1371 self.
detect.isotropicGrow =
True 1372 self.
detect.thresholdType =
"pixel_stdev" 1384 \anchor CompareWarpAssembleCoaddTask_ 1386 \brief Assemble a compareWarp coadded image from a set of warps 1387 by masking artifacts detected by comparing PSF-matched warps 1389 \section pipe_tasks_assembleCoadd_Contents Contents 1390 - \ref pipe_tasks_assembleCoadd_CompareWarpAssembleCoaddTask_Purpose 1391 - \ref pipe_tasks_assembleCoadd_CompareWarpAssembleCoaddTask_Initialize 1392 - \ref pipe_tasks_assembleCoadd_CompareWarpAssembleCoaddTask_Run 1393 - \ref pipe_tasks_assembleCoadd_CompareWarpAssembleCoaddTask_Config 1394 - \ref pipe_tasks_assembleCoadd_CompareWarpAssembleCoaddTask_Debug 1395 - \ref pipe_tasks_assembleCoadd_CompareWarpAssembleCoaddTask_Example 1397 \section pipe_tasks_assembleCoadd_CompareWarpAssembleCoaddTask_Purpose Description 1399 \copybrief CompareWarpAssembleCoaddTask 1401 In \ref AssembleCoaddTask_ "AssembleCoaddTask", we compute the coadd as an clipped mean (i.e. we clip 1403 The problem with doing this is that when computing the coadd PSF at a given location, individual visit 1404 PSFs from visits with outlier pixels contribute to the coadd PSF and cannot be treated correctly. 1405 In this task, we correct for this behavior by creating a new badMaskPlane 'CLIPPED' which marks 1406 pixels in the individual warps suspected to contain an artifact. 1407 We populate this plane on the input warps by comparing PSF-matched warps with a PSF-matched median coadd 1408 which serves as a model of the static sky. Any group of pixels that deviates from the PSF-matched 1409 template coadd by more than config.detect.threshold sigma, is an artifact candidate. 1410 The candidates are then filtered to remove variable sources and sources that are difficult to subtract 1411 such as bright stars. 1412 This filter is configured using the config parameters temporalThreshold and spatialThreshold. 1413 The temporalThreshold is the maximum fraction of epochs that the deviation can 1414 appear in and still be considered an artifact. The spatialThreshold is the maximum fraction of pixels in 1415 the footprint of the deviation that appear in other epochs (where other epochs is defined by the 1416 temporalThreshold). If the deviant region meets this criteria of having a significant percentage of pixels 1417 that deviate in only a few epochs, these pixels have the 'CLIPPED' bit set in the mask. 1418 These regions will not contribute to the final coadd. 1419 Furthermore, any routine to determine the coadd PSF can now be cognizant of clipped regions. 1420 Note that the algorithm implemented by this task is preliminary and works correctly for HSC data. 1421 Parameter modifications and or considerable redesigning of the algorithm is likley required for other 1424 CompareWarpAssembleCoaddTask sub-classes 1425 \ref AssembleCoaddTask_ "AssembleCoaddTask" and instantiates \ref AssembleCoaddTask_ "AssembleCoaddTask" 1426 as a subtask to generate the TemplateCoadd (the model of the static sky) 1428 \section pipe_tasks_assembleCoadd_CompareWarpAssembleCoaddTask_Initialize Task initialization 1429 \copydoc \_\_init\_\_ 1431 \section pipe_tasks_assembleCoadd_CompareWarpAssembleCoaddTask_Run Invoking the Task 1434 \section pipe_tasks_assembleCoadd_CompareWarpAssembleCoaddTask_Config Configuration parameters 1435 See \ref CompareWarpAssembleCoaddConfig 1437 \section pipe_tasks_assembleCoadd_CompareWarpAssembleCoaddTask_Debug Debug variables 1438 The \link lsst.pipe.base.cmdLineTask.CmdLineTask command line task\endlink interface supports a 1439 flag \c -d to import \b debug.py from your \c PYTHONPATH; see \ref baseDebug for more about \b debug.py 1442 This task supports the following debug variables: 1445 <dd> If True then save the Epoch Count Image as a fits file in the `figPath` 1447 <dd> Path to save the debug fits images and figures 1450 For example, put something like: 1453 def DebugInfo(name): 1454 di = lsstDebug.getInfo(name) 1455 if name == "lsst.pipe.tasks.assembleCoadd": 1456 di.saveCountIm = True 1457 di.figPath = "/desired/path/to/debugging/output/images" 1459 lsstDebug.Info = DebugInfo 1461 into your `debug.py` file and run `assemebleCoadd.py` with the `--debug` 1463 Some subtasks may have their own debug variables; see individual Task 1466 \section pipe_tasks_assembleCoadd_CompareWarpAssembleCoaddTask_Example A complete example of using 1467 CompareWarpAssembleCoaddTask 1469 CompareWarpAssembleCoaddTask assembles a set of warped images into a coadded image. 1470 The CompareWarpAssembleCoaddTask is invoked by running assembleCoadd.py with the flag 1471 '--compareWarpCoadd'. 1472 Usage of assembleCoadd.py expects a data reference to the tract patch and filter to be coadded 1473 (specified using '--id = [KEY=VALUE1[^VALUE2[^VALUE3...] [KEY=VALUE1[^VALUE2[^VALUE3...] ...]]') along 1474 with a list of coaddTempExps to attempt to coadd (specified using 1475 '--selectId [KEY=VALUE1[^VALUE2[^VALUE3...] [KEY=VALUE1[^VALUE2[^VALUE3...] ...]]'). 1476 Only the warps that cover the specified tract and patch will be coadded. 1477 A list of the available optional arguments can be obtained by calling assembleCoadd.py with the --help 1478 command line argument: 1480 assembleCoadd.py --help 1482 To demonstrate usage of the CompareWarpAssembleCoaddTask in the larger context of multi-band processing, 1483 we will generate the HSC-I & -R band coadds from HSC engineering test data provided in the ci_hsc package. 1484 To begin, assuming that the lsst stack has been already set up, we must set up the obs_subaru and ci_hsc 1486 This defines the environment variable $CI_HSC_DIR and points at the location of the package. The raw HSC 1487 data live in the $CI_HSC_DIR/raw directory. To begin assembling the coadds, we must first 1490 <DD> process the individual ccds in $CI_HSC_RAW to produce calibrated exposures</DD> 1492 <DD> create a skymap that covers the area of the sky present in the raw exposures</DD> 1493 <DT>makeCoaddTempExp</DT> 1494 <DD> warp the individual calibrated exposures to the tangent plane of the coadd</DD> 1496 We can perform all of these steps by running 1498 $CI_HSC_DIR scons warp-903986 warp-904014 warp-903990 warp-904010 warp-903988 1500 This will produce warped coaddTempExps for each visit. To coadd the warped data, we call assembleCoadd.py 1503 assembleCoadd.py --compareWarpCoadd $CI_HSC_DIR/DATA --id patch=5,4 tract=0 filter=HSC-I \ 1504 --selectId visit=903986 ccd=16 --selectId visit=903986 ccd=22 --selectId visit=903986 ccd=23 \ 1505 --selectId visit=903986 ccd=100 --selectId visit=904014 ccd=1 --selectId visit=904014 ccd=6 \ 1506 --selectId visit=904014 ccd=12 --selectId visit=903990 ccd=18 --selectId visit=903990 ccd=25 \ 1507 --selectId visit=904010 ccd=4 --selectId visit=904010 ccd=10 --selectId visit=904010 ccd=100 \ 1508 --selectId visit=903988 ccd=16 --selectId visit=903988 ccd=17 --selectId visit=903988 ccd=23 \ 1509 --selectId visit=903988 ccd=24 1511 This will process the HSC-I band data. The results are written in 1512 `$CI_HSC_DIR/DATA/deepCoadd-results/HSC-I`. 1514 ConfigClass = CompareWarpAssembleCoaddConfig
1515 _DefaultName =
"compareWarpAssembleCoadd" 1519 \brief Initialize the task and make the \ref AssembleCoadd_ "assembleStaticSkyModel" subtask. 1521 AssembleCoaddTask.__init__(self, *args, **kwargs)
1522 self.makeSubtask(
"assembleStaticSkyModel")
1523 detectionSchema = afwTable.SourceTable.makeMinimalSchema()
1524 self.makeSubtask(
"detect", schema=detectionSchema)
1528 \brief Make inputs specific to Subclass 1530 Generate a templateCoadd to use as a native model of static sky to subtract from warps. 1532 templateCoadd = self.assembleStaticSkyModel.
run(dataRef, selectDataList)
1534 if templateCoadd
is None:
1535 warpName = (self.assembleStaticSkyModel.warpType[0].upper() +
1536 self.assembleStaticSkyModel.warpType[1:])
1537 message =
"""No %(warpName)s warps were found to build the template coadd which is 1538 required to run CompareWarpAssembleCoaddTask. To continue assembling this type of coadd, 1539 first either rerun makeCoaddTempExp with config.make%(warpName)s=True or 1540 coaddDriver with config.makeCoadTempExp.make%(warpName)s=True, before assembleCoadd. 1542 Alternatively, to use another algorithm with existing warps, retarget the CoaddDriverConfig to 1543 another algorithm like: 1545 from lsst.pipe.tasks.assembleCoadd import SafeClipAssembleCoaddTask 1546 config.assemble.retarget(SafeClipAssembleCoaddTask) 1547 """ % {
"warpName": warpName}
1548 raise RuntimeError(message)
1550 return pipeBase.Struct(templateCoadd=templateCoadd.coaddExposure)
1552 def assemble(self, skyInfo, tempExpRefList, imageScalerList, weightList,
1553 supplementaryData, *args, **kwargs):
1555 \brief Assemble the coadd 1557 Requires additional inputs Struct `supplementaryData` to contain a `templateCoadd` that serves 1558 as the model of the static sky. 1560 Find artifacts and apply them to the warps' masks creating a list of alternative masks with a 1561 new "CLIPPED" plane and updated "NO_DATA" plane. 1562 Then pass these alternative masks to the base class's assemble method. 1564 @param skyInfo: Patch geometry information 1565 @param tempExpRefList: List of data references to warps 1566 @param imageScalerList: List of image scalers 1567 @param weightList: List of weights 1568 @param supplementaryData: PipeBase.Struct containing a templateCoadd 1570 return pipeBase.Struct with coaddExposure, nImage if requested 1572 templateCoadd = supplementaryData.templateCoadd
1573 spanSetMaskList = self.
findArtifacts(templateCoadd, tempExpRefList, imageScalerList)
1574 badMaskPlanes = self.config.badMaskPlanes[:]
1575 badMaskPlanes.append(
"CLIPPED")
1576 badPixelMask = afwImage.Mask.getPlaneBitMask(badMaskPlanes)
1578 return AssembleCoaddTask.assemble(self, skyInfo, tempExpRefList, imageScalerList, weightList,
1579 spanSetMaskList, mask=badPixelMask)
1583 \brief Find artifacts 1585 Loop through warps twice. The first loop builds a map with the count of how many 1586 epochs each pixel deviates from the templateCoadd by more than config.chiThreshold sigma. 1587 The second loop takes each difference image and filters the artifacts detected 1588 in each using count map to filter out variable sources and sources that are difficult to 1591 @param templateCoadd: Exposure to serve as model of static sky 1592 @param tempExpRefList: List of data references to warps 1593 @param imageScalerList: List of image scalers 1596 self.log.debug(
"Generating Count Image, and mask lists.")
1597 coaddBBox = templateCoadd.getBBox()
1598 slateIm = afwImage.ImageU(coaddBBox)
1599 epochCountImage = afwImage.ImageU(coaddBBox)
1600 nImage = afwImage.ImageU(coaddBBox)
1601 spanSetArtifactList = []
1602 spanSetNoDataMaskList = []
1604 for warpRef, imageScaler
in zip(tempExpRefList, imageScalerList):
1606 if warpDiffExp
is not None:
1607 nImage.array += numpy.where(numpy.isnan(warpDiffExp.image.array),
1608 0, 1).astype(numpy.uint16)
1609 fpSet = self.detect.detectFootprints(warpDiffExp, doSmooth=
False, clearMask=
True)
1610 fpSet.positive.merge(fpSet.negative)
1611 footprints = fpSet.positive
1613 spanSetList = [footprint.spans
for footprint
in footprints.getFootprints()]
1614 for spans
in spanSetList:
1615 spans.setImage(slateIm, 1, doClip=
True)
1616 epochCountImage += slateIm
1622 nans = numpy.where(numpy.isnan(warpDiffExp.maskedImage.image.array), 1, 0)
1623 nansMask = afwImage.makeMaskFromArray(nans.astype(afwImage.MaskPixel))
1624 nansMask.setXY0(warpDiffExp.getXY0())
1628 nansMask = afwImage.MaskX(coaddBBox, 1)
1631 spanSetNoDataMask = afwGeom.SpanSet.fromMask(nansMask).split()
1633 spanSetNoDataMaskList.append(spanSetNoDataMask)
1634 spanSetArtifactList.append(spanSetList)
1638 epochCountImage.writeFits(path)
1640 for i, spanSetList
in enumerate(spanSetArtifactList):
1642 filteredSpanSetList = self.
_filterArtifacts(spanSetList, epochCountImage, nImage)
1643 spanSetArtifactList[i] = filteredSpanSetList
1646 for artifacts, noData
in zip(spanSetArtifactList, spanSetNoDataMaskList):
1647 altMasks.append({
'CLIPPED': artifacts,
1651 def _filterArtifacts(self, spanSetList, epochCountImage, nImage):
1653 \brief Filter artifact candidates 1655 @param spanSetList: List of SpanSets representing artifact candidates 1656 @param epochCountImage: Image of accumulated number of warpDiff detections 1657 @param nImage: Image of the accumulated number of total epochs contributing 1659 return List of SpanSets with artifacts 1662 maskSpanSetList = []
1663 x0, y0 = epochCountImage.getXY0()
1664 for i, span
in enumerate(spanSetList):
1665 y, x = span.indices()
1666 yIdxLocal = [y1 - y0
for y1
in y]
1667 xIdxLocal = [x1 - x0
for x1
in x]
1668 outlierN = epochCountImage.array[yIdxLocal, xIdxLocal]
1669 totalN = nImage.array[yIdxLocal, xIdxLocal]
1672 effMaxNumEpochsHighN = (self.config.maxNumEpochs +
1673 self.config.maxFractionEpochsHigh*numpy.mean(totalN))
1674 effMaxNumEpochsLowN = self.config.maxFractionEpochsLow * numpy.mean(totalN)
1675 effectiveMaxNumEpochs = int(min(effMaxNumEpochsLowN, effMaxNumEpochsHighN))
1676 nPixelsBelowThreshold = numpy.count_nonzero((outlierN > 0) &
1677 (outlierN <= effectiveMaxNumEpochs))
1678 percentBelowThreshold = nPixelsBelowThreshold / len(outlierN)
1679 if percentBelowThreshold > self.config.spatialThreshold:
1680 maskSpanSetList.append(span)
1681 return maskSpanSetList
1683 def _readAndComputeWarpDiff(self, warpRef, imageScaler, templateCoadd):
1685 \brief Fetch a warp from the butler and return a warpDiff 1687 @param warpRef: `Butler dataRef` for the warp 1688 @param imageScaler: `scaleZeroPoint.ImageScaler` object 1689 @param templateCoadd: Exposure to be substracted from the scaled warp 1691 return Exposure of the image difference between the warp and template 1696 if not warpRef.datasetExists(warpName):
1697 self.log.warn(
"Could not find %s %s; skipping it", warpName, warpRef.dataId)
1699 warp = warpRef.get(warpName, immediate=
True)
1701 imageScaler.scaleMaskedImage(warp.getMaskedImage())
1702 mi = warp.getMaskedImage()
1703 if self.config.doScaleWarpVariance:
1706 mi -= templateCoadd.getMaskedImage()
1709 def _dataRef2DebugPath(self, prefix, warpRef, coaddLevel=False):
1711 \brief Return a path to which to write debugging output 1713 @param prefix: string, prefix for filename 1714 @param warpRef: Butler dataRef 1715 @param coaddLevel: bool, optional. If True, include only coadd-level keys 1716 (e.g. 'tract', 'patch', 'filter', but no 'visit') 1718 Creates a hyphen-delimited string of dataId values for simple filenames. 1723 keys = warpRef.dataId.keys()
1724 keyList = sorted(keys, reverse=
True)
1726 filename =
"%s-%s.fits" % (prefix,
'-'.join([str(warpRef.dataId[k])
for k
in keyList]))
1727 return os.path.join(directory, filename)
def setBrightObjectMasks(self, exposure, dataId, brightObjectMasks)
def getCoaddDatasetName(self, warpType="direct")
def _dataRef2DebugPath(self, prefix, warpRef, coaddLevel=False)
Return a path to which to write debugging output.
def getGroupDataRef(butler, datasetType, groupTuple, keys)
Base class for coaddition.
def findArtifacts(self, templateCoadd, tempExpRefList, imageScalerList)
Find artifacts.
def assembleMetadata(self, coaddExposure, tempExpRefList, weightList)
Set the metadata for the coadd.
def makeSupplementaryData(self, dataRef, selectDataList)
Make additional inputs to assemble() specific to subclasses.
def makeSupplementaryData(self, dataRef, selectDataList)
Make inputs specific to Subclass.
def getTempExpRefList(self, patchRef, calExpRefList)
Generate list data references corresponding to warped exposures that lie within the patch to be coadd...
def assemble(self, skyInfo, tempExpRefList, imageScalerList, weightList, args, kwargs)
Assemble the coadd for a region.
def run(self, dataRef, selectDataList=[])
Assemble a coadd from a set of Warps.
def _readAndComputeWarpDiff(self, warpRef, imageScaler, templateCoadd)
Fetch a warp from the butler and return a warpDiff.
def prepareInputs(self, refList)
Prepare the input warps for coaddition by measuring the weight for each warp and the scaling for the ...
def applyAltMaskPlanes(self, mask, altMaskSpans)
Apply in place alt mask formatted as SpanSets to a mask.
def getSkyInfo(self, patchRef)
Use getSkyinfo to return the skyMap, tract and patch information, wcs and the outer bbox of the patch...
def getTempExpDatasetName(self, warpType="direct")
def __init__(self, args, kwargs)
Initialize the task and make the assembleStaticSkyModel subtask.
def makeDataRefList(self, namespace)
Make self.refList from self.idList.
def getBadPixelMask(self)
Convenience method to provide the bitmask from the mask plane names.
def assembleSubregion(self, coaddExposure, bbox, tempExpRefList, imageScalerList, weightList, altMaskList, statsFlags, statsCtrl, nImage=None)
Assemble the coadd for a sub-region.
def detectClip(self, exp, tempExpRefList)
Detect clipped regions on an exposure and set the mask on the individual tempExp masks.
def setInexactPsf(self, mask)
Configuration parameters for the SafeClipAssembleCoaddTask.
def __init__(self, args, kwargs)
Initialize the task.
Assemble a coadded image from a set of warps (coadded temporary exposures).
Assemble a coadded image from a set of coadded temporary exposures, being careful to clip & flag area...
def buildDifferenceImage(self, skyInfo, tempExpRefList, imageScalerList, weightList)
Return an exposure that contains the difference between and unclipped and clipped coadds...
def selectExposures(self, patchRef, skyInfo=None, selectDataList=[])
Select exposures to coadd.
def readBrightObjectMasks(self, dataRef)
Configuration parameters for the AssembleCoaddTask.
Assemble a compareWarp coadded image from a set of warps by masking artifacts detected by comparing P...
def scaleVariance(maskedImage, maskPlanes, log=None)
Scale the variance in a maskedImage.
def __init__(self, args, kwargs)
Initialize the task and make the clipDetection subtask.
def assemble(self, skyInfo, tempExpRefList, imageScalerList, weightList, supplementaryData, args, kwargs)
Assemble the coadd.
def _filterArtifacts(self, spanSetList, epochCountImage, nImage)
Filter artifact candidates.
A version of lsst.pipe.base.DataIdContainer specialized for assembleCoadd.
def countMaskFromFootprint(mask, footprint, bitmask, ignoreMask)
Function to count the number of pixels with a specific mask in a footprint.
def groupPatchExposures(patchDataRef, calexpDataRefList, coaddDatasetType="deepCoadd", tempExpDatasetType="deepCoadd_directWarp")
def assemble(self, skyInfo, tempExpRefList, imageScalerList, weightList, altMaskList=None, mask=None, supplementaryData=None)
Assemble a coadd from input warps.
def detectClipBig(self, clipList, clipFootprints, clipIndices, detectionFootprints, maskClipValue, maskDetValue, coaddBBox)
Return individual warp footprints for large artifacts and append them to clipList in place...