24 from lsst.pex.config 
import Config, Field, DictField
 
   32     """!Configuration for propagating flags to coadd""" 
   33     flags = DictField(keytype=str, itemtype=float,
 
   34                       default={
"calib_psf_candidate": 0.2, 
"calib_psf_used": 0.2, 
"calib_psf_reserved": 0.2,
 
   35                                "calib_astrometry_used": 0.2, 
"calib_photometry_used": 0.2,
 
   36                                "calib_photometry_reserved": 0.2, },
 
   37                       doc=(
"Source catalog flags to propagate, with the threshold of relative occurrence " 
   38                            "(valid range: [0-1], default is 0.2).  Coadd object will have flag set if the " 
   39                            "fraction of input visits in which it is flagged is greater than the threshold."))
 
   40     matchRadius = Field(dtype=float, default=0.2, doc=
"Source matching radius (arcsec)")
 
   41     ccdName = Field(dtype=str, default=
'ccd', doc=
"Name of ccd to give to butler")
 
   52     r"""!Task to propagate flags from single-frame measurements to coadd measurements 
   54 \anchor PropagateVisitFlagsTask_ 
   56 \brief Propagate flags from individual visit measurements to coadd measurements 
   58 \section pipe_tasks_propagateVisitFlagsTask_Contents Contents 
   60  - \ref pipe_tasks_propagateVisitFlagsTask_Description 
   61  - \ref pipe_tasks_propagateVisitFlagsTask_Initialization 
   62  - \ref pipe_tasks_propagateVisitFlagsTask_Config 
   63  - \ref pipe_tasks_propagateVisitFlagsTask_Use 
   64  - \ref pipe_tasks_propagateVisitFlagsTask_Example 
   66 \section pipe_tasks_propagateVisitFlagsTask_Description Description 
   68 \copybrief PropagateVisitFlagsTask 
   70 We want to be able to set a flag for sources on the coadds using flags 
   71 that were determined from the individual visits.  A common example is sources 
   72 that were used for PSF determination, since we do not do any PSF determination 
   73 on the coadd but use the individual visits.  This requires matching the coadd 
   74 source catalog to each of the catalogs from the inputs (see 
   75 PropagateVisitFlagsConfig.matchRadius), and thresholding on the number of 
   76 times a source is flagged on the input catalog. 
   78 An important consideration in this is that the flagging of sources in the 
   79 individual visits can be somewhat stochastic, e.g., the same stars may not 
   80 always be used for PSF determination because the field of view moves slightly 
   81 between visits, or the seeing changed.  We there threshold on the relative 
   82 occurrence of the flag in the visits (see PropagateVisitFlagsConfig.flags). 
   83 Flagging a source that is always flagged in inputs corresponds to a threshold 
   84 of 1, while flagging a source that is flagged in any of the input corresponds 
   85 to a threshold of 0.  But neither of these extrema are really useful in 
   88 Setting the threshold too high means that sources that are not consistently 
   89 flagged (e.g., due to chip gaps) will not have the flag propagated.  Setting 
   90 that threshold too low means that random sources which are falsely flagged in 
   91 the inputs will start to dominate.  If in doubt, we suggest making this 
   92 threshold relatively low, but not zero (e.g., 0.1 to 0.2 or so).  The more 
   93 confidence in the quality of the flagging, the lower the threshold can be. 
   95 The relative occurrence accounts for the edge of the field-of-view of the 
   96 camera, but does not include chip gaps, bad or saturated pixels, etc. 
   98 \section pipe_tasks_propagateVisitFlagsTask_Initialization Initialization 
  100 Beyond the usual Task initialization, PropagateVisitFlagsTask also requires 
  101 a schema for the catalog that is being constructed. 
  103 \section pipe_tasks_propagateVisitFlagsTask_Config Configuration parameters 
  105 See \ref PropagateVisitFlagsConfig 
  107 \section pipe_tasks_propagateVisitFlagsTask_Use Use 
  109 The 'run' method (described below) is the entry-point for operations.  The 
  110 'getCcdInputs' staticmethod is provided as a convenience for retrieving the 
  111 'ccdInputs' (CCD inputs table) from an Exposure. 
  115 \section pipe_tasks_propagateVisitFlagsTask_Example Example 
  119 # * butler: data butler, for retrieving the CCD catalogs 
  120 # * coaddCatalog: catalog of source measurements on the coadd (lsst.afw.table.SourceCatalog) 
  121 # * coaddExposure: coadd (lsst.afw.image.Exposure) 
  122 from lsst.pipe.tasks.propagateVisitFlags import PropagateVisitFlagsTask, PropagateVisitFlagsConfig 
  123 config = PropagateVisitFlagsConfig() 
  124 config.flags["calib_psf_used"] = 0.3 # Relative threshold for this flag 
  125 config.matchRadius = 0.5 # Matching radius in arcsec 
  126 task = PropagateVisitFlagsTask(coaddCatalog.schema, config=config) 
  127 ccdInputs = task.getCcdInputs(coaddExposure) 
  128 task.run(butler, coaddCatalog, ccdInputs, coaddExposure.getWcs()) 
  131     ConfigClass = PropagateVisitFlagsConfig
 
  134         Task.__init__(self, **kwargs)
 
  136         self.
_keys = dict((f, self.
schema.addField(f, type=
"Flag", doc=
"Propagated from visits")) 
for 
  141         """!Convenience method to retrieve the CCD inputs table from a coadd exposure""" 
  142         return coaddExposure.getInfo().getCoaddInputs().ccds
 
  144     def run(self, butler, coaddSources, ccdInputs, coaddWcs, visitCatalogs=None, wcsUpdates=None):
 
  145         """!Propagate flags from individual visit measurements to coadd 
  147         This requires matching the coadd source catalog to each of the catalogs 
  148         from the inputs, and thresholding on the number of times a source is 
  149         flagged on the input catalog.  The threshold is made on the relative 
  150         occurrence of the flag in each source.  Flagging a source that is always 
  151         flagged in inputs corresponds to a threshold of 1, while flagging a 
  152         source that is flagged in any of the input corresponds to a threshold of 
  153         0.  But neither of these extrema are really useful in practise. 
  155         Setting the threshold too high means that sources that are not consistently 
  156         flagged (e.g., due to chip gaps) will not have the flag propagated.  Setting 
  157         that threshold too low means that random sources which are falsely flagged in 
  158         the inputs will start to dominate.  If in doubt, we suggest making this threshold 
  159         relatively low, but not zero (e.g., 0.1 to 0.2 or so).  The more confidence in 
  160         the quality of the flagging, the lower the threshold can be. 
  162         The relative occurrence accounts for the edge of the field-of-view of 
  163         the camera, but does not include chip gaps, bad or saturated pixels, etc. 
  165         @param[in] butler  Data butler, for retrieving the input source catalogs 
  166         @param[in,out] coaddSources  Source catalog from the coadd 
  167         @param[in] ccdInputs  Table of CCDs that contribute to the coadd 
  168         @param[in] coaddWcs  Wcs for coadd 
  169         @param[in] visitCatalogs List of loaded source catalogs for each input ccd in 
  170                                  the coadd. If provided this is used instead of this 
  171                                  method loading in the catalogs itself 
  172         @param[in] wcsUpdates optional, If visitCatalogs is a list of ccd catalogs, this 
  173                               should be a list of updated wcs to apply 
  175         if len(self.
config.flags) == 0:
 
  179         counts = dict((f, numpy.zeros(len(coaddSources), dtype=int)) 
for f 
in flags)
 
  180         indices = numpy.array([s.getId() 
for s 
in coaddSources])  
 
  181         radius = self.
