22 from __future__
import absolute_import, division, print_function
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)
94 result = task.run(butler, dataRefList)
97 result = task.run(butler, dataRefList)
98 except Exception
as e:
99 task.log.fatal(
"Failed: %s" % e)
101 if not isinstance(e, pipeBase.TaskError):
102 traceback.print_exc(file=sys.stderr)
103 for dataRef
in dataRefList:
104 task.writeMetadata(dataRef)
106 if self.doReturnResults:
107 return pipeBase.Struct(
108 dataRefList=dataRefList,
109 metadata=task.metadata,
111 exitStatus=exitStatus,
114 return pipeBase.Struct(
115 exitStatus=exitStatus,
120 """!Make a DiscreteSkyMap in a repository, using the bounding box of a set of calexps. 122 The command-line and run signatures and config are sufficiently different from MakeSkyMapTask 123 that we don't inherit from it, but it is a replacement, so we use the same config/metadata names. 125 ConfigClass = MakeDiscreteSkyMapConfig
126 _DefaultName =
"makeDiscreteSkyMap" 127 RunnerClass = MakeDiscreteSkyMapRunner
130 pipeBase.CmdLineTask.__init__(self, **kwargs)
133 def run(self, butler, dataRefList):
134 """!Make a skymap from the bounds of the given set of calexps. 136 @param[in] butler data butler used to save the SkyMap 137 @param[in] dataRefList dataRefs of calexps used to determine the size and pointing of the SkyMap 138 @return a pipeBase Struct containing: 139 - skyMap: the constructed SkyMap 141 self.log.info(
"Extracting bounding boxes of %d images" % len(dataRefList))
143 for dataRef
in dataRefList:
144 if not dataRef.datasetExists(
"calexp"):
145 self.log.warn(
"CalExp for %s does not exist: ignoring" % (dataRef.dataId,))
147 md = dataRef.get(
"calexp_md", immediate=
True)
148 wcs = afwGeom.makeSkyWcs(md)
150 boxI = afwImage.bboxFromMetadata(md)
151 boxD = afwGeom.Box2D(boxI)
152 points.extend(tuple(wcs.pixelToSky(corner).getVector())
for corner
in boxD.getCorners())
154 raise RuntimeError(
"No data found from which to compute convex hull")
155 self.log.info(
"Computing spherical convex hull")
156 polygon = lsst.geom.convexHull(points)
159 "Failed to compute convex hull of the vertices of all calexp bounding boxes; " 160 "they may not be hemispherical." 162 circle = polygon.getBoundingCircle()
164 datasetName = self.config.coaddName +
"Coadd_skyMap" 166 skyMapConfig = DiscreteSkyMap.ConfigClass()
167 if self.config.doAppend
and butler.datasetExists(datasetName):
168 oldSkyMap = butler.get(datasetName, immediate=
True)
169 if not isinstance(oldSkyMap.config, DiscreteSkyMap.ConfigClass):
170 raise TypeError(
"Cannot append to existing non-discrete skymap")
172 if not self.config.skyMap.compare(oldSkyMap.config, output=compareLog.append):
173 raise ValueError(
"Cannot append to existing skymap - configurations differ:", *compareLog)
174 skyMapConfig.raList.extend(oldSkyMap.config.raList)
175 skyMapConfig.decList.extend(oldSkyMap.config.decList)
176 skyMapConfig.radiusList.extend(oldSkyMap.config.radiusList)
177 skyMapConfig.update(**self.config.skyMap.toDict())
178 skyMapConfig.raList.append(circle.center[0])
179 skyMapConfig.decList.append(circle.center[1])
180 skyMapConfig.radiusList.append(circle.radius + self.config.borderSize)
181 skyMap = DiscreteSkyMap(skyMapConfig)
183 for tractInfo
in skyMap:
184 wcs = tractInfo.getWcs()
185 posBox = afwGeom.Box2D(tractInfo.getBBox())
188 afwGeom.Point2D(posBox.getMaxX(), posBox.getMinY()),
190 afwGeom.Point2D(posBox.getMinX(), posBox.getMaxY()),
192 skyPosList = [wcs.pixelToSky(pos).getPosition(afwGeom.degrees)
for pos
in pixelPosList]
193 posStrList = [
"(%0.3f, %0.3f)" % tuple(skyPos)
for skyPos
in skyPosList]
194 self.log.info(
"tract %s has corners %s (RA, Dec deg) and %s x %s patches" %
195 (tractInfo.getId(),
", ".join(posStrList),
196 tractInfo.getNumPatches()[0], tractInfo.getNumPatches()[1]))
197 if self.config.doWrite:
198 butler.put(skyMap, datasetName)
199 return pipeBase.Struct(
203 def _getConfigName(self):
204 """Return None to disable saving config 206 There's only one SkyMap per repository, so the config is redundant, and checking it means we can't 207 easily overwrite or append to an existing repository. 211 def _getMetadataName(self):
212 """Return None to disable saving metadata 214 The metadata is not interesting, and by not saving it we can eliminate a dataset type. 219 def _makeArgumentParser(cls):
221 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.