31 from lsst.geom
import convexHull
33 from .forcedPhotImage
import ForcedPhotImageTask, ForcedPhotImageConfig
36 from lsst.meas.mosaic
import applyMosaicResults
38 applyMosaicResults =
None 40 __all__ = (
"PerTractCcdDataIdContainer",
"ForcedPhotCcdConfig",
"ForcedPhotCcdTask")
44 """A version of lsst.pipe.base.DataIdContainer that combines raw data IDs with a tract. 46 Required because we need to add "tract" to the raw data ID keys (defined as whatever we 47 use for 'src') when no tract is provided (so that the user is not required to know 48 which tracts are spanned by the raw data ID). 50 This IdContainer assumes that a calexp is being measured using the detection information, 51 a set of reference catalogs, from the set of coadds which intersect with the calexp. 52 It needs the calexp id (e.g. visit, raft, sensor), but is also uses the tract to decide 53 what set of coadds to use. The references from the tract whose patches intersect with 58 """Make self.refList from self.idList 60 if self.datasetType
is None:
61 raise RuntimeError(
"Must call setDatasetType first")
62 log = Log.getLogger(
"meas.base.forcedPhotCcd.PerTractCcdDataIdContainer")
64 visitTract = collections.defaultdict(set)
65 visitRefs = collections.defaultdict(list)
66 for dataId
in self.idList:
67 if "tract" not in dataId:
69 log.info(
"Reading WCS for components of dataId=%s to determine tracts", dict(dataId))
71 skymap = namespace.butler.get(namespace.config.coaddName +
"Coadd_skyMap")
73 for ref
in namespace.butler.subset(
"calexp", dataId=dataId):
74 if not ref.datasetExists(
"calexp"):
77 visit = ref.dataId[
"visit"]
78 visitRefs[visit].append(ref)
80 md = ref.get(
"calexp_md", immediate=
True)
85 tract = skymap.findTract(wcs.pixelToSky(box.getCenter()))
87 visitTract[visit].add(tract.getId())
89 self.refList.extend(ref
for ref
in namespace.butler.subset(self.datasetType, dataId=dataId))
92 for visit, tractSet
in visitTract.items():
93 for ref
in visitRefs[visit]:
94 for tract
in tractSet:
95 self.refList.append(namespace.butler.dataRef(datasetType=self.datasetType,
96 dataId=ref.dataId, tract=tract))
98 tractCounter = collections.Counter()
99 for tractSet
in visitTract.values():
100 tractCounter.update(tractSet)
101 log.info(
"Number of visits for each tract: %s", dict(tractCounter))
105 """Return whether the image (specified by Wcs and bounding box) overlaps the tract 107 @param tract: TractInfo specifying a tract 108 @param imageWcs: Wcs for image 109 @param imageBox: Bounding box for image 112 tractWcs = tract.getWcs()
114 coord
in tract.getBBox().getCorners()]
115 tractPoly = convexHull(tractCorners)
119 except lsst.pex.exceptions.LsstCppException
as e:
121 if (
not isinstance(e.message, lsst.pex.exceptions.DomainErrorException)
and 122 not isinstance(e.message, lsst.pex.exceptions.RuntimeErrorException)):
126 imagePoly = convexHull([coord.getVector()
for coord
in imageCorners])
127 if imagePoly
is None:
129 return tractPoly.intersects(imagePoly)
133 doApplyUberCal = lsst.pex.config.Field(
135 doc=
"Apply meas_mosaic ubercal results to input calexps?",
148 """!A command-line driver for performing forced measurement on CCD images 150 This task is a subclass of ForcedPhotImageTask which is specifically for doing forced 151 measurement on a single CCD exposure, using as a reference catalog the detections which 152 were made on overlapping coadds. 154 The run method (inherited from ForcedPhotImageTask) takes a lsst.daf.persistence.ButlerDataRef 155 argument that corresponds to a single CCD. This should contain the data ID keys that correspond to 156 the "forced_src" dataset (the output dataset for ForcedPhotCcdTask), which are typically all those 157 used to specify the "calexp" dataset (e.g. visit, raft, sensor for LSST data) as well as a coadd 158 tract. The tract is used to look up the appropriate coadd measurement catalogs to use as references 159 (e.g. deepCoadd_src; see CoaddSrcReferencesTask for more information). While the tract must be given 160 as part of the dataRef, the patches are determined automatically from the bounding box and WCS of the 161 calexp to be measured, and the filter used to fetch references is set via config 162 (BaseReferencesConfig.filter). 164 In addition to the run method, ForcedPhotCcdTask overrides several methods of ForcedPhotImageTask 165 to specialize it for single-CCD processing, including makeIdFactory(), fetchReferences(), and 166 getExposure(). None of these should be called directly by the user, though it may be useful 167 to override them further in subclasses. 170 ConfigClass = ForcedPhotCcdConfig
171 RunnerClass = lsst.pipe.base.ButlerInitializedTaskRunner
172 _DefaultName =
"forcedPhotCcd" 176 """Create an object that generates globally unique source IDs from per-CCD IDs and the CCD ID. 178 @param dataRef Data reference from butler. The "ccdExposureId_bits" and "ccdExposureId" 179 datasets are accessed. The data ID must have the keys that correspond 180 to ccdExposureId, which is generally the same that correspond to "calexp" 181 (e.g. visit, raft, sensor for LSST data). 183 expBits = dataRef.get(
"ccdExposureId_bits")
184 expId = int(dataRef.get(
"ccdExposureId"))
188 return int(dataRef.get(
"ccdExposureId", immediate=
True))
191 """Return a SourceCatalog of sources which overlap the exposure. 193 The returned catalog is sorted by ID and guarantees that all included children have their 194 parent included and that all Footprints are valid. 196 @param dataRef Data reference from butler corresponding to the image to be measured; 197 should have tract, patch, and filter keys. 198 @param exposure lsst.afw.image.Exposure to be measured (used only to obtain a Wcs and 201 All work is delegated to the references subtask; see CoaddSrcReferencesTask for information 202 about the default behavior. 206 unfiltered = self.references.fetchInBox(dataRef, exposure.getBBox(), exposure.getWcs())
207 for record
in unfiltered:
208 if record.getFootprint()
is None or record.getFootprint().getArea() == 0:
209 if record.getParent() != 0:
210 self.log.warn(
"Skipping reference %s (child of %s) with bad Footprint",
211 record.getId(), record.getParent())
213 self.log.warn(
"Skipping reference parent %s with bad Footprint", record.getId())
214 badParents.add(record.getId())
215 elif record.getParent()
not in badParents:
216 references.append(record)
222 """Read input exposure to measure 224 @param dataRef Data reference from butler. Only the 'calexp' dataset is used, 225 unless config.doApplyUberCal is true, in which case the corresponding 226 meas_mosaic outputs are used as well. 228 exposure = ForcedPhotImageTask.getExposure(self, dataRef)
229 if not self.config.doApplyUberCal:
231 if applyMosaicResults
is None:
233 "Cannot use improved calibrations for %s because meas_mosaic could not be imported." 239 def _getConfigName(self):
240 """!Return the name of the config dataset. Forces config comparison from run-to-run 242 return self.
dataPrefix +
"forcedPhotCcd_config" 244 def _getMetadataName(self):
245 """!Return the name of the metadata dataset. Forced metadata to be saved 247 return self.
dataPrefix +
"forcedPhotCcd_metadata" 250 def _makeArgumentParser(cls):
251 parser = lsst.pipe.base.ArgumentParser(name=cls.
_DefaultName)
252 parser.add_id_argument(
"--id",
"forced_src", help=
"data ID with raw CCD keys [+ tract optionally], " 253 "e.g. --id visit=12345 ccd=1,2 [tract=0]",
254 ContainerClass=PerTractCcdDataIdContainer)
def getExposure(self, dataRef)
A base class for command-line forced measurement drivers.
std::shared_ptr< Wcs > makeWcs(coord::Coord const &crval, geom::Point2D const &crpix, double CD11, double CD12, double CD21, double CD22)
def makeDataRefList(self, namespace)
A command-line driver for performing forced measurement on CCD images.
def makeIdFactory(self, dataRef)
static std::shared_ptr< IdFactory > makeSource(RecordId expId, int reserved)
geom::Box2I bboxFromMetadata(daf::base::PropertySet &metadata)
def getExposureId(self, dataRef)
def overlapsTract(tract, imageWcs, imageBox)
static Key< RecordId > getParentKey()
def fetchReferences(self, dataRef, exposure)
Config class for forced measurement driver task.