22 from __future__
import absolute_import, division, print_function
27 import lsst.afw.image
as afwImage
28 import lsst.afw.geom
as afwGeom
29 import lsst.pex.config
as pexConfig
30 import lsst.pipe.base
as pipeBase
31 from lsst.skymap
import DiscreteSkyMap, BaseSkyMap
32 from lsst.pipe.base
import ArgumentParser
36 """Config for MakeDiscreteSkyMapTask 38 coaddName = pexConfig.Field(
39 doc=
"coadd name, e.g. deep, goodSeeing, chiSquared",
43 skyMap = pexConfig.ConfigField(
44 dtype=BaseSkyMap.ConfigClass,
45 doc=
"SkyMap configuration parameters, excluding position and radius" 47 borderSize = pexConfig.Field(
48 doc=
"additional border added to the bounding box of the calexps, in degrees",
52 doAppend = pexConfig.Field(
53 doc=
"append another tract to an existing DiscreteSkyMap on disk, if present?",
57 doWrite = pexConfig.Field(
58 doc=
"persist the skyMap?",
64 self.
skyMap.tractOverlap = 0.0
68 """Run a task with all dataRefs at once, rather than one dataRef at a time. 70 Call the run method of the task using two positional arguments: 72 - dataRefList: list of all dataRefs, 76 return [(parsedCmd.butler, parsedCmd.id.refList)]
80 @param args Arguments for Task.run() 83 - None if self.doReturnResults false 84 - A pipe_base Struct containing these fields if self.doReturnResults true: 85 - dataRef: the provided data reference 86 - metadata: task metadata after execution of run 87 - result: result returned by task run, or None if the task fails 89 butler, dataRefList = args
90 task = self.TaskClass(config=self.config, log=self.log)
93 result = task.run(butler, dataRefList)
96 result = task.run(butler, dataRefList)
97 except Exception
as e:
98 task.log.fatal(
"Failed: %s" % e)
99 if not isinstance(e, pipeBase.TaskError):
100 traceback.print_exc(file=sys.stderr)
101 for dataRef
in dataRefList:
102 task.writeMetadata(dataRef)
104 if self.doReturnResults:
105 return pipeBase.Struct(
106 dataRefList=dataRefList,
107 metadata=task.metadata,
113 """!Make a DiscreteSkyMap in a repository, using the bounding box of a set of calexps. 115 The command-line and run signatures and config are sufficiently different from MakeSkyMapTask 116 that we don't inherit from it, but it is a replacement, so we use the same config/metadata names. 118 ConfigClass = MakeDiscreteSkyMapConfig
119 _DefaultName =
"makeDiscreteSkyMap" 120 RunnerClass = MakeDiscreteSkyMapRunner
123 pipeBase.CmdLineTask.__init__(self, **kwargs)
126 def run(self, butler, dataRefList):
127 """!Make a skymap from the bounds of the given set of calexps. 129 @param[in] butler data butler used to save the SkyMap 130 @param[in] dataRefList dataRefs of calexps used to determine the size and pointing of the SkyMap 131 @return a pipeBase Struct containing: 132 - skyMap: the constructed SkyMap 134 self.log.info(
"Extracting bounding boxes of %d images" % len(dataRefList))
136 for dataRef
in dataRefList:
137 if not dataRef.datasetExists(
"calexp"):
138 self.log.warn(
"CalExp for %s does not exist: ignoring" % (dataRef.dataId,))
140 md = dataRef.get(
"calexp_md", immediate=
True)
141 wcs = afwImage.makeWcs(md)
143 boxI = afwImage.bboxFromMetadata(md)
144 boxD = afwGeom.Box2D(boxI)
145 points.extend(tuple(wcs.pixelToSky(corner).getVector())
for corner
in boxD.getCorners())
147 raise RuntimeError(
"No data found from which to compute convex hull")
148 self.log.info(
"Computing spherical convex hull")
149 polygon = lsst.geom.convexHull(points)
152 "Failed to compute convex hull of the vertices of all calexp bounding boxes; " 153 "they may not be hemispherical." 155 circle = polygon.getBoundingCircle()
157 datasetName = self.config.coaddName +
"Coadd_skyMap" 159 skyMapConfig = DiscreteSkyMap.ConfigClass()
160 if self.config.doAppend
and butler.datasetExists(datasetName):
161 oldSkyMap = butler.get(datasetName, immediate=
True)
162 if not isinstance(oldSkyMap.config, DiscreteSkyMap.ConfigClass):
163 raise TypeError(
"Cannot append to existing non-discrete skymap")
165 if not self.config.skyMap.compare(oldSkyMap.config, output=compareLog.append):
166 raise ValueError(
"Cannot append to existing skymap - configurations differ:", *compareLog)
167 skyMapConfig.raList.extend(oldSkyMap.config.raList)
168 skyMapConfig.decList.extend(oldSkyMap.config.decList)
169 skyMapConfig.radiusList.extend(oldSkyMap.config.radiusList)
170 skyMapConfig.update(**self.config.skyMap.toDict())
171 skyMapConfig.raList.append(circle.center[0])
172 skyMapConfig.decList.append(circle.center[1])
173 skyMapConfig.radiusList.append(circle.radius + self.config.borderSize)
174 skyMap = DiscreteSkyMap(skyMapConfig)
176 for tractInfo
in skyMap:
177 wcs = tractInfo.getWcs()
178 posBox = afwGeom.Box2D(tractInfo.getBBox())
181 afwGeom.Point2D(posBox.getMaxX(), posBox.getMinY()),
183 afwGeom.Point2D(posBox.getMinX(), posBox.getMaxY()),
185 skyPosList = [wcs.pixelToSky(pos).getPosition(afwGeom.degrees)
for pos
in pixelPosList]
186 posStrList = [
"(%0.3f, %0.3f)" % tuple(skyPos)
for skyPos
in skyPosList]
187 self.log.info(
"tract %s has corners %s (RA, Dec deg) and %s x %s patches" %
188 (tractInfo.getId(),
", ".join(posStrList),
189 tractInfo.getNumPatches()[0], tractInfo.getNumPatches()[1]))
190 if self.config.doWrite:
191 butler.put(skyMap, datasetName)
192 return pipeBase.Struct(
196 def _getConfigName(self):
197 """Return None to disable saving config 199 There's only one SkyMap per repository, so the config is redundant, and checking it means we can't 200 easily overwrite or append to an existing repository. 204 def _getMetadataName(self):
205 """Return None to disable saving metadata 207 The metadata is not interesting, and by not saving it we can eliminate a dataset type. 212 def _makeArgumentParser(cls):
214 parser.add_id_argument(name=
"--id", datasetType=
"calexp", help=
"data ID, e.g. --id visit=123 ccd=1,2")
def __init__(self, kwargs)
def getTargetList(parsedCmd)
def run(self, butler, dataRefList)
Make a skymap from the bounds of the given set of calexps.
Make a DiscreteSkyMap in a repository, using the bounding box of a set of calexps.