LSSTApplications  16.0-10-g0ee56ad+5,16.0-11-ga33d1f2+5,16.0-12-g3ef5c14+3,16.0-12-g71e5ef5+18,16.0-12-gbdf3636+3,16.0-13-g118c103+3,16.0-13-g8f68b0a+3,16.0-15-gbf5c1cb+4,16.0-16-gfd17674+3,16.0-17-g7c01f5c+3,16.0-18-g0a50484+1,16.0-20-ga20f992+8,16.0-21-g0e05fd4+6,16.0-21-g15e2d33+4,16.0-22-g62d8060+4,16.0-22-g847a80f+4,16.0-25-gf00d9b8+1,16.0-28-g3990c221+4,16.0-3-gf928089+3,16.0-32-g88a4f23+5,16.0-34-gd7987ad+3,16.0-37-gc7333cb+2,16.0-4-g10fc685+2,16.0-4-g18f3627+26,16.0-4-g5f3a788+26,16.0-5-gaf5c3d7+4,16.0-5-gcc1f4bb+1,16.0-6-g3b92700+4,16.0-6-g4412fcd+3,16.0-6-g7235603+4,16.0-69-g2562ce1b+2,16.0-8-g14ebd58+4,16.0-8-g2df868b+1,16.0-8-g4cec79c+6,16.0-8-gadf6c7a+1,16.0-8-gfc7ad86,16.0-82-g59ec2a54a+1,16.0-9-g5400cdc+2,16.0-9-ge6233d7+5,master-g2880f2d8cf+3,v17.0.rc1
LSSTDataManagementBasePackage
debugger.py
Go to the documentation of this file.
1 #
2 # LSST Data Management System
3 #
4 # Copyright 2008-2017 AURA/LSST.
5 #
6 # This product includes software developed by the
7 # LSST Project (http://www.lsst.org/).
8 #
9 # This program is free software: you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation, either version 3 of the License, or
12 # (at your option) any later version.
13 #
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
18 #
19 # You should have received a copy of the LSST License Statement and
20 # the GNU General Public License along with this program. If not,
21 # see <https://www.lsstcorp.org/LegalNotices/>.
22 #
23 """This is a useful module for debugging measurements.
24 
25 It relies on the presence of a catalog already produced by running
26 measurements in the regular context. You provide the image and
27 catalog on the command-line, a list of source identifiers and the
28 measurement configuration in the config; the module reads the inputs,
29 subsets the catalog to contain only the sources of interest, and measures
30 those. This reduces the frustration of waiting for image processing
31 and the measurements to run on many other sources, greatly increasing
32 debugging efficiency.
33 """
34 
35 import sys
36 from argparse import ArgumentParser, Namespace
37 from lsst.log import Log
38 from lsst.pex.config import Config, ConfigurableField, Field, ListField
39 from lsst.pipe.base import CmdLineTask, ConfigValueAction, ConfigFileAction, TaskRunner, Struct
40 import lsst.afw.image as afwImage
41 import lsst.afw.table as afwTable
42 
43 from lsst.meas.algorithms.measurement import SourceMeasurementTask
44 
45 
47  sourceId = ListField(dtype=int, default=[], doc="List of source identifiers to measure")
48  outputName = Field(dtype=str, default="catalog.fits", doc="Output name for source catalog")
49  measurement = ConfigurableField(target=SourceMeasurementTask, doc="Measurements")
50 
51 
53  """Provide the image and catalog names to the Task
54 
55  We provide a dummy dataRef only to avoid further overrides
56  of this class.
57  """
58  @staticmethod
59  def getTargetList(parsedCmd, **kwargs):
60  kwargs["image"] = parsedCmd.image
61  kwargs["catalog"] = parsedCmd.catalog
62  return [(Struct(dataId="<none>"), kwargs)]
63 
64 
65 class MeasurementDebuggerArgumentParser(ArgumentParser):
66  """A stripped down version of the pipe_base ArgumentParser
67 
68  We don't care about the butler, just the config, and log.
69  """
70 
71  def __init__(self, *args, **kwargs):
72  super(MeasurementDebuggerArgumentParser, self).__init__(*args, **kwargs)
73  self.add_argument("image", help="Name of image to measure")
74  self.add_argument("catalog", help="Name of catalog to measure")
75  self.add_argument("-c", "--config", nargs="*", action=ConfigValueAction,
76  help="config override(s), e.g. -c foo=newfoo bar.baz=3", metavar="NAME=VALUE")
77  self.add_argument("-C", "--configfile", dest="configfile", nargs="*", action=ConfigFileAction,
78  help="config override file(s)")
79  self.add_argument("--doraise", action="store_true",
80  help="raise an exception on error (else log a message and continue)?")
81  self.add_argument("--logdest", help="logging destination")
82 
83  def parse_args(self, config, args=None, log=None, override=None):
84  if args is None:
85  args = sys.argv[1:]
86  namespace = Namespace()
87  namespace.config = config
88  namespace.clobberConfig = False
89  namespace.butler = None
90  namespace.log = log if log is not None else Log.getDefaultLogger()
91  namespace = super(MeasurementDebuggerArgumentParser, self).parse_args(args=args, namespace=namespace)
92  del namespace.configfile
93  return namespace
94 
95 
97  _DefaultName = "debugger"
98  ConfigClass = MeasurementDebuggerConfig
99  RunnerClass = MeasurementDebuggerRunner
100 
101  def __init__(self, schema=None, **kwargs):
102  super(MeasurementDebuggerTask, self).__init__(**kwargs)
103  if schema is None:
104  schema = afwTable.SourceTable.makeMinimalSchema()
105  self.schema = schema
106  self.makeSubtask("measurement", schema=schema)
107 
108  @classmethod
109  def _makeArgumentParser(cls):
111 
112  def runDataRef(self, dataRef, image, catalog):
113  exp = self.readImage(image)
114  sources = self.readSources(catalog)
115  sources = self.subsetSources(sources)
116  sources = self.mapSchemas(sources)
117  self.measurement.measure(exp, sources)
118  self.writeSources(sources)
119  return Struct(exp=exp, sources=sources)
120 
121  def readImage(self, image):
122  exp = afwImage.ExposureF(image)
123  self.log.info("Read %dx%d image", exp.getWidth(), exp.getHeight())
124  return exp
125 
126  def readSources(self, catalog):
127  sources = afwTable.SourceCatalog.readFits(catalog)
128  self.log.info("Read %d sources", len(sources))
129  return sources
130 
131  def mapSchemas(self, sources):
132  catalog = afwTable.SourceCatalog(self.schema)
133  for ss in sources:
134  new = catalog.addNew()
135  new.setFootprint(ss.getFootprint())
136  for name in self.schema.getNames():
137  if name in ss.schema:
138  new.set(name, ss.get(name))
139  return catalog
140 
141  def subsetSources(self, sources):
142  """Return a subset of the input catalog
143 
144  The full catalog is used if the 'sourceId' list is empty.
145 
146  Parent sources (in the deblending sense) are also added to the
147  subset so that they can be removed (via replaceWithNoise).
148  """
149  if not self.config.sourceId:
150  return sources
151 
152  identifiers = set(self.config.sourceId)
153  subset = afwTable.SourceCatalog(sources.table)
154  while len(identifiers) > 0:
155  ident = identifiers.pop()
156  ss = sources.find(ident)
157  if ss is None:
158  raise RuntimeError("Unable to find id=%d in catalog" % ident)
159  subset.append(ss)
160  parent = ss.getParent()
161  if parent:
162  identifiers.add(parent)
163  self.log.info("Subset to %d sources", len(subset))
164  return subset
165 
166  def writeSources(self, sources):
167  sources.writeFits(self.config.outputName)
168  self.log.info("Wrote %s", self.config.outputName)
169 
170  def writeConfig(self, *args, **kwargs):
171  pass
172 
173  def writeMetadata(self, *args, **kwargs):
174  pass
175 
176  def writeSchemas(self, *args, **kwargs):
177  pass
def parse_args(self, config, args=None, log=None, override=None)
Definition: debugger.py:83
def makeSubtask(self, name, keyArgs)
Definition: task.py:275
daf::base::PropertySet * set
Definition: fits.cc:832
Definition: Log.h:691
def runDataRef(self, dataRef, image, catalog)
Definition: debugger.py:112
def measure(mi, x, y, size, statistic, stats)
Definition: fringe.py:357