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")