34 from .forcedPhotImage
import ForcedPhotImageTask, ForcedPhotImageConfig
37 from lsst.meas.mosaic
import applyMosaicResults
39 applyMosaicResults =
None 41 __all__ = (
"PerTractCcdDataIdContainer",
"ForcedPhotCcdConfig",
"ForcedPhotCcdTask",
"imageOverlapsTract")
45 """A data ID container which combines raw data IDs with a tract. 49 Required because we need to add "tract" to the raw data ID keys (defined as 50 whatever we use for ``src``) when no tract is provided (so that the user is 51 not required to know which tracts are spanned by the raw data ID). 53 This subclass of `~lsst.pipe.base.DataIdContainer` assumes that a calexp is 54 being measured using the detection information, a set of reference 55 catalogs, from the set of coadds which intersect with the calexp. It needs 56 the calexp id (e.g. visit, raft, sensor), but is also uses the tract to 57 decide what set of coadds to use. The references from the tract whose 58 patches intersect with the calexp are used. 62 """Make self.refList from self.idList 64 if self.datasetType
is None:
65 raise RuntimeError(
"Must call setDatasetType first")
66 log = Log.getLogger(
"meas.base.forcedPhotCcd.PerTractCcdDataIdContainer")
68 visitTract = collections.defaultdict(set)
69 visitRefs = collections.defaultdict(list)
70 for dataId
in self.idList:
71 if "tract" not in dataId:
73 log.info(
"Reading WCS for components of dataId=%s to determine tracts", dict(dataId))
75 skymap = namespace.butler.get(namespace.config.coaddName +
"Coadd_skyMap")
77 for ref
in namespace.butler.subset(
"calexp", dataId=dataId):
78 if not ref.datasetExists(
"calexp"):
81 visit = ref.dataId[
"visit"]
82 visitRefs[visit].append(ref)
84 md = ref.get(
"calexp_md", immediate=
True)
89 tract = skymap.findTract(wcs.pixelToSky(box.getCenter()))
91 visitTract[visit].add(tract.getId())
93 self.refList.extend(ref
for ref
in namespace.butler.subset(self.datasetType, dataId=dataId))
96 for visit, tractSet
in visitTract.items():
97 for ref
in visitRefs[visit]:
98 for tract
in tractSet:
99 self.refList.append(namespace.butler.dataRef(datasetType=self.datasetType,
100 dataId=ref.dataId, tract=tract))
102 tractCounter = collections.Counter()
103 for tractSet
in visitTract.values():
104 tractCounter.update(tractSet)
105 log.info(
"Number of visits for each tract: %s", dict(tractCounter))
109 """Return whether the given bounding box overlaps the tract given a WCS. 113 tract : `lsst.skymap.TractInfo` 114 TractInfo specifying a tract. 115 imageWcs : `lsst.afw.geom.SkyWcs` 116 World coordinate system for the image. 117 imageBox : `lsst.geom.Box2I` 118 Bounding box for the image. 123 `True` if the bounding box overlaps the tract; `False` otherwise. 125 tractPoly = tract.getOuterSkyPolygon()
129 imageSkyCorners = imageWcs.pixelToSky(imagePixelCorners)
130 except lsst.pex.exceptions.LsstCppException
as e:
132 if (
not isinstance(e.message, lsst.pex.exceptions.DomainErrorException)
and 133 not isinstance(e.message, lsst.pex.exceptions.RuntimeErrorException)):
138 return tractPoly.intersects(imagePoly)
142 doApplyUberCal = lsst.pex.config.Field(
144 doc=
"Apply meas_mosaic ubercal results to input calexps?",
150 """A command-line driver for performing forced measurement on CCD images. 154 This task is a subclass of 155 :lsst-task:`lsst.meas.base.forcedPhotImage.ForcedPhotImageTask` which is 156 specifically for doing forced measurement on a single CCD exposure, using 157 as a reference catalog the detections which were made on overlapping 160 The `run` method (inherited from `ForcedPhotImageTask`) takes a 161 `~lsst.daf.persistence.ButlerDataRef` argument that corresponds to a single 162 CCD. This should contain the data ID keys that correspond to the 163 ``forced_src`` dataset (the output dataset for this task), which are 164 typically all those used to specify the ``calexp`` dataset (``visit``, 165 ``raft``, ``sensor`` for LSST data) as well as a coadd tract. The tract is 166 used to look up the appropriate coadd measurement catalogs to use as 167 references (e.g. ``deepCoadd_src``; see 168 :lsst-task:`lsst.meas.base.references.CoaddSrcReferencesTask` for more 169 information). While the tract must be given as part of the dataRef, the 170 patches are determined automatically from the bounding box and WCS of the 171 calexp to be measured, and the filter used to fetch references is set via 172 the ``filter`` option in the configuration of 173 :lsst-task:`lsst.meas.base.references.BaseReferencesTask`). 175 In addition to the `run` method, `ForcedPhotCcdTask` overrides several 176 methods of `ForcedPhotImageTask` to specialize it for single-CCD 177 processing, including `~ForcedPhotImageTask.makeIdFactory`, 178 `~ForcedPhotImageTask.fetchReferences`, and 179 `~ForcedPhotImageTask.getExposure`. None of these should be called 180 directly by the user, though it may be useful to override them further in 184 ConfigClass = ForcedPhotCcdConfig
185 RunnerClass = lsst.pipe.base.ButlerInitializedTaskRunner
186 _DefaultName =
"forcedPhotCcd" 190 """Create an object that generates globally unique source IDs. 192 Source IDs are created based on a per-CCD ID and the ID of the CCD 197 dataRef : `lsst.daf.persistence.ButlerDataRef` 198 Butler data reference. The ``ccdExposureId_bits`` and 199 ``ccdExposureId`` datasets are accessed. The data ID must have the 200 keys that correspond to ``ccdExposureId``, which are generally the 201 same as those that correspond to ``calexp`` (``visit``, ``raft``, 202 ``sensor`` for LSST data). 204 expBits = dataRef.get(
"ccdExposureId_bits")
205 expId = int(dataRef.get(
"ccdExposureId"))
209 return int(dataRef.get(
"ccdExposureId", immediate=
True))
212 """Get sources that overlap the exposure. 216 dataRef : `lsst.daf.persistence.ButlerDataRef` 217 Butler data reference corresponding to the image to be measured; 218 should have ``tract``, ``patch``, and ``filter`` keys. 219 exposure : `lsst.afw.image.Exposure` 220 The image to be measured (used only to obtain a WCS and bounding 225 referencs : `lsst.afw.table.SourceCatalog` 226 Catalog of sources that overlap the exposure 230 The returned catalog is sorted by ID and guarantees that all included 231 children have their parent included and that all Footprints are valid. 233 All work is delegated to the references subtask; see 234 :lsst-task:`lsst.meas.base.references.CoaddSrcReferencesTask` 235 for information about the default behavior. 239 unfiltered = self.references.fetchInBox(dataRef, exposure.getBBox(), exposure.getWcs())
240 for record
in unfiltered:
241 if record.getFootprint()
is None or record.getFootprint().getArea() == 0:
242 if record.getParent() != 0:
243 self.log.warn(
"Skipping reference %s (child of %s) with bad Footprint",
244 record.getId(), record.getParent())
246 self.log.warn(
"Skipping reference parent %s with bad Footprint", record.getId())
247 badParents.add(record.getId())
248 elif record.getParent()
not in badParents:
249 references.append(record)
255 """Read input exposure for measurement. 259 dataRef : `lsst.daf.persistence.ButlerDataRef` 260 Butler data reference. Only the ``calexp`` dataset is used, unless 261 ``config.doApplyUberCal`` is `True`, in which case the 262 corresponding meas_mosaic outputs are used as well. 264 exposure = ForcedPhotImageTask.getExposure(self, dataRef)
265 if not self.config.doApplyUberCal:
267 if applyMosaicResults
is None:
269 "Cannot use improved calibrations for %s because meas_mosaic could not be imported." 275 def _getConfigName(self):
277 return self.
dataPrefix +
"forcedPhotCcd_config" 279 def _getMetadataName(self):
281 return self.
dataPrefix +
"forcedPhotCcd_metadata" 284 def _makeArgumentParser(cls):
285 parser = lsst.pipe.base.ArgumentParser(name=cls.
_DefaultName)
286 parser.add_id_argument(
"--id",
"forced_src", help=
"data ID with raw CCD keys [+ tract optionally], " 287 "e.g. --id visit=12345 ccd=1,2 [tract=0]",
288 ContainerClass=PerTractCcdDataIdContainer)
def getExposure(self, dataRef)
def makeDataRefList(self, namespace)
def makeIdFactory(self, dataRef)
static std::shared_ptr< IdFactory > makeSource(RecordId expId, int reserved)
static ConvexPolygon convexHull(std::vector< UnitVector3d > const &points)
def imageOverlapsTract(tract, imageWcs, imageBox)
def getExposureId(self, dataRef)
std::shared_ptr< SkyWcs > makeSkyWcs(TransformPoint2ToPoint2 const &pixelsToFieldAngle, lsst::geom::Angle const &orientation, bool flipX, lsst::geom::SpherePoint const &boresight, std::string const &projection="TAN")
static Key< RecordId > getParentKey()
def fetchReferences(self, dataRef, exposure)
lsst::geom::Box2I bboxFromMetadata(daf::base::PropertySet &metadata)