23 """This is a useful module for debugging measurements.
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
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
41 import lsst.afw.table
as afwTable
43 from lsst.meas.algorithms.measurement
import SourceMeasurementTask
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")
53 """Provide the image and catalog names to the Task
55 We provide a dummy dataRef only to avoid further overrides
60 kwargs[
"image"] = parsedCmd.image
61 kwargs[
"catalog"] = parsedCmd.catalog
62 return [(Struct(dataId=
"<none>"), kwargs)]
66 """A stripped down version of the pipe_base ArgumentParser
68 We don't care about the butler, just the config, and log.
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")
83 def parse_args(self, config, args=None, log=None, override=None):
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
97 _DefaultName =
"debugger"
98 ConfigClass = MeasurementDebuggerConfig
99 RunnerClass = MeasurementDebuggerRunner
102 super(MeasurementDebuggerTask, self).
__init__(**kwargs)
104 schema = afwTable.SourceTable.makeMinimalSchema()
106 self.makeSubtask(
"measurement", schema=schema)
109 def _makeArgumentParser(cls):
112 def run(self, dataRef, image, catalog):
117 self.measurement.measure(exp, sources)
119 return Struct(exp=exp, sources=sources)
122 exp = afwImage.ExposureF(image)
123 self.log.info(
"Read %dx%d image", exp.getWidth(), exp.getHeight())
127 sources = afwTable.SourceCatalog.readFits(catalog)
128 self.log.info(
"Read %d sources", len(sources))
132 catalog = afwTable.SourceCatalog(self.
schema)
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))
142 """Return a subset of the input catalog
144 The full catalog is used if the 'sourceId' list is empty.
146 Parent sources (in the deblending sense) are also added to the
147 subset so that they can be removed (via replaceWithNoise).
149 if not self.config.sourceId:
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)
158 raise RuntimeError(
"Unable to find id=%d in catalog" % ident)
160 parent = ss.getParent()
162 identifiers.add(parent)
163 self.log.info(
"Subset to %d sources", len(subset))
167 sources.writeFits(self.config.outputName)
168 self.log.info(
"Wrote %s", self.config.outputName)