29 import lsst.pex.config
as pexConfig
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.runDataRef(butler, dataRefList)
97 result = task.runDataRef(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)
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)
152 points.extend(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")
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())
179 skyMapConfig.raList.append(circleCenter[0].asDegrees())
180 skyMapConfig.decList.append(circleCenter[1].asDegrees())
181 circleRadiusDeg = circle.getOpeningAngle().asDegrees()
182 skyMapConfig.radiusList.append(circleRadiusDeg + self.config.borderSize)
185 for tractInfo
in skyMap:
186 wcs = tractInfo.getWcs()
194 skyPosList = [wcs.pixelToSky(pos).getPosition(geom.degrees)
for pos
in pixelPosList]
195 posStrList = [
"(%0.3f, %0.3f)" % tuple(skyPos)
for skyPos
in skyPosList]
196 self.log.
info(
"tract %s has corners %s (RA, Dec deg) and %s x %s patches" %
197 (tractInfo.getId(),
", ".join(posStrList),
198 tractInfo.getNumPatches()[0], tractInfo.getNumPatches()[1]))
199 if self.config.doWrite:
200 butler.put(skyMap, datasetName)
201 return pipeBase.Struct(
205 def _getConfigName(self):
206 """Return None to disable saving config
208 There's only one SkyMap per repository, so the config is redundant, and checking it means we can't
209 easily overwrite or append to an existing repository.
213 def _getMetadataName(self):
214 """Return None to disable saving metadata
216 The metadata is not interesting, and by not saving it we can eliminate a dataset type.
221 def _makeArgumentParser(cls):
223 parser.add_id_argument(name=
"--id", datasetType=
"calexp", help=
"data ID, e.g. --id visit=123 ccd=1,2")