config.matchRadius*geom.arcseconds
 
  183         def processCcd(ccdSources, wcsUpdate):
 
  184             for sourceRecord 
in ccdSources:
 
  185                 sourceRecord.updateCoord(wcsUpdate)
 
  192                 mc.findOnlyClosest = 
False 
  195                     index = (numpy.where(indices == m.first.getId()))[0][0]
 
  196                     counts[flag][index] += 1
 
  198         if visitCatalogs 
is not None:
 
  199             if wcsUpdates 
is None:
 
  200                 raise pexExceptions.ValueError(
"If ccdInputs is a list of src catalogs, a list of wcs" 
  201                                                " updates for each catalog must be supplied in the " 
  202                                                "wcsUpdates parameter")
 
  203             for i, ccdSource 
in enumerate(visitCatalogs):
 
  204                 processCcd(ccdSource, wcsUpdates[i])
 
  206             if ccdInputs 
is None:
 
  207                 raise pexExceptions.ValueError(
"The visitCatalogs and ccdInput parameters can't both be None")
 
  208             visitKey = ccdInputs.schema.find(
"visit").key
 
  209             ccdKey = ccdInputs.schema.find(
"ccd").key
 
  211             self.
log.
info(
"Propagating flags %s from inputs" % (flags,))
 
  214             for ccdRecord 
in ccdInputs:
 
  215                 v = ccdRecord.get(visitKey)
 
  216                 c = ccdRecord.get(ccdKey)
 
  217                 dataId = {
"visit": int(v), self.
config.ccdName: int(c)}
 
  218                 ccdSources = butler.get(
"src", dataId=dataId, immediate=
True)
 
  219                 processCcd(ccdSources, ccdRecord.getWcs())
 
  224             for s, num 
in zip(coaddSources, counts[f]):
 
  225                 numOverlaps = len(ccdInputs.subsetContaining(s.getCentroid(), coaddWcs, 
True))
 
  226                 s.setFlag(key, bool(num > numOverlaps*self.
config.flags[f]))
 
  227             self.
log.
info(
"Propagated %d sources with flag %s" % (sum(s.get(key) 
for s 
in coaddSources), f))