1 from __future__
import division, absolute_import
2 from __future__
import print_function
3 from builtins
import zip
4 from builtins
import range
38 from .coaddBase
import CoaddBaseTask, SelectDataIdContainer
39 from .interpImage
import InterpImageTask
40 from .matchBackgrounds
import MatchBackgroundsTask
41 from .scaleZeroPoint
import ScaleZeroPointTask
42 from .coaddHelpers
import groupPatchExposures, getGroupDataRef
45 __all__ = [
"AssembleCoaddTask",
"SafeClipAssembleCoaddTask"]
50 \anchor AssembleCoaddConfig_
52 \brief Configuration parameters for the \ref AssembleCoaddTask_ "AssembleCoaddTask"
54 subregionSize = pexConfig.ListField(
56 doc=
"Width, height of stack subregion size; "
57 "make small enough that a full stack of images will fit into memory at once.",
61 doSigmaClip = pexConfig.Field(
63 doc=
"Perform sigma clipped outlier rejection? If False then compute a simple mean.",
66 sigmaClip = pexConfig.Field(
68 doc=
"Sigma for outlier rejection; ignored if doSigmaClip false.",
71 clipIter = pexConfig.Field(
73 doc=
"Number of iterations of outlier rejection; ignored if doSigmaClip false.",
76 scaleZeroPoint = pexConfig.ConfigurableField(
77 target=ScaleZeroPointTask,
78 doc=
"Task to adjust the photometric zero point of the coadd temp exposures",
80 doInterp = pexConfig.Field(
81 doc=
"Interpolate over NaN pixels? Also extrapolate, if necessary, but the results are ugly.",
85 interpImage = pexConfig.ConfigurableField(
86 target=InterpImageTask,
87 doc=
"Task to interpolate (and extrapolate) over NaN pixels",
89 matchBackgrounds = pexConfig.ConfigurableField(
90 target=MatchBackgroundsTask,
91 doc=
"Task to match backgrounds",
93 maxMatchResidualRatio = pexConfig.Field(
94 doc=
"Maximum ratio of the mean squared error of the background matching model to the variance "
95 "of the difference in backgrounds",
99 maxMatchResidualRMS = pexConfig.Field(
100 doc=
"Maximum RMS of residuals of the background offset fit in matchBackgrounds.",
104 doWrite = pexConfig.Field(
105 doc=
"Persist coadd?",
109 doMatchBackgrounds = pexConfig.Field(
110 doc=
"Match backgrounds of coadd temp exposures before coadding them? "
111 "If False, the coadd temp expsosures must already have been background subtracted or matched",
115 autoReference = pexConfig.Field(
116 doc=
"Automatically select the coadd temp exposure to use as a reference for background matching? "
117 "Ignored if doMatchBackgrounds false. "
118 "If False you must specify the reference temp exposure as the data Id",
122 maskPropagationThresholds = pexConfig.DictField(
125 doc=(
"Threshold (in fractional weight) of rejection at which we propagate a mask plane to "
126 "the coadd; that is, we set the mask bit on the coadd if the fraction the rejected frames "
127 "would have contributed exceeds this value."),
128 default={
"SAT": 0.1},
130 removeMaskPlanes = pexConfig.ListField(dtype=str, default=[
"CROSSTALK",
"NOT_DEBLENDED"],
131 doc=
"Mask planes to remove before coadding")
140 doMaskBrightObjects = pexConfig.Field(dtype=bool, default=
False,
141 doc=
"Set mask and flag bits for bright objects?")
142 brightObjectMaskName = pexConfig.Field(dtype=str, default=
"BRIGHT_OBJECT",
143 doc=
"Name of mask bit used for bright objects")
146 CoaddBaseTask.ConfigClass.setDefaults(self)
159 \anchor AssembleCoaddTask_
161 \brief Assemble a coadded image from a set of coadded temporary exposures.
163 \section pipe_tasks_assembleCoadd_Contents Contents
164 - \ref pipe_tasks_assembleCoadd_AssembleCoaddTask_Purpose
165 - \ref pipe_tasks_assembleCoadd_AssembleCoaddTask_Initialize
166 - \ref pipe_tasks_assembleCoadd_AssembleCoaddTask_Run
167 - \ref pipe_tasks_assembleCoadd_AssembleCoaddTask_Config
168 - \ref pipe_tasks_assembleCoadd_AssembleCoaddTask_Debug
169 - \ref pipe_tasks_assembleCoadd_AssembleCoaddTask_Example
171 \section pipe_tasks_assembleCoadd_AssembleCoaddTask_Purpose Description
173 \copybrief AssembleCoaddTask_
175 We want to assemble a coadded image from a set of coadded temporary exposures (coaddTempExps).
176 Each input coaddTempExp covers a patch on the sky and corresponds to a single run/visit/exposure of the
177 covered patch. We provide the task with a list of coaddTempExps (selectDataList) from which it selects
178 coaddTempExps that cover the specified patch (pointed at by dataRef).
179 Each coaddTempExp that goes into a coadd will typically have an independent photometric zero-point.
180 Therefore, we must scale each coaddTempExp to set it to a common photometric zeropoint. By default, each
181 coaddTempExp has backgrounds and hence will require config.doMatchBackgrounds=True.
182 When background matching is enabled, the task may be configured to automatically select a reference exposure
183 (config.autoReference=True). If this is not done, we require that the input dataRef provides access to a
184 coaddTempExp (dataset type coaddName + 'Coadd_tempExp') which is used as the reference exposure.
185 The coadd is computed as a mean with optional outlier rejection.
186 Criteria for outlier rejection are set in \ref AssembleCoaddConfig. Finally, coaddTempExps can have bad 'NaN'
187 pixels which received no input from the source calExps. We interpolate over these bad (NaN) pixels.
189 AssembleCoaddTask uses several sub-tasks. These are
191 <DT>\ref ScaleZeroPointTask_ "ScaleZeroPointTask"</DT>
192 <DD> create and use an imageScaler object to scale the photometric zeropoint for each coaddTempExp</DD>
193 <DT>\ref MatchBackgroundsTask_ "MatchBackgroundsTask"</DT>
194 <DD> match background in a coaddTempExp to a reference exposure (and select the reference exposure if one is
196 <DT>\ref InterpImageTask_ "InterpImageTask"</DT>
197 <DD>interpolate across bad pixels (NaN) in the final coadd</DD>
199 You can retarget these subtasks if you wish.
201 \section pipe_tasks_assembleCoadd_AssembleCoaddTask_Initialize Task initialization
202 \copydoc \_\_init\_\_
204 \section pipe_tasks_assembleCoadd_AssembleCoaddTask_Run Invoking the Task
207 \section pipe_tasks_assembleCoadd_AssembleCoaddTask_Config Configuration parameters
208 See \ref AssembleCoaddConfig_
210 \section pipe_tasks_assembleCoadd_AssembleCoaddTask_Debug Debug variables
211 The \link lsst.pipe.base.cmdLineTask.CmdLineTask command line task\endlink interface supports a
212 flag \c -d to import \b debug.py from your \c PYTHONPATH; see \ref baseDebug for more about \b debug.py files.
213 AssembleCoaddTask has no debug variables of its own. Some of the subtasks may support debug variables. See
214 the documetation for the subtasks for further information.
216 \section pipe_tasks_assembleCoadd_AssembleCoaddTask_Example A complete example of using AssembleCoaddTask
218 AssembleCoaddTask assembles a set of warped coaddTempExp images into a coadded image. The AssembleCoaddTask
219 can be invoked by running assembleCoadd.py with the flag '--legacyCoadd'. Usage of assembleCoadd.py expects
220 a data reference to the tract patch and filter to be coadded (specified using
221 '--id = [KEY=VALUE1[^VALUE2[^VALUE3...] [KEY=VALUE1[^VALUE2[^VALUE3...] ...]]') along with a list of
222 coaddTempExps to attempt to coadd (specified using
223 '--selectId [KEY=VALUE1[^VALUE2[^VALUE3...] [KEY=VALUE1[^VALUE2[^VALUE3...] ...]]'). Only the coaddTempExps
224 that cover the specified tract and patch will be coadded. A list of the available optional
225 arguments can be obtained by calling assembleCoadd.py with the --help command line argument:
227 assembleCoadd.py --help
229 To demonstrate usage of the AssembleCoaddTask in the larger context of multi-band processing, we will generate
230 the HSC-I & -R band coadds from HSC engineering test data provided in the ci_hsc package. To begin, assuming
231 that the lsst stack has been already set up, we must set up the obs_subaru and ci_hsc packages.
232 This defines the environment variable $CI_HSC_DIR and points at the location of the package. The raw HSC
233 data live in the $CI_HSC_DIR/raw directory. To begin assembling the coadds, we must first
236 <DD> process the individual ccds in $CI_HSC_RAW to produce calibrated exposures</DD>
238 <DD> create a skymap that covers the area of the sky present in the raw exposures</DD>
239 <DT>makeCoaddTempExp</DT>
240 <DD> warp the individual calibrated exposures to the tangent plane of the coadd</DD>
242 We can perform all of these steps by running
244 $CI_HSC_DIR scons warp-903986 warp-904014 warp-903990 warp-904010 warp-903988
246 This will produce warped coaddTempExps for each visit. To coadd the warped data, we call assembleCoadd.py as
249 assembleCoadd.py --legacyCoadd $CI_HSC_DIR/DATA --id patch=5,4 tract=0 filter=HSC-I --selectId visit=903986 ccd=16 --selectId visit=903986 ccd=22 --selectId visit=903986 ccd=23 --selectId visit=903986 ccd=100 --selectId visit=904014 ccd=1 --selectId visit=904014 ccd=6 --selectId visit=904014 ccd=12 --selectId visit=903990 ccd=18 --selectId visit=903990 ccd=25 --selectId visit=904010 ccd=4 --selectId visit=904010 ccd=10 --selectId visit=904010 ccd=100 --selectId visit=903988 ccd=16 --selectId visit=903988 ccd=17 --selectId visit=903988 ccd=23 --selectId visit=903988 ccd=24\endcode
250 that will process the HSC-I band data. The results are written in $CI_HSC_DIR/DATA/deepCoadd-results/HSC-I
251 You may also choose to run:
253 scons warp-903334 warp-903336 warp-903338 warp-903342 warp-903344 warp-903346
254 assembleCoadd.py --legacyCoadd $CI_HSC_DIR/DATA --id patch=5,4 tract=0 filter=HSC-R --selectId visit=903334 ccd=16 --selectId visit=903334 ccd=22 --selectId visit=903334 ccd=23 --selectId visit=903334 ccd=100 --selectId visit=903336 ccd=17 --selectId visit=903336 ccd=24 --selectId visit=903338 ccd=18 --selectId visit=903338 ccd=25 --selectId visit=903342 ccd=4 --selectId visit=903342 ccd=10 --selectId visit=903342 ccd=100 --selectId visit=903344 ccd=0 --selectId visit=903344 ccd=5 --selectId visit=903344 ccd=11 --selectId visit=903346 ccd=1 --selectId visit=903346 ccd=6 --selectId visit=903346 ccd=12
256 to generate the coadd for the HSC-R band if you are interested in following multiBand Coadd processing as
257 discussed in \ref pipeTasks_multiBand (but note that normally, one would use the
258 \ref SafeClipAssembleCoaddTask_ "SafeClipAssembleCoaddTask" rather than AssembleCoaddTask to make the coadd.
260 ConfigClass = AssembleCoaddConfig
261 _DefaultName =
"assembleCoadd"
265 \brief Initialize the task. Create the \ref InterpImageTask "interpImage",
266 \ref MatchBackgroundsTask "matchBackgrounds", & \ref ScaleZeroPointTask "scaleZeroPoint" subtasks.
268 CoaddBaseTask.__init__(self, *args, **kwargs)
269 self.makeSubtask(
"interpImage")
270 self.makeSubtask(
"matchBackgrounds")
271 self.makeSubtask(
"scaleZeroPoint")
273 if self.config.doMaskBrightObjects:
274 mask = afwImage.MaskU()
277 except pexExceptions.LsstCppException:
278 raise RuntimeError(
"Unable to define mask plane for bright objects; planes used are %s" %
279 mask.getMaskPlaneDict().keys())
283 def run(self, dataRef, selectDataList=[]):
285 \brief Assemble a coadd from a set of coaddTempExp
287 Coadd a set of coaddTempExps. Compute weights to be applied to each coaddTempExp and find scalings to
288 match the photometric zeropoint to a reference coaddTempExp. Optionally, match backgrounds across
289 coaddTempExps if the background has not already been removed. Assemble the coaddTempExps using
290 \ref assemble. Interpolate over NaNs and optionally write the coadd to disk. Return the coadded
294 \param[in] dataRef: Data reference defining the patch for coaddition and the reference coaddTempExp
295 (if config.autoReference=False). Used to access the following data products:
296 - [in] self.config.coaddName + "Coadd_skyMap"
297 - [in] self.config.coaddName + "Coadd_tempExp" (optionally)
298 - [out] self.config.coaddName + "Coadd"
299 \param[in] selectDataList[in]: List of data references to coaddTempExps. Data to be coadded will be
300 selected from this list based on overlap with the patch defined by dataRef.
302 \return a pipeBase.Struct with fields:
303 - coaddExposure: coadded exposure
305 skyInfo = self.getSkyInfo(dataRef)
306 calExpRefList = self.selectExposures(dataRef, skyInfo, selectDataList=selectDataList)
307 if len(calExpRefList) == 0:
308 self.log.warn(
"No exposures to coadd")
310 self.log.info(
"Coadding %d exposures", len(calExpRefList))
314 self.log.info(
"Found %d %s", len(inputData.tempExpRefList), self.getTempExpDatasetName())
315 if len(inputData.tempExpRefList) == 0:
316 self.log.warn(
"No coadd temporary exposures found")
318 if self.config.doMatchBackgrounds:
321 if len(inputData.tempExpRefList) == 0:
322 self.log.warn(
"No valid background models")
325 coaddExp = self.
assemble(skyInfo, inputData.tempExpRefList, inputData.imageScalerList,
326 inputData.weightList,
327 inputData.backgroundInfoList
if self.config.doMatchBackgrounds
else None,
328 doClip=self.config.doSigmaClip)
329 if self.config.doMatchBackgrounds:
331 inputData.backgroundInfoList)
333 if self.config.doInterp:
334 self.interpImage.run(coaddExp.getMaskedImage(), planeName=
"NO_DATA")
336 varArray = coaddExp.getMaskedImage().getVariance().getArray()
337 varArray[:] = numpy.where(varArray > 0, varArray, numpy.inf)
339 if self.config.doMaskBrightObjects:
343 if self.config.doWrite:
344 self.writeCoaddOutput(dataRef, coaddExp)
346 return pipeBase.Struct(coaddExposure=coaddExp)
350 \brief Generate list of coaddTempExp data references corresponding to exposures that lie within the
353 \param[in] patchRef: Data reference for patch
354 \param[in] calExpRefList: List of data references for input calexps
355 \return List of coaddTempExp data references
357 butler = patchRef.getButler()
359 self.getTempExpDatasetName())
360 tempExpRefList = [
getGroupDataRef(butler, self.getTempExpDatasetName(), g, groupData.keys)
for
361 g
in groupData.groups.keys()]
362 return tempExpRefList
366 \brief Construct an image scaler for the background reference frame
368 Each coaddTempExp has a different background level. A reference background level must be chosen before
369 coaddition. If config.autoReference=True, \ref backgroundMatching will pick the reference level and
370 this routine is a no-op and None is returned. Otherwise, use the
371 \ref ScaleZeroPointTask_ "scaleZeroPoint" subtask to compute an imageScaler object for the provided
372 reference image and return it.
374 \param[in] dataRef: Data reference for the background reference frame, or None
375 \return image scaler, or None
377 if self.config.autoReference:
381 dataset = self.getTempExpDatasetName()
382 if not dataRef.datasetExists(dataset):
383 raise RuntimeError(
"Could not find reference exposure %s %s." % (dataset, dataRef.dataId))
385 refExposure = dataRef.get(self.getTempExpDatasetName(), immediate=
True)
386 refImageScaler = self.scaleZeroPoint.computeImageScaler(
387 exposure=refExposure,
390 return refImageScaler
394 \brief Prepare the input warps for coaddition by measuring the weight for each warp and the scaling
395 for the photometric zero point.
397 Each coaddTempExp has its own photometric zeropoint and background variance. Before coadding these
398 coaddTempExps together, compute a scale factor to normalize the photometric zeropoint and compute the
399 weight for each coaddTempExp.
401 \param[in] refList: List of data references to tempExp
403 - tempExprefList: List of data references to tempExp
404 - weightList: List of weightings
405 - imageScalerList: List of image scalers
408 statsCtrl.setNumSigmaClip(self.config.sigmaClip)
409 statsCtrl.setNumIter(self.config.clipIter)
410 statsCtrl.setAndMask(self.getBadPixelMask())
411 statsCtrl.setNanSafe(
True)
419 tempExpName = self.getTempExpDatasetName()
420 for tempExpRef
in refList:
421 if not tempExpRef.datasetExists(tempExpName):
422 self.log.warn(
"Could not find %s %s; skipping it", tempExpName, tempExpRef.dataId)
425 tempExp = tempExpRef.get(tempExpName, immediate=
True)
426 maskedImage = tempExp.getMaskedImage()
427 imageScaler = self.scaleZeroPoint.computeImageScaler(
432 imageScaler.scaleMaskedImage(maskedImage)
433 except Exception
as e:
434 self.log.warn(
"Scaling failed for %s (skipping it): %s", tempExpRef.dataId, e)
437 afwMath.MEANCLIP, statsCtrl)
438 meanVar, meanVarErr = statObj.getResult(afwMath.MEANCLIP)
439 weight = 1.0 / float(meanVar)
440 if not numpy.isfinite(weight):
441 self.log.warn(
"Non-finite weight for %s: skipping", tempExpRef.dataId)
443 self.log.info(
"Weight of %s %s = %0.3f", tempExpName, tempExpRef.dataId, weight)
448 tempExpRefList.append(tempExpRef)
449 weightList.append(weight)
450 imageScalerList.append(imageScaler)
452 return pipeBase.Struct(tempExpRefList=tempExpRefList, weightList=weightList,
453 imageScalerList=imageScalerList)
457 \brief Perform background matching on the prepared inputs
459 Each coaddTempExp has a different background level that must be normalized to a reference level
460 before coaddition. If no reference is provided, the background matcher selects one. If the background
461 matching is performed sucessfully, recompute the weight to be applied to the coaddTempExp to be
462 consistent with the scaled background.
464 \param[in] inputData: Struct from prepareInputs() with tempExpRefList, weightList, imageScalerList
465 \param[in] refExpDataRef: Data reference for background reference tempExp, or None
466 \param[in] refImageScaler: Image scaler for background reference tempExp, or None
468 - tempExprefList: List of data references to tempExp
469 - weightList: List of weightings
470 - imageScalerList: List of image scalers
471 - backgroundInfoList: result from background matching
474 backgroundInfoList = self.matchBackgrounds.run(
475 expRefList=inputData.tempExpRefList,
476 imageScalerList=inputData.imageScalerList,
477 refExpDataRef=refExpDataRef
if not self.config.autoReference
else None,
478 refImageScaler=refImageScaler,
479 expDatasetType=self.getTempExpDatasetName(),
481 except Exception
as e:
482 self.log.fatal(
"Cannot match backgrounds: %s", e)
483 raise pipeBase.TaskError(
"Background matching failed.")
486 newTempExpRefList = []
487 newBackgroundStructList = []
491 for tempExpRef, bgInfo, scaler, weight
in zip(inputData.tempExpRefList, backgroundInfoList,
492 inputData.imageScalerList, inputData.weightList):
493 if not bgInfo.isReference:
496 if (bgInfo.backgroundModel
is None):
497 self.log.info(
"No background offset model available for %s: skipping", tempExpRef.dataId)
500 varianceRatio = bgInfo.matchedMSE / bgInfo.diffImVar
501 except Exception
as e:
502 self.log.info(
"MSE/Var ratio not calculable (%s) for %s: skipping",
503 e, tempExpRef.dataId)
505 if not numpy.isfinite(varianceRatio):
506 self.log.info(
"MSE/Var ratio not finite (%.2f / %.2f) for %s: skipping",
507 bgInfo.matchedMSE, bgInfo.diffImVar, tempExpRef.dataId)
509 elif (varianceRatio > self.config.maxMatchResidualRatio):
510 self.log.info(
"Bad fit. MSE/Var ratio %.2f > %.2f for %s: skipping",
511 varianceRatio, self.config.maxMatchResidualRatio, tempExpRef.dataId)
513 elif (bgInfo.fitRMS > self.config.maxMatchResidualRMS):
514 self.log.info(
"Bad fit. RMS %.2f > %.2f for %s: skipping",
515 bgInfo.fitRMS, self.config.maxMatchResidualRMS, tempExpRef.dataId)
517 newWeightList.append(1 / (1 / weight + bgInfo.fitRMS**2))
518 newTempExpRefList.append(tempExpRef)
519 newBackgroundStructList.append(bgInfo)
520 newScaleList.append(scaler)
522 return pipeBase.Struct(tempExpRefList=newTempExpRefList, weightList=newWeightList,
523 imageScalerList=newScaleList, backgroundInfoList=newBackgroundStructList)
525 def assemble(self, skyInfo, tempExpRefList, imageScalerList, weightList, bgInfoList=None,
526 altMaskList=
None, doClip=
False, mask=
None):
528 \anchor AssembleCoaddTask.assemble_
530 \brief Assemble a coadd from input warps
532 Assemble the coadd using the provided list of coaddTempExps. Since the full coadd covers a patch (a
533 large area), the assembly is performed over small areas on the image at a time in order to
534 conserve memory usage. Iterate over subregions within the outer bbox of the patch using
535 \ref assembleSubregion to mean-stack the corresponding subregions from the coaddTempExps (with outlier
536 rejection if config.doSigmaClip=True). Set the edge bits the the coadd mask based on the weight map.
538 \param[in] skyInfo: Patch geometry information, from getSkyInfo
539 \param[in] tempExpRefList: List of data references to tempExp
540 \param[in] imageScalerList: List of image scalers
541 \param[in] weightList: List of weights
542 \param[in] bgInfoList: List of background data from background matching, or None
543 \param[in] altMaskList: List of alternate masks to use rather than those stored with tempExp, or None
544 \param[in] doClip: Use clipping when codding?
545 \param[in] mask: Mask to ignore when coadding
546 \return coadded exposure
548 tempExpName = self.getTempExpDatasetName()
549 self.log.info(
"Assembling %s %s", len(tempExpRefList), tempExpName)
551 mask = self.getBadPixelMask()
554 statsCtrl.setNumSigmaClip(self.config.sigmaClip)
555 statsCtrl.setNumIter(self.config.clipIter)
556 statsCtrl.setAndMask(mask)
557 statsCtrl.setNanSafe(
True)
558 statsCtrl.setWeighted(
True)
559 statsCtrl.setCalcErrorFromInputVariance(
True)
560 for plane, threshold
in self.config.maskPropagationThresholds.items():
561 bit = afwImage.MaskU.getMaskPlane(plane)
562 statsCtrl.setMaskPropagationThreshold(bit, threshold)
565 statsFlags = afwMath.MEANCLIP
567 statsFlags = afwMath.MEAN
569 if bgInfoList
is None:
570 bgInfoList = [
None]*len(tempExpRefList)
572 if altMaskList
is None:
573 altMaskList = [
None]*len(tempExpRefList)
575 coaddExposure = afwImage.ExposureF(skyInfo.bbox, skyInfo.wcs)
576 coaddExposure.setCalib(self.scaleZeroPoint.getCalib())
577 coaddExposure.getInfo().setCoaddInputs(self.inputRecorder.makeCoaddInputs())
579 coaddMaskedImage = coaddExposure.getMaskedImage()
580 subregionSizeArr = self.config.subregionSize
582 for subBBox
in _subBBoxIter(skyInfo.bbox, subregionSize):
585 weightList, bgInfoList, altMaskList, statsFlags, statsCtrl)
586 except Exception
as e:
587 self.log.fatal(
"Cannot compute coadd %s: %s", subBBox, e)
595 \brief Set the metadata for the coadd
597 This basic implementation simply sets the filter from the
600 \param[in] coaddExposure: The target image for the coadd
601 \param[in] tempExpRefList: List of data references to tempExp
602 \param[in] weightList: List of weights
604 assert len(tempExpRefList) == len(weightList),
"Length mismatch"
605 tempExpName = self.getTempExpDatasetName()
609 tempExpList = [tempExpRef.get(tempExpName +
"_sub",
611 imageOrigin=
"LOCAL", immediate=
True)
for tempExpRef
in tempExpRefList]
612 numCcds = sum(len(tempExp.getInfo().getCoaddInputs().ccds)
for tempExp
in tempExpList)
614 coaddExposure.setFilter(tempExpList[0].getFilter())
615 coaddInputs = coaddExposure.getInfo().getCoaddInputs()
616 coaddInputs.ccds.reserve(numCcds)
617 coaddInputs.visits.reserve(len(tempExpList))
619 for tempExp, weight
in zip(tempExpList, weightList):
620 self.inputRecorder.addVisitToCoadd(coaddInputs, tempExp, weight)
621 coaddInputs.visits.sort()
622 if self.config.doPsfMatch:
623 psf = self.config.modelPsf.apply()
626 coaddExposure.setPsf(psf)
627 apCorrMap = measAlg.makeCoaddApCorrMap(coaddInputs.ccds, coaddExposure.getBBox(afwImage.PARENT),
628 coaddExposure.getWcs())
629 coaddExposure.getInfo().setApCorrMap(apCorrMap)
631 def assembleSubregion(self, coaddExposure, bbox, tempExpRefList, imageScalerList, weightList,
632 bgInfoList, altMaskList, statsFlags, statsCtrl):
634 \brief Assemble the coadd for a sub-region.
636 For each coaddTempExp, check for (and swap in) an alternative mask if one is passed. If background
637 matching is enabled, add the background and background variance from each coaddTempExp. Remove mask
638 planes listed in config.removeMaskPlanes, Finally, mean-stack
639 the actual exposures using \ref afwMath.statisticsStack "statisticsStack" with outlier rejection if
640 config.doSigmaClip=True. Assign the stacked subregion back to the coadd.
642 \param[in] coaddExposure: The target image for the coadd
643 \param[in] bbox: Sub-region to coadd
644 \param[in] tempExpRefList: List of data reference to tempExp
645 \param[in] imageScalerList: List of image scalers
646 \param[in] weightList: List of weights
647 \param[in] bgInfoList: List of background data from background matching
648 \param[in] altMaskList: List of alternate masks to use rather than those stored with tempExp, or None
649 \param[in] statsFlags: Statistic for coadd
650 \param[in] statsCtrl: Statistics control object for coadd
652 self.log.debug(
"Computing coadd over %s", bbox)
653 tempExpName = self.getTempExpDatasetName()
654 coaddMaskedImage = coaddExposure.getMaskedImage()
655 maskedImageList = afwImage.vectorMaskedImageF()
656 for tempExpRef, imageScaler, bgInfo, altMask
in zip(tempExpRefList, imageScalerList, bgInfoList,
658 exposure = tempExpRef.get(tempExpName +
"_sub", bbox=bbox)
659 maskedImage = exposure.getMaskedImage()
662 altMaskSub = altMask.Factory(altMask, bbox, afwImage.PARENT)
663 maskedImage.getMask().
swap(altMaskSub)
664 imageScaler.scaleMaskedImage(maskedImage)
666 if self.config.doMatchBackgrounds
and not bgInfo.isReference:
667 backgroundModel = bgInfo.backgroundModel
668 backgroundImage = backgroundModel.getImage()
if \
669 self.matchBackgrounds.config.usePolynomial
else \
670 backgroundModel.getImageF()
671 backgroundImage.setXY0(coaddMaskedImage.getXY0())
672 maskedImage += backgroundImage.Factory(backgroundImage, bbox, afwImage.PARENT,
False)
673 var = maskedImage.getVariance()
674 var += (bgInfo.fitRMS)**2
676 if self.config.removeMaskPlanes:
677 mask = maskedImage.getMask()
678 for maskPlane
in self.config.removeMaskPlanes:
680 mask &= ~mask.getPlaneBitMask(maskPlane)
681 except Exception
as e:
682 self.log.warn(
"Unable to remove mask plane %s: %s", maskPlane, e.message)
684 maskedImageList.append(maskedImage)
686 with self.timer(
"stack"):
688 maskedImageList, statsFlags, statsCtrl, weightList)
690 coaddMaskedImage.assign(coaddSubregion, bbox)
694 \brief Add metadata from the background matching to the coadd
696 \param[in] coaddExposure: Coadd
697 \param[in] tempExpRefList: List of data references for temp exps to go into coadd
698 \param[in] backgroundInfoList: List of background info, results from background matching
700 self.log.info(
"Adding exposure information to metadata")
701 metadata = coaddExposure.getMetadata()
702 metadata.addString(
"CTExp_SDQA1_DESCRIPTION",
703 "Background matching: Ratio of matchedMSE / diffImVar")
704 for ind, (tempExpRef, backgroundInfo)
in enumerate(zip(tempExpRefList, backgroundInfoList)):
705 tempExpStr =
'&'.join(
'%s=%s' % (k, v)
for k, v
in tempExpRef.dataId.items())
706 if backgroundInfo.isReference:
707 metadata.addString(
"ReferenceExp_ID", tempExpStr)
709 metadata.addString(
"CTExp_ID_%d" % (ind), tempExpStr)
710 metadata.addDouble(
"CTExp_SDQA1_%d" % (ind),
711 backgroundInfo.matchedMSE/backgroundInfo.diffImVar)
712 metadata.addDouble(
"CTExp_SDQA2_%d" % (ind),
713 backgroundInfo.fitRMS)
716 """Returns None on failure"""
718 return dataRef.get(
"brightObjectMask", immediate=
True)
719 except Exception
as e:
720 self.log.warn(
"Unable to read brightObjectMask for %s: %s", dataRef.dataId, e)
724 """Set the bright object masks
726 exposure: Exposure under consideration
727 dataId: Data identifier dict for patch
728 brightObjectMasks: afwTable of bright objects to mask
733 if brightObjectMasks
is None:
734 self.log.warn(
"Unable to apply bright object mask: none supplied")
736 self.log.info(
"Applying %d bright object masks to %s", len(brightObjectMasks), dataId)
737 md = brightObjectMasks.table.getMetadata()
740 self.log.warn(
"Expected to see %s in metadata", k)
742 if md.get(k) != dataId[k]:
743 self.log.warn(
"Expected to see %s == %s in metadata, saw %s", k, md.get(k), dataId[k])
745 mask = exposure.getMaskedImage().getMask()
746 wcs = exposure.getWcs()
747 plateScale = wcs.pixelScale().asArcseconds()
749 for rec
in brightObjectMasks:
751 radius = rec[
"radius"].asArcseconds()/plateScale
759 \brief Create an argument parser
761 parser = pipeBase.ArgumentParser(name=cls._DefaultName)
762 parser.add_id_argument(
"--id", cls.ConfigClass().coaddName +
"Coadd_tempExp",
763 help=
"data ID, e.g. --id tract=12345 patch=1,2",
764 ContainerClass=AssembleCoaddDataIdContainer)
765 parser.add_id_argument(
"--selectId",
"calexp", help=
"data ID, e.g. --selectId visit=6789 ccd=0..9",
766 ContainerClass=SelectDataIdContainer)
772 \brief Iterate over subregions of a bbox
774 \param[in] bbox: bounding box over which to iterate: afwGeom.Box2I
775 \param[in] subregionSize: size of sub-bboxes
777 \return subBBox: next sub-bounding box of size subregionSize or smaller;
778 each subBBox is contained within bbox, so it may be smaller than subregionSize at the edges of bbox,
779 but it will never be empty
782 raise RuntimeError(
"bbox %s is empty" % (bbox,))
783 if subregionSize[0] < 1
or subregionSize[1] < 1:
784 raise RuntimeError(
"subregionSize %s must be nonzero" % (subregionSize,))
786 for rowShift
in range(0, bbox.getHeight(), subregionSize[1]):
787 for colShift
in range(0, bbox.getWidth(), subregionSize[0]):
790 if subBBox.isEmpty():
791 raise RuntimeError(
"Bug: empty bbox! bbox=%s, subregionSize=%s, colShift=%s, rowShift=%s" %
792 (bbox, subregionSize, colShift, rowShift))
798 \brief A version of lsst.pipe.base.DataIdContainer specialized for assembleCoadd.
803 \brief Make self.refList from self.idList.
805 Interpret the config.doMatchBackgrounds, config.autoReference,
806 and whether a visit/run supplied.
807 If a visit/run is supplied, config.autoReference is automatically set to False.
808 if config.doMatchBackgrounds == false, then a visit/run will be ignored if accidentally supplied.
811 keysCoadd = namespace.butler.getKeys(datasetType=namespace.config.coaddName +
"Coadd",
813 keysCoaddTempExp = namespace.butler.getKeys(datasetType=namespace.config.coaddName +
"Coadd_tempExp",
816 if namespace.config.doMatchBackgrounds:
817 if namespace.config.autoReference:
818 datasetType = namespace.config.coaddName +
"Coadd"
819 validKeys = keysCoadd
821 datasetType = namespace.config.coaddName +
"Coadd_tempExp"
822 validKeys = keysCoaddTempExp
824 datasetType = namespace.config.coaddName +
"Coadd"
825 validKeys = keysCoadd
827 for dataId
in self.idList:
829 for key
in validKeys:
830 if key
not in dataId:
831 raise RuntimeError(
"--id must include " + key)
834 if (key
not in keysCoadd)
and (key
in keysCoaddTempExp):
835 if namespace.config.autoReference:
837 namespace.config.autoReference =
False
838 datasetType = namespace.config.coaddName +
"Coadd_tempExp"
839 print(
"Switching config.autoReference to False; applies only to background Matching.")
842 dataRef = namespace.butler.dataRef(
843 datasetType=datasetType,
846 self.refList.append(dataRef)
851 \brief Function to count the number of pixels with a specific mask in a footprint.
853 Find the intersection of mask & footprint. Count all pixels in the mask that are in the intersection that
854 have bitmask set but do not have ignoreMask set. Return the count.
856 \param[in] mask: mask to define intersection region by.
857 \parma[in] footprint: footprint to define the intersection region by.
858 \param[in] bitmask: specific mask that we wish to count the number of occurances of.
859 \param[in] ignoreMask: pixels to not consider.
860 \return count of number of pixels in footprint with specified mask.
862 bbox = footprint.getBBox()
863 bbox.clip(mask.getBBox(afwImage.PARENT))
864 fp = afwImage.MaskU(bbox)
865 subMask = mask.Factory(mask, bbox, afwImage.PARENT)
867 return numpy.logical_and((subMask.getArray() & fp.getArray()) > 0,
868 (subMask.getArray() & ignoreMask) == 0).sum()
873 \anchor SafeClipAssembleCoaddConfig
875 \brief Configuration parameters for the SafeClipAssembleCoaddTask
877 clipDetection = pexConfig.ConfigurableField(
878 target=SourceDetectionTask,
879 doc=
"Detect sources on difference between unclipped and clipped coadd")
880 minClipFootOverlap = pexConfig.Field(
881 doc=
"Minimum fractional overlap of clipped footprint with visit DETECTED to be clipped",
885 minClipFootOverlapSingle = pexConfig.Field(
886 doc=
"Minimum fractional overlap of clipped footprint with visit DETECTED to be "
887 "clipped when only one visit overlaps",
891 minClipFootOverlapDouble = pexConfig.Field(
892 doc=
"Minimum fractional overlap of clipped footprints with visit DETECTED to be "
893 "clipped when two visits overlap",
897 maxClipFootOverlapDouble = pexConfig.Field(
898 doc=
"Maximum fractional overlap of clipped footprints with visit DETECTED when "
899 "considering two visits",
903 minBigOverlap = pexConfig.Field(
904 doc=
"Minimum number of pixels in footprint to use DETECTED mask from the single visits "
905 "when labeling clipped footprints",
913 AssembleCoaddConfig.setDefaults(self)
914 self.clipDetection.doTempLocalBackground =
False
915 self.clipDetection.reEstimateBackground =
False
916 self.clipDetection.returnOriginalFootprints =
False
917 self.clipDetection.thresholdPolarity =
"both"
918 self.clipDetection.thresholdValue = 2
919 self.clipDetection.nSigmaToGrow = 2
920 self.clipDetection.minPixels = 4
921 self.clipDetection.isotropicGrow =
True
922 self.clipDetection.thresholdType =
"pixel_stdev"
936 \anchor SafeClipAssembleCoaddTask_
938 \brief Assemble a coadded image from a set of coadded temporary exposures, being careful to clip & flag areas
939 with potential artifacts.
941 \section pipe_tasks_assembleCoadd_Contents Contents
942 - \ref pipe_tasks_assembleCoadd_SafeClipAssembleCoaddTask_Purpose
943 - \ref pipe_tasks_assembleCoadd_SafeClipAssembleCoaddTask_Initialize
944 - \ref pipe_tasks_assembleCoadd_SafeClipAssembleCoaddTask_Run
945 - \ref pipe_tasks_assembleCoadd_SafeClipAssembleCoaddTask_Config
946 - \ref pipe_tasks_assembleCoadd_SafeClipAssembleCoaddTask_Debug
947 - \ref pipe_tasks_assembleCoadd_SafeClipAssembleCoaddTask_Example
949 \section pipe_tasks_assembleCoadd_SafeClipAssembleCoaddTask_Purpose Description
951 \copybrief SafeClipAssembleCoaddTask
953 Read the documentation for \ref AssembleCoaddTask_ "AssembleCoaddTask" first since
954 SafeClipAssembleCoaddTask subtasks that task.
955 In \ref AssembleCoaddTask_ "AssembleCoaddTask", we compute the coadd as an clipped mean (i.e. we clip
957 The problem with doing this is that when computing the coadd PSF at a given location, individual visit
958 PSFs from visits with outlier pixels contribute to the coadd PSF and cannot be treated correctly.
959 In this task, we correct for this behavior by creating a new badMaskPlane 'CLIPPED'.
960 We populate this plane on the input coaddTempExps and the final coadd where i. difference imaging suggests
961 that there is an outlier and ii. this outlier appears on only one or two images.
962 Such regions will not contribute to the final coadd.
963 Furthermore, any routine to determine the coadd PSF can now be cognizant of clipped regions.
964 Note that the algorithm implemented by this task is preliminary and works correctly for HSC data.
965 Parameter modifications and or considerable redesigning of the algorithm is likley required for other
968 SafeClipAssembleCoaddTask uses a \ref SourceDetectionTask_ "clipDetection" subtask and also sub-classes
969 \ref AssembleCoaddTask_ "AssembleCoaddTask". You can retarget the
970 \ref SourceDetectionTask_ "clipDetection" subtask if you wish.
972 \section pipe_tasks_assembleCoadd_SafeClipAssembleCoaddTask_Initialize Task initialization
973 \copydoc \_\_init\_\_
975 \section pipe_tasks_assembleCoadd_SafeClipAssembleCoaddTask_Run Invoking the Task
978 \section pipe_tasks_assembleCoadd_SafeClipAssembleCoaddTask_Config Configuration parameters
979 See \ref SafeClipAssembleCoaddConfig
981 \section pipe_tasks_assembleCoadd_SafeClipAssembleCoaddTask_Debug Debug variables
982 The \link lsst.pipe.base.cmdLineTask.CmdLineTask command line task\endlink interface supports a
983 flag \c -d to import \b debug.py from your \c PYTHONPATH; see \ref baseDebug for more about \b debug.py
985 SafeClipAssembleCoaddTask has no debug variables of its own. The \ref SourceDetectionTask_ "clipDetection"
986 subtasks may support debug variables. See the documetation for \ref SourceDetectionTask_ "clipDetection"
987 for further information.
989 \section pipe_tasks_assembleCoadd_SafeClipAssembleCoaddTask_Example A complete example of using SafeClipAssembleCoaddTask
991 SafeClipAssembleCoaddTask assembles a set of warped coaddTempExp images into a coadded image.
992 The SafeClipAssembleCoaddTask is invoked by running assembleCoadd.py <em>without</em> the flag
994 Usage of assembleCoadd.py expects a data reference to the tract patch and filter to be coadded
995 (specified using '--id = [KEY=VALUE1[^VALUE2[^VALUE3...] [KEY=VALUE1[^VALUE2[^VALUE3...] ...]]') along
996 with a list of coaddTempExps to attempt to coadd (specified using
997 '--selectId [KEY=VALUE1[^VALUE2[^VALUE3...] [KEY=VALUE1[^VALUE2[^VALUE3...] ...]]').
998 Only the coaddTempExps that cover the specified tract and patch will be coadded.
999 A list of the available optional arguments can be obtained by calling assembleCoadd.py with the --help
1000 command line argument:
1002 assembleCoadd.py --help
1004 To demonstrate usage of the SafeClipAssembleCoaddTask in the larger context of multi-band processing, we
1005 will generate the HSC-I & -R band coadds from HSC engineering test data provided in the ci_hsc package. To
1006 begin, assuming that the lsst stack has been already set up, we must set up the obs_subaru and ci_hsc
1008 This defines the environment variable $CI_HSC_DIR and points at the location of the package. The raw HSC
1009 data live in the $CI_HSC_DIR/raw directory. To begin assembling the coadds, we must first
1012 <DD> process the individual ccds in $CI_HSC_RAW to produce calibrated exposures</DD>
1014 <DD> create a skymap that covers the area of the sky present in the raw exposures</DD>
1015 <DT>makeCoaddTempExp</DT>
1016 <DD> warp the individual calibrated exposures to the tangent plane of the coadd</DD>
1018 We can perform all of these steps by running
1020 $CI_HSC_DIR scons warp-903986 warp-904014 warp-903990 warp-904010 warp-903988
1022 This will produce warped coaddTempExps for each visit. To coadd the wraped data, we call assembleCoadd.py
1025 assembleCoadd.py $CI_HSC_DIR/DATA --id patch=5,4 tract=0 filter=HSC-I --selectId visit=903986 ccd=16 --selectId visit=903986 ccd=22 --selectId visit=903986 ccd=23 --selectId visit=903986 ccd=100 --selectId visit=904014 ccd=1 --selectId visit=904014 ccd=6 --selectId visit=904014 ccd=12 --selectId visit=903990 ccd=18 --selectId visit=903990 ccd=25 --selectId visit=904010 ccd=4 --selectId visit=904010 ccd=10 --selectId visit=904010 ccd=100 --selectId visit=903988 ccd=16 --selectId visit=903988 ccd=17 --selectId visit=903988 ccd=23 --selectId visit=903988 ccd=24
1027 This will process the HSC-I band data. The results are written in $CI_HSC_DIR/DATA/deepCoadd-results/HSC-I
1028 You may also choose to run:
1030 scons warp-903334 warp-903336 warp-903338 warp-903342 warp-903344 warp-903346
1031 assembleCoadd.py $CI_HSC_DIR/DATA --id patch=5,4 tract=0 filter=HSC-R --selectId visit=903334 ccd=16 --selectId visit=903334 ccd=22 --selectId visit=903334 ccd=23 --selectId visit=903334 ccd=100 --selectId visit=903336 ccd=17 --selectId visit=903336 ccd=24 --selectId visit=903338 ccd=18 --selectId visit=903338 ccd=25 --selectId visit=903342 ccd=4 --selectId visit=903342 ccd=10 --selectId visit=903342 ccd=100 --selectId visit=903344 ccd=0 --selectId visit=903344 ccd=5 --selectId visit=903344 ccd=11 --selectId visit=903346 ccd=1 --selectId visit=903346 ccd=6 --selectId visit=903346 ccd=12
1033 to generate the coadd for the HSC-R band if you are interested in following multiBand Coadd processing as
1034 discussed in \ref pipeTasks_multiBand.
1036 ConfigClass = SafeClipAssembleCoaddConfig
1037 _DefaultName =
"safeClipAssembleCoadd"
1041 \brief Initialize the task and make the \ref SourceDetectionTask_ "clipDetection" subtask.
1043 AssembleCoaddTask.__init__(self, *args, **kwargs)
1044 schema = afwTable.SourceTable.makeMinimalSchema()
1045 self.makeSubtask(
"clipDetection", schema=schema)
1047 def assemble(self, skyInfo, tempExpRefList, imageScalerList, weightList, bgModelList, *args, **kwargs):
1049 \brief Assemble the coadd for a region
1051 Compute the difference of coadds created with and without outlier rejection to identify coadd pixels
1052 that have outlier values in some individual visits. Detect clipped regions on the difference image and
1053 mark these regions on the one or two individual coaddTempExps where they occur if there is significant
1054 overlap between the clipped region and a source.
1055 This leaves us with a set of footprints from the difference image that have been identified as having
1056 occured on just one or two individual visits. However, these footprints were generated from a
1057 difference image. It is conceivable for a large diffuse source to have become broken up into multiple
1058 footprints acrosss the coadd difference in this process.
1059 Determine the clipped region from all overlapping footprints from the detected sources in each visit -
1060 these are big footprints.
1061 Combine the small and big clipped footprints and mark them on a new bad mask plane
1062 Generate the coadd using \ref AssembleCoaddTask.assemble_ "AssembleCoaddTask.assemble" without outlier
1063 removal. Clipped footprints will no longer make it into the coadd because they are marked in the new
1066 N.b. *args and **kwargs are passed but ignored in order to match the call signature expected by the
1069 @param skyInfo: Patch geometry information, from getSkyInfo
1070 @param tempExpRefList: List of data reference to tempExp
1071 @param imageScalerList: List of image scalers
1072 @param weightList: List of weights
1073 @param bgModelList: List of background models from background matching
1074 return coadd exposure
1076 exp = self.
buildDifferenceImage(skyInfo, tempExpRefList, imageScalerList, weightList, bgModelList)
1077 mask = exp.getMaskedImage().getMask()
1078 mask.addMaskPlane(
"CLIPPED")
1080 result = self.
detectClip(exp, tempExpRefList)
1082 self.log.info(
'Found %d clipped objects', len(result.clipFootprints))
1085 maskClipValue = mask.getPlaneBitMask(
"CLIPPED")
1086 maskDetValue = mask.getPlaneBitMask(
"DETECTED") | mask.getPlaneBitMask(
"DETECTED_NEGATIVE")
1087 bigFootprints = self.
detectClipBig(result.tempExpClipList, result.clipFootprints, result.clipIndices,
1088 maskClipValue, maskDetValue)
1091 maskClip = mask.Factory(mask.getBBox(afwImage.PARENT))
1094 maskClipBig = maskClip.Factory(mask.getBBox(afwImage.PARENT))
1096 maskClip |= maskClipBig
1099 badMaskPlanes = self.config.badMaskPlanes[:]
1100 badMaskPlanes.append(
"CLIPPED")
1101 badPixelMask = afwImage.MaskU.getPlaneBitMask(badMaskPlanes)
1102 coaddExp = AssembleCoaddTask.assemble(self, skyInfo, tempExpRefList, imageScalerList, weightList,
1103 bgModelList, result.tempExpClipList,
1109 maskExp = coaddExp.getMaskedImage().getMask()
1116 \brief Return an exposure that contains the difference between and unclipped and clipped coadds.
1118 Generate a difference image between clipped and unclipped coadds.
1119 Compute the difference image by subtracting an outlier-clipped coadd from an outlier-unclipped coadd.
1120 Return the difference image.
1122 @param skyInfo: Patch geometry information, from getSkyInfo
1123 @param tempExpRefList: List of data reference to tempExp
1124 @param imageScalerList: List of image scalers
1125 @param weightList: List of weights
1126 @param bgModelList: List of background models from background matching
1127 @return Difference image of unclipped and clipped coadd wrapped in an Exposure
1130 coaddMean = AssembleCoaddTask.assemble(self, skyInfo, tempExpRefList, imageScalerList, weightList,
1131 bgModelList, doClip=
False)
1134 coaddClip = AssembleCoaddTask.assemble(self, skyInfo, tempExpRefList, imageScalerList, weightList,
1135 bgModelList, doClip=
True)
1137 coaddDiff = coaddMean.getMaskedImage().Factory(coaddMean.getMaskedImage())
1138 coaddDiff -= coaddClip.getMaskedImage()
1139 exp = afwImage.ExposureF(coaddDiff)
1140 exp.setPsf(coaddMean.getPsf())
1145 \brief Detect clipped regions on an exposure and set the mask on the individual tempExp masks
1147 Detect footprints in the difference image after smoothing the difference image with a Gaussian kernal.
1148 Identify footprints that overlap with one or two input coaddTempExps by comparing the computed overlap
1149 fraction to thresholds set in the config.
1150 A different threshold is applied depending on the number of overlapping visits (restricted to one or
1152 If the overlap exceeds the thresholds, the footprint is considered "CLIPPED" and is marked as such on
1154 Return a struct with the clipped footprints, the indices of the coaddTempExps that end up overlapping
1155 with the clipped footprints and a list of new masks for the coaddTempExps.
1157 \param[in] exp: Exposure to run detection on
1158 \param[in] tempExpRefList: List of data reference to tempExp
1159 \return struct containing:
1160 - clippedFootprints: list of clipped footprints
1161 - clippedIndices: indices for each clippedFootprint in tempExpRefList
1162 - tempExpClipList: list of new masks for tempExp
1164 mask = exp.getMaskedImage().getMask()
1165 maskClipValue = mask.getPlaneBitMask(
"CLIPPED")
1166 maskDetValue = mask.getPlaneBitMask(
"DETECTED") | mask.getPlaneBitMask(
"DETECTED_NEGATIVE")
1167 fpSet = self.clipDetection.detectFootprints(exp, doSmooth=
True, clearMask=
True)
1169 fpSet.positive.merge(fpSet.negative)
1170 footprints = fpSet.positive
1171 self.log.info(
'Found %d potential clipped objects', len(footprints.getFootprints()))
1172 ignoreMask = self.getBadPixelMask()
1178 tempExpClipList = [tmpExpRef.get(self.getTempExpDatasetName(),
1179 immediate=
True).getMaskedImage().getMask()
for
1180 tmpExpRef
in tempExpRefList]
1182 for footprint
in footprints.getFootprints():
1183 nPixel = footprint.getArea()
1187 for i, tmpExpMask
in enumerate(tempExpClipList):
1191 totPixel = nPixel - ignore
1194 if ignore > overlapDet
or totPixel <= 0.5*nPixel
or overlapDet == 0:
1196 overlap.append(overlapDet/float(totPixel))
1197 maskList.append(tmpExpMask)
1200 overlap = numpy.array(overlap)
1201 if not len(overlap):
1208 if len(overlap) == 1:
1209 if overlap[0] > self.config.minClipFootOverlapSingle:
1214 clipIndex = numpy.where(overlap > self.config.minClipFootOverlap)[0]
1215 if len(clipIndex) == 1:
1217 keepIndex = [clipIndex[0]]
1220 clipIndex = numpy.where(overlap > self.config.minClipFootOverlapDouble)[0]
1221 if len(clipIndex) == 2
and len(overlap) > 3:
1222 clipIndexComp = numpy.where(overlap < self.config.minClipFootOverlapDouble)[0]
1223 if numpy.max(overlap[clipIndexComp]) < self.config.maxClipFootOverlapDouble:
1225 keepIndex = clipIndex
1230 for index
in keepIndex:
1233 clipIndices.append(numpy.array(indexList)[keepIndex])
1234 clipFootprints.append(footprint)
1236 return pipeBase.Struct(clipFootprints=clipFootprints, clipIndices=clipIndices,
1237 tempExpClipList=tempExpClipList)
1239 def detectClipBig(self, tempExpClipList, clipFootprints, clipIndices, maskClipValue, maskDetValue):
1241 \brief Find footprints from individual tempExp footprints for large footprints.
1243 Identify big footprints composed of many sources in the coadd difference that may have originated in a
1244 large diffuse source in the coadd. We do this by indentifying all clipped footprints that overlap
1245 significantly with each source in all the coaddTempExps.
1247 \param[in] tempExpClipList: List of tempExp masks with clipping information
1248 \param[in] clipFootprints: List of clipped footprints
1249 \param[in] clipIndices: List of which entries in tempExpClipList each footprint belongs to
1250 \param[in] maskClipValue: Mask value of clipped pixels
1251 \param[in] maskClipValue: Mask value of detected pixels
1252 \return list of big footprints
1254 bigFootprintsCoadd = []
1255 ignoreMask = self.getBadPixelMask()
1256 for index, tmpExpMask
in enumerate(tempExpClipList):
1259 maskVisitDet = tmpExpMask.Factory(tmpExpMask, tmpExpMask.getBBox(afwImage.PARENT),
1260 afwImage.PARENT,
True)
1261 maskVisitDet &= maskDetValue
1265 clippedFootprintsVisit = []
1266 for foot, clipIndex
in zip(clipFootprints, clipIndices):
1267 if index
not in clipIndex:
1269 clippedFootprintsVisit.append(foot)
1270 maskVisitClip = maskVisitDet.Factory(maskVisitDet.getBBox(afwImage.PARENT))
1273 bigFootprintsVisit = []
1274 for foot
in visitFootprints.getFootprints():
1275 if foot.getArea() < self.config.minBigOverlap:
1278 if nCount > self.config.minBigOverlap:
1279 bigFootprintsVisit.append(foot)
1280 bigFootprintsCoadd.append(foot)
1283 maskVisitClip.clearAllMaskPlanes()
1285 tmpExpMask |= maskVisitClip
1287 return bigFootprintsCoadd
def __init__
Initialize the task and make the clipDetection subtask.
def run
Assemble a coadd from a set of coaddTempExp.
def getBackgroundReferenceScaler
Construct an image scaler for the background reference frame.
void setCoaddEdgeBits(lsst::afw::image::Mask< lsst::afw::image::MaskPixel > &coaddMask, lsst::afw::image::Image< WeightPixelT > const &weightMap)
set edge bits of coadd mask based on weight map
def assemble
Assemble the coadd for a region.
def addBackgroundMatchingMetadata
Add metadata from the background matching to the coadd.
A Threshold is used to pass a threshold value to detection algorithms.
def detectClipBig
Find footprints from individual tempExp footprints for large footprints.
void swap(Mask< PixelT > &a, Mask< PixelT > &b)
Fit spatial kernel using approximate fluxes for candidates, and solving a linear system of equations...
def _subBBoxIter
Iterate over subregions of a bbox.
An integer coordinate rectangle.
def __init__
Initialize the task.
Pass parameters to a Statistics objectA class to pass parameters which control how the stats are calc...
def assembleSubregion
Assemble the coadd for a sub-region.
def assembleMetadata
Set the metadata for the coadd.
CoaddPsf is the Psf derived to be used for non-PSF-matched Coadd images.
def backgroundMatching
Perform background matching on the prepared inputs.
Configuration parameters for the SafeClipAssembleCoaddTask.
Assemble a coadded image from a set of coadded temporary exposures.
Assemble a coadded image from a set of coadded temporary exposures, being careful to clip & flag area...
def buildDifferenceImage
Return an exposure that contains the difference between and unclipped and clipped coadds...
def _makeArgumentParser
Create an argument parser.
def detectClip
Detect clipped regions on an exposure and set the mask on the individual tempExp masks.
def prepareInputs
Prepare the input warps for coaddition by measuring the weight for each warp and the scaling for the ...
def makeDataRefList
Make self.refList from self.idList.
MaskT setMaskFromFootprint(lsst::afw::image::Mask< MaskT > *mask, Footprint const &footprint, MaskT const bitmask)
OR bitmask into all the Mask's pixels that are in the Footprint.
Statistics makeStatistics(afwImage::Mask< afwImage::MaskPixel > const &msk, int const flags, StatisticsControl const &sctrl)
Specialization to handle Masks.
Configuration parameters for the AssembleCoaddTask.
MaskT setMaskFromFootprintList(lsst::afw::image::Mask< MaskT > *mask, boost::shared_ptr< std::vector< boost::shared_ptr< Footprint >> const > const &footprints, MaskT const bitmask)
OR bitmask into all the Mask's pixels which are in the set of Footprints.
def countMaskFromFootprint
Function to count the number of pixels with a specific mask in a footprint.
def assemble
Assemble a coadd from input warps.
def readBrightObjectMasks
A version of lsst.pipe.base.DataIdContainer specialized for assembleCoadd.
lsst::afw::image::MaskedImage< PixelT >::Ptr statisticsStack(lsst::afw::image::MaskedImage< PixelT > const &image, Property flags, char dimension, StatisticsControl const &sctrl=StatisticsControl())
A function to compute statistics on the rows or columns of an image.
def getTempExpRefList
Generate list of coaddTempExp data references corresponding to exposures that lie within the patch to...