31 __all__ = [
"BaseSelectImagesTask",
"BaseExposureInfo",
"WcsSelectImagesTask",
"PsfWcsSelectImagesTask",
32 "DatabaseSelectImagesConfig",
"BestSeeingWcsSelectImagesTask",
"BestSeeingSelectVisitsTask",
33 "BestSeeingQuantileSelectVisitsTask"]
37 """Base configuration for subclasses of BaseSelectImagesTask that use a database"""
38 host = pexConfig.Field(
39 doc=
"Database server host name",
42 port = pexConfig.Field(
43 doc=
"Database server port",
46 database = pexConfig.Field(
47 doc=
"Name of database",
50 maxExposures = pexConfig.Field(
51 doc=
"maximum exposures to select; intended for debugging; ignored if None",
58 """Data about a selected exposure
62 """Create exposure information that can be used to generate data references
64 The object has the following fields:
65 - dataId: data ID of exposure (a dict)
66 - coordList: ICRS coordinates of the corners of the exposure (list of lsst.geom.SpherePoint)
67 plus any others items that are desired
69 super(BaseExposureInfo, self).
__init__(dataId=dataId, coordList=coordList)
73 """Base task for selecting images suitable for coaddition
75 ConfigClass = pexConfig.Config
76 _DefaultName =
"selectImages"
79 def run(self, coordList):
80 """Select images suitable for coaddition in a particular region
82 @param[in] coordList: list of coordinates defining region of interest; if None then select all images
83 subclasses may add additional keyword arguments, as required
85 @return a pipeBase Struct containing:
86 - exposureInfoList: a list of exposure information objects (subclasses of BaseExposureInfo),
87 which have at least the following fields:
88 - dataId: data ID dictionary
89 - coordList: ICRS coordinates of the corners of the exposure (list of lsst.geom.SpherePoint)
91 raise NotImplementedError()
93 def _runArgDictFromDataId(self, dataId):
94 """Extract keyword arguments for run (other than coordList) from a data ID
96 @return keyword arguments for run (other than coordList), as a dict
98 raise NotImplementedError()
100 def runDataRef(self, dataRef, coordList, makeDataRefList=True, selectDataList=[]):
101 """Run based on a data reference
103 This delegates to run() and _runArgDictFromDataId() to do the actual
104 selection. In the event that the selectDataList is non-empty, this will
105 be used to further restrict the selection, providing the user with
106 additional control over the selection.
108 @param[in] dataRef: data reference; must contain any extra keys needed by the subclass
109 @param[in] coordList: list of coordinates defining region of interest; if None, search the whole sky
110 @param[in] makeDataRefList: if True, return dataRefList
111 @param[in] selectDataList: List of SelectStruct with dataRefs to consider for selection
112 @return a pipeBase Struct containing:
113 - exposureInfoList: a list of objects derived from ExposureInfo
114 - dataRefList: a list of data references (None if makeDataRefList False)
117 exposureInfoList = self.
runrun(coordList, **runArgDict).exposureInfoList
119 if len(selectDataList) > 0
and len(exposureInfoList) > 0:
121 ccdKeys, ccdValues = _extractKeyValue(exposureInfoList)
122 inKeys, inValues = _extractKeyValue([s.dataRef
for s
in selectDataList], keys=ccdKeys)
123 inValues =
set(inValues)
124 newExposureInfoList = []
125 for info, ccdVal
in zip(exposureInfoList, ccdValues):
126 if ccdVal
in inValues:
127 newExposureInfoList.append(info)
129 self.log.
info(
"De-selecting exposure %s: not in selectDataList" % info.dataId)
130 exposureInfoList = newExposureInfoList
133 butler = dataRef.butlerSubset.butler
134 dataRefList = [butler.dataRef(datasetType=
"calexp",
135 dataId=expInfo.dataId,
136 )
for expInfo
in exposureInfoList]
140 return pipeBase.Struct(
141 dataRefList=dataRefList,
142 exposureInfoList=exposureInfoList,
146 def _extractKeyValue(dataList, keys=None):
147 """Extract the keys and values from a list of dataIds
149 The input dataList is a list of objects that have 'dataId' members.
150 This allows it to be used for both a list of data references and a
153 assert len(dataList) > 0
155 keys = sorted(dataList[0].dataId.keys())
158 for data
in dataList:
159 thisKeys =
set(data.dataId.keys())
160 if thisKeys != keySet:
161 raise RuntimeError(
"DataId keys inconsistent: %s vs %s" % (keySet, thisKeys))
162 values.append(tuple(data.dataId[k]
for k
in keys))
167 """A container for data to be passed to the WcsSelectImagesTask"""
170 super(SelectStruct, self).
__init__(dataRef=dataRef, wcs=wcs, bbox=bbox)
174 """Select images using their Wcs
176 We use the "convexHull" method of lsst.sphgeom.ConvexPolygon to define
177 polygons on the celestial sphere, and test the polygon of the
178 patch for overlap with the polygon of the image.
180 We use "convexHull" instead of generating a ConvexPolygon
181 directly because the standard for the inputs to ConvexPolygon
182 are pretty high and we don't want to be responsible for reaching them.
185 def runDataRef(self, dataRef, coordList, makeDataRefList=True, selectDataList=[]):
186 """Select images in the selectDataList that overlap the patch
188 This method is the old entry point for the Gen2 commandline tasks and drivers
189 Will be deprecated in v22.
191 @param dataRef: Data reference for coadd/tempExp (with tract, patch)
192 @param coordList: List of ICRS coordinates (lsst.geom.SpherePoint) specifying boundary of patch
193 @param makeDataRefList: Construct a list of data references?
194 @param selectDataList: List of SelectStruct, to consider for selection
197 exposureInfoList = []
199 patchVertices = [coord.getVector()
for coord
in coordList]
202 for data
in selectDataList:
203 dataRef = data.dataRef
207 imageCorners = self.
getValidImageCornersgetValidImageCorners(imageWcs, imageBox, patchPoly, dataId=
None)
209 dataRefList.append(dataRef)
212 return pipeBase.Struct(
213 dataRefList=dataRefList
if makeDataRefList
else None,
214 exposureInfoList=exposureInfoList,
217 def run(self, wcsList, bboxList, coordList, dataIds=None, **kwargs):
218 """Return indices of provided lists that meet the selection criteria
222 wcsList : `list` of `lsst.afw.geom.SkyWcs`
223 specifying the WCS's of the input ccds to be selected
224 bboxList : `list` of `lsst.geom.Box2I`
225 specifying the bounding boxes of the input ccds to be selected
226 coordList : `list` of `lsst.geom.SpherePoint`
227 ICRS coordinates specifying boundary of the patch.
231 result: `list` of `int`
232 of indices of selected ccds
235 dataIds = [
None] * len(wcsList)
236 patchVertices = [coord.getVector()
for coord
in coordList]
239 for i, (imageWcs, imageBox, dataId)
in enumerate(zip(wcsList, bboxList, dataIds)):
240 imageCorners = self.
getValidImageCornersgetValidImageCorners(imageWcs, imageBox, patchPoly, dataId)
246 "Return corners or None if bad"
248 imageCorners = [imageWcs.pixelToSky(pix)
for pix
in geom.Box2D(imageBox).getCorners()]
251 self.log.
debug(
"WCS error in testing calexp %s (%s): deselecting", dataId, e)
255 if imagePoly
is None:
256 self.log.
debug(
"Unable to create polygon from image %s: deselecting", dataId)
259 if patchPoly.intersects(imagePoly):
261 self.log.
info(
"Selecting calexp %s" % dataId)
266 "Return median absolute deviation scaled to normally distributed data"
267 return 1.4826*np.median(np.abs(array - np.median(array)))
271 dimensions=(
"tract",
"patch",
"skymap",
"instrument",
"visit"),
272 defaultTemplates={
"coaddName":
"deep"}):
276 class PsfWcsSelectImagesConfig(pipeBase.PipelineTaskConfig,
277 pipelineConnections=PsfWcsSelectImagesConnections):
278 maxEllipResidual = pexConfig.Field(
279 doc=
"Maximum median ellipticity residual",
284 maxSizeScatter = pexConfig.Field(
285 doc=
"Maximum scatter in the size residuals",
289 maxScaledSizeScatter = pexConfig.Field(
290 doc=
"Maximum scatter in the size residuals, scaled by the median size",
295 starSelection = pexConfig.Field(
296 doc=
"select star with this field",
298 default=
'calib_psf_used'
300 starShape = pexConfig.Field(
301 doc=
"name of star shape",
303 default=
'base_SdssShape'
305 psfShape = pexConfig.Field(
306 doc=
"name of psf shape",
308 default=
'base_SdssShape_psf'
313 """Select images using their Wcs and cuts on the PSF properties
315 The PSF quality criteria are based on the size and ellipticity residuals from the
316 adaptive second moments of the star and the PSF.
319 - the median of the ellipticty residuals
320 - the robust scatter of the size residuals (using the median absolute deviation)
321 - the robust scatter of the size residuals scaled by the square of
325 ConfigClass = PsfWcsSelectImagesConfig
326 _DefaultName =
"PsfWcsSelectImages"
328 def runDataRef(self, dataRef, coordList, makeDataRefList=True, selectDataList=[]):
329 """Select images in the selectDataList that overlap the patch and satisfy PSF quality critera.
331 This method is the old entry point for the Gen2 commandline tasks and drivers
332 Will be deprecated in v22.
334 @param dataRef: Data reference for coadd/tempExp (with tract, patch)
335 @param coordList: List of ICRS coordinates (lsst.geom.SpherePoint) specifying boundary of patch
336 @param makeDataRefList: Construct a list of data references?
337 @param selectDataList: List of SelectStruct, to consider for selection
339 result = super(PsfWcsSelectImagesTask, self).runDataRef(dataRef, coordList, makeDataRefList,
343 exposureInfoList = []
344 for dataRef, exposureInfo
in zip(result.dataRefList, result.exposureInfoList):
345 butler = dataRef.butlerSubset.butler
346 srcCatalog = butler.get(
'src', dataRef.dataId)
347 valid = self.isValid(srcCatalog, dataRef.dataId)
351 dataRefList.append(dataRef)
352 exposureInfoList.append(exposureInfo)
354 return pipeBase.Struct(
355 dataRefList=dataRefList,
356 exposureInfoList=exposureInfoList,
359 def run(self, wcsList, bboxList, coordList, srcList, dataIds=None, **kwargs):
360 """Return indices of provided lists that meet the selection criteria
364 wcsList : `list` of `lsst.afw.geom.SkyWcs`
365 specifying the WCS's of the input ccds to be selected
366 bboxList : `list` of `lsst.geom.Box2I`
367 specifying the bounding boxes of the input ccds to be selected
368 coordList : `list` of `lsst.geom.SpherePoint`
369 ICRS coordinates specifying boundary of the patch.
370 srcList : `list` of `lsst.afw.table.SourceCatalog`
371 containing the PSF shape information for the input ccds to be selected
375 goodPsf: `list` of `int`
376 of indices of selected ccds
378 goodWcs = super(PsfWcsSelectImagesTask, self).
run(wcsList=wcsList, bboxList=bboxList,
379 coordList=coordList, dataIds=dataIds)
383 dataIds = [
None] * len(srcList)
384 for i, (srcCatalog, dataId)
in enumerate(zip(srcList, dataIds)):
387 if self.isValid(srcCatalog, dataId):
392 def isValid(self, srcCatalog, dataId=None):
393 """Should this ccd be selected based on its PSF shape information
397 srcCatalog : `lsst.afw.table.SourceCatalog`
398 dataId : `dict` of dataId keys, optional.
399 Used only for logging. Defaults to None.
406 mask = srcCatalog[self.config.starSelection]
408 starXX = srcCatalog[self.config.starShape+
'_xx'][mask]
409 starYY = srcCatalog[self.config.starShape+
'_yy'][mask]
410 starXY = srcCatalog[self.config.starShape+
'_xy'][mask]
411 psfXX = srcCatalog[self.config.psfShape+
'_xx'][mask]
412 psfYY = srcCatalog[self.config.psfShape+
'_yy'][mask]
413 psfXY = srcCatalog[self.config.psfShape+
'_xy'][mask]
415 starSize = np.power(starXX*starYY - starXY**2, 0.25)
416 starE1 = (starXX - starYY)/(starXX + starYY)
417 starE2 = 2*starXY/(starXX + starYY)
418 medianSize = np.median(starSize)
420 psfSize = np.power(psfXX*psfYY - psfXY**2, 0.25)
421 psfE1 = (psfXX - psfYY)/(psfXX + psfYY)
422 psfE2 = 2*psfXY/(psfXX + psfYY)
424 medianE1 = np.abs(np.median(starE1 - psfE1))
425 medianE2 = np.abs(np.median(starE2 - psfE2))
426 medianE = np.sqrt(medianE1**2 + medianE2**2)
428 scatterSize =
sigmaMad(starSize - psfSize)
429 scaledScatterSize = scatterSize/medianSize**2
432 if self.config.maxEllipResidual
and medianE > self.config.maxEllipResidual:
433 self.log.
info(
"Removing visit %s because median e residual too large: %f vs %f" %
434 (dataId, medianE, self.config.maxEllipResidual))
436 elif self.config.maxSizeScatter
and scatterSize > self.config.maxSizeScatter:
437 self.log.
info(
"Removing visit %s because size scatter is too large: %f vs %f" %
438 (dataId, scatterSize, self.config.maxSizeScatter))
440 elif self.config.maxScaledSizeScatter
and scaledScatterSize > self.config.maxScaledSizeScatter:
441 self.log.
info(
"Removing visit %s because scaled size scatter is too large: %f vs %f" %
442 (dataId, scaledScatterSize, self.config.maxScaledSizeScatter))
448 class BestSeeingWcsSelectImageConfig(WcsSelectImagesTask.ConfigClass):
449 """Base configuration for BestSeeingSelectImagesTask.
451 nImagesMax = pexConfig.RangeField(
453 doc=
"Maximum number of images to select",
456 maxPsfFwhm = pexConfig.Field(
458 doc=
"Maximum PSF FWHM (in arcseconds) to select",
461 minPsfFwhm = pexConfig.Field(
463 doc=
"Minimum PSF FWHM (in arcseconds) to select",
469 """Select up to a maximum number of the best-seeing images using their Wcs.
471 ConfigClass = BestSeeingWcsSelectImageConfig
473 def runDataRef(self, dataRef, coordList, makeDataRefList=True,
474 selectDataList=None):
475 """Select the best-seeing images in the selectDataList that overlap the patch.
477 This method is the old entry point for the Gen2 commandline tasks and drivers
478 Will be deprecated in v22.
482 dataRef : `lsst.daf.persistence.ButlerDataRef`
483 Data reference for coadd/tempExp (with tract, patch)
484 coordList : `list` of `lsst.geom.SpherePoint`
485 List of ICRS sky coordinates specifying boundary of patch
486 makeDataRefList : `boolean`, optional
487 Construct a list of data references?
488 selectDataList : `list` of `SelectStruct`
489 List of SelectStruct, to consider for selection
493 result : `lsst.pipe.base.Struct`
494 Result struct with components:
495 - ``exposureList``: the selected exposures
496 (`list` of `lsst.pipe.tasks.selectImages.BaseExposureInfo`).
497 - ``dataRefList``: the optional data references corresponding to
498 each element of ``exposureList``
499 (`list` of `lsst.daf.persistence.ButlerDataRef`, or `None`).
503 exposureInfoList = []
505 if selectDataList
is None:
508 result = super().runDataRef(dataRef, coordList, makeDataRefList=
True, selectDataList=selectDataList)
510 for dataRef, exposureInfo
in zip(result.dataRefList, result.exposureInfoList):
511 cal = dataRef.get(
"calexp", immediate=
True)
514 pixToArcseconds = cal.getWcs().getPixelScale().asArcseconds()
515 psfSize = cal.getPsf().computeShape().getDeterminantRadius()*pixToArcseconds
516 sizeFwhm = psfSize * np.sqrt(8.*np.log(2.))
517 if self.config.maxPsfFwhm
and sizeFwhm > self.config.maxPsfFwhm:
519 if self.config.minPsfFwhm
and sizeFwhm < self.config.minPsfFwhm:
521 psfSizes.append(sizeFwhm)
522 dataRefList.append(dataRef)
523 exposureInfoList.append(exposureInfo)
525 if len(psfSizes) > self.config.nImagesMax:
526 sortedIndices = np.argsort(psfSizes)[:self.config.nImagesMax]
527 filteredDataRefList = [dataRefList[i]
for i
in sortedIndices]
528 filteredExposureInfoList = [exposureInfoList[i]
for i
in sortedIndices]
529 self.log.
info(f
"{len(sortedIndices)} images selected with FWHM "
530 f
"range of {psfSizes[sortedIndices[0]]}--{psfSizes[sortedIndices[-1]]} arcseconds")
533 if len(psfSizes) == 0:
534 self.log.
warn(
"0 images selected.")
536 self.log.
debug(f
"{len(psfSizes)} images selected with FWHM range "
537 f
"of {psfSizes[0]}--{psfSizes[-1]} arcseconds")
538 filteredDataRefList = dataRefList
539 filteredExposureInfoList = exposureInfoList
541 return pipeBase.Struct(
542 dataRefList=filteredDataRefList
if makeDataRefList
else None,
543 exposureInfoList=filteredExposureInfoList,
547 class BestSeeingSelectVisitsConnections(pipeBase.PipelineTaskConnections,
548 dimensions=(
"tract",
"patch",
"skymap",
"band",
"instrument"),
549 defaultTemplates={
"coaddName":
"bestSeeing"}):
550 skyMap = pipeBase.connectionTypes.Input(
551 doc=
"Input definition of geometry/bbox and projection/wcs for coadded exposures",
552 name=BaseSkyMap.SKYMAP_DATASET_TYPE_NAME,
553 storageClass=
"SkyMap",
554 dimensions=(
"skymap",),
556 visitSummaries = pipeBase.connectionTypes.Input(
557 doc=
"Per-visit consolidated exposure metadata from ConsolidateVisitSummaryTask",
559 storageClass=
"ExposureCatalog",
560 dimensions=(
"instrument",
"visit",),
564 goodVisits = pipeBase.connectionTypes.Output(
565 doc=
"Selected visits to be coadded.",
566 name=
"{coaddName}VisitsDict",
567 storageClass=
"StructuredDataDict",
568 dimensions=(
"instrument",
"tract",
"patch",
"skymap",
"band"),
572 class BestSeeingSelectVisitsConfig(pipeBase.PipelineTaskConfig,
573 pipelineConnections=BestSeeingSelectVisitsConnections):
574 nVisitsMax = pexConfig.RangeField(
576 doc=
"Maximum number of visits to select",
580 maxPsfFwhm = pexConfig.Field(
582 doc=
"Maximum PSF FWHM (in arcseconds) to select",
586 minPsfFwhm = pexConfig.Field(
588 doc=
"Minimum PSF FWHM (in arcseconds) to select",
592 doConfirmOverlap = pexConfig.Field(
594 doc=
"Do remove visits that do not actually overlap the patch?",
599 class BestSeeingSelectVisitsTask(pipeBase.PipelineTask):
600 """Select up to a maximum number of the best-seeing visits
602 Don't exceed the FWHM range specified by configs min(max)PsfFwhm.
603 This Task is a port of the Gen2 image-selector used in the AP pipeline:
604 BestSeeingSelectImagesTask. This Task selects full visits based on the
605 average PSF of the entire visit.
607 ConfigClass = BestSeeingSelectVisitsConfig
608 _DefaultName =
'bestSeeingSelectVisits'
610 def runQuantum(self, butlerQC, inputRefs, outputRefs):
611 inputs = butlerQC.get(inputRefs)
612 quantumDataId = butlerQC.quantum.dataId
613 outputs = self.run(**inputs, dataId=quantumDataId)
614 butlerQC.put(outputs, outputRefs)
616 def run(self, visitSummaries, skyMap, dataId):
621 visitSummary : `list`
622 List of `lsst.pipe.base.connections.DeferredDatasetRef` of
623 visitSummary tables of type `lsst.afw.table.ExposureCatalog`
624 skyMap : `lsst.skyMap.SkyMap`
625 SkyMap for checking visits overlap patch
626 dataId : `dict` of dataId keys
627 For retrieving patch info for checking visits overlap patch
631 result : `lsst.pipe.base.Struct`
632 Result struct with components:
634 - `goodVisits`: `dict` with selected visit ids as keys,
635 so that it can be be saved as a StructuredDataDict.
636 StructuredDataList's are currently limited.
639 if self.config.doConfirmOverlap:
640 patchPolygon = self.makePatchPolygon(skyMap, dataId)
642 inputVisits = [visitSummary.ref.dataId[
'visit']
for visitSummary
in visitSummaries]
645 for visit, visitSummary
in zip(inputVisits, visitSummaries):
647 visitSummary = visitSummary.get()
649 pixToArcseconds = [vs.getWcs().getPixelScale(vs.getBBox().getCenter()).asArcseconds()
650 for vs
in visitSummary]
652 psfSigmas = np.array([vs[
'psfSigma']
for vs
in visitSummary])
653 fwhm = np.nanmean(psfSigmas * pixToArcseconds) * np.sqrt(8.*np.log(2.))
655 if self.config.maxPsfFwhm
and fwhm > self.config.maxPsfFwhm:
657 if self.config.minPsfFwhm
and fwhm < self.config.minPsfFwhm:
659 if self.config.doConfirmOverlap
and not self.doesIntersectPolygon(visitSummary, patchPolygon):
662 fwhmSizes.append(fwhm)
665 sortedVisits = [ind
for (_, ind)
in sorted(zip(fwhmSizes, visits))]
666 output = sortedVisits[:self.config.nVisitsMax]
667 self.log.
info(f
"{len(output)} images selected with FWHM "
668 f
"range of {fwhmSizes[visits.index(output[0])]}"
669 f
"--{fwhmSizes[visits.index(output[-1])]} arcseconds")
672 goodVisits = {key:
True for key
in output}
673 return pipeBase.Struct(goodVisits=goodVisits)
675 def makePatchPolygon(self, skyMap, dataId):
676 """Return True if sky polygon overlaps visit
680 skyMap : `lsst.afw.table.ExposureCatalog`
681 Exposure catalog with per-detector geometry
682 dataId : `dict` of dataId keys
683 For retrieving patch info
687 result :` lsst.sphgeom.ConvexPolygon.convexHull`
688 Polygon of patch's outer bbox
690 wcs = skyMap[dataId[
'tract']].getWcs()
691 bbox = skyMap[dataId[
'tract']][dataId[
'patch']].getOuterBBox()
696 def doesIntersectPolygon(self, visitSummary, polygon):
697 """Return True if sky polygon overlaps visit
701 visitSummary : `lsst.afw.table.ExposureCatalog`
702 Exposure catalog with per-detector geometry
703 polygon :` lsst.sphgeom.ConvexPolygon.convexHull`
704 Polygon to check overlap
708 doesIntersect: `bool`
709 Does the visit overlap the polygon
711 doesIntersect =
False
712 for detectorSummary
in visitSummary:
714 zip(detectorSummary[
'raCorners'], detectorSummary[
'decCorners'])]
716 if detectorPolygon.intersects(polygon):
722 class BestSeeingQuantileSelectVisitsConfig(pipeBase.PipelineTaskConfig,
723 pipelineConnections=BestSeeingSelectVisitsConnections):
724 qMin = pexConfig.RangeField(
725 doc=
"Lower bound of quantile range to select. Sorts visits by seeing from narrow to wide, "
726 "and select those in the interquantile range (qMin, qMax). Set qMin to 0 for Best Seeing. "
727 "This config should be changed from zero only for exploratory diffIm testing.",
733 qMax = pexConfig.RangeField(
734 doc=
"Upper bound of quantile range to select. Sorts visits by seeing from narrow to wide, "
735 "and select those in the interquantile range (qMin, qMax). Set qMax to 1 for Worst Seeing.",
741 nVisitsMin = pexConfig.Field(
742 doc=
"At least this number of visits selected and supercedes quantile. For example, if 10 visits "
743 "cover this patch, qMin=0.33, and nVisitsMin=5, the best 5 visits will be selected.",
747 doConfirmOverlap = pexConfig.Field(
749 doc=
"Do remove visits that do not actually overlap the patch?",
754 class BestSeeingQuantileSelectVisitsTask(BestSeeingSelectVisitsTask):
755 """Select a quantile of the best-seeing visits
757 Selects the best (for example, third) full visits based on the average
758 PSF width in the entire visit. It can also be used for difference imaging
759 experiments that require templates with the worst seeing visits.
760 For example, selecting the worst third can be acheived by
761 changing the config parameters qMin to 0.66 and qMax to 1.
763 ConfigClass = BestSeeingQuantileSelectVisitsConfig
764 _DefaultName =
'bestSeeingQuantileSelectVisits'
766 @utils.inheritDoc(BestSeeingSelectVisitsTask)
767 def run(self, visitSummaries, skyMap, dataId):
768 if self.config.doConfirmOverlap:
769 patchPolygon = self.makePatchPolygon(skyMap, dataId)
770 visits = np.array([visitSummary.ref.dataId[
'visit']
for visitSummary
in visitSummaries])
771 radius = np.empty(len(visits))
772 intersects = np.full(len(visits),
True)
773 for i, visitSummary
in enumerate(visitSummaries):
775 visitSummary = visitSummary.get()
777 psfSigma = np.nanmedian([vs[
'psfSigma']
for vs
in visitSummary])
779 if self.config.doConfirmOverlap:
780 intersects[i] = self.doesIntersectPolygon(visitSummary, patchPolygon)
782 sortedVisits = [v
for rad, v
in sorted(zip(radius[intersects], visits[intersects]))]
783 lowerBound =
min(int(np.round(self.config.qMin*len(visits))),
784 max(0, len(visits) - self.config.nVisitsMin))
785 upperBound =
max(int(np.round(self.config.qMax*len(visits))), self.config.nVisitsMin)
788 goodVisits = {int(visit):
True for visit
in sortedVisits[lowerBound:upperBound]}
789 return pipeBase.Struct(goodVisits=goodVisits)
A floating-point coordinate rectangle geometry.
Point in an unspecified spherical coordinate system.
Reports arguments outside the domain of an operation.
Reports errors that are due to events beyond the control of the program.
def __init__(self, dataId, coordList)
def _runArgDictFromDataId(self, dataId)
def runDataRef(self, dataRef, coordList, makeDataRefList=True, selectDataList=[])
def __init__(self, dataRef, wcs, bbox)
def getValidImageCorners(self, imageWcs, imageBox, patchPoly, dataId=None)
def runDataRef(self, dataRef, coordList, makeDataRefList=True, selectDataList=[])
def run(self, wcsList, bboxList, coordList, dataIds=None, **kwargs)
static ConvexPolygon convexHull(std::vector< UnitVector3d > const &points)
convexHull returns the convex hull of the given set of points if it exists and throws an exception ot...
daf::base::PropertyList * list
daf::base::PropertySet * set
def run(self, skyInfo, tempExpRefList, imageScalerList, weightList, altMaskList=None, mask=None, supplementaryData=None)