lsst.meas.modelfit  15.0-3-g150fc43+8
interactive.py
Go to the documentation of this file.
1 from past.builtins import basestring
2 from builtins import object
3 #
4 # LSST Data Management System
5 # Copyright 2008-2013 LSST Corporation.
6 #
7 # This product includes software developed by the
8 # LSST Project (http://www.lsst.org/).
9 #
10 # This program is free software: you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # the Free Software Foundation, either version 3 of the License, or
13 # (at your option) any later version.
14 #
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
19 #
20 # You should have received a copy of the LSST License Statement and
21 # the GNU General Public License along with this program. If not,
22 # see <http://www.lsstcorp.org/LegalNotices/>.
23 #
24 
25 import numpy
26 
27 import lsst.pipe.base
28 import lsst.pex.config
30 import lsst.afw.image
33 
34 from ..measureCcd import MeasureCcdTask
35 from ..measureCoadd import MeasureCoaddTask
36 from ..measureMulti import MeasureMultiTask
37 from .. import modelfitLib
38 
39 from .densityPlot import CrossPointsLayer, DensityPlot, HistogramLayer, SurfaceLayer
40 from .modelFitAdapters import OptimizerDataAdapter, OptimizerTrackLayer, SamplingDataAdapter
41 from .optimizerDisplay import OptimizerDisplay
42 
43 __all__ = ("Interactive", )
44 
45 
46 class Interactive(object):
47  """Interactive analysis helper class
48 
49  This class manages a butler, calexp, modelfits catalog, and an instance
50  of a Measure*Task, allowing individual objects to be re-fit and plotted.
51  """
52 
53  def __init__(self, root, tag=None, config=None, dataId=None, mode="ccd"):
54  """Construct an interactive analysis object.
55 
56  @param[in] rerun Output directory, relative to $S13_DATA_DIR/output.
57  measureCcd.py (or measureCoadd.py if mode='coadd') must
58  have been run (possibly with prepOnly=True) previously
59  with this output directory.
60  @param[in] tag Tag associated with the run; see BaseMeasureConfig.tag.
61  If None, config must not be (and config.tag will be used).
62  @param[in] config ConfigClass instance; if None, it will be loaded from disk.
63  @param[in] dataId Butler data ID of the image to analyze.
64  @param[in] mode One of "ccd", "coadd", or "multi", indicating whether
65  to use MeasureCcdTask, MeasureCoaddTask, or MeasureMultiTask.
66  """
67  self.mode = mode.lower()
68  self.butler = lsst.daf.persistence.Butler(root)
69  TaskClass = None
70  configName = None
71  if self.mode == "ccd":
72  if dataId is None:
73  dataId = dict(visit=100, raft="2,2", sensor="1,1")
74  self.dataRef = self.butler.dataRef("calexp", dataId=dataId)
75  configName = "measureCcd_config"
76  TaskClass = MeasureCcdTask
77  elif self.mode == "coadd":
78  if dataId is None:
79  dataId = dict(tract=0, patch="2,2", filter="i")
80  self.dataRef = self.butler.dataRef("deepCoadd_calexp", dataId=dataId)
81  configName = "deep_measureCoadd_config"
82  TaskClass = MeasureCoaddTask
83  elif self.mode.startswith("multi"):
84  if dataId is None:
85  dataId = dict(tract=0, patch="2,2", filter="i")
86  self.dataRef = self.butler.dataRef("deepCoadd_calexp", dataId=dataId)
87  configName = "deep_measureMulti_config"
88  TaskClass = MeasureMultiTask
89  if config is None:
90  config = self.butler.get(configName, tag=tag, immediate=True)
91  config.previous = tag
92  if tag is None:
93  if config is None:
94  raise ValueError("tag and config arguments cannot both be None")
95  tag = config.tag
96  else:
97  config.tag = "intermediate"
98  self.task = TaskClass(config=config, butler=self.butler)
99  self.inputs = self.task.readInputs(self.dataRef)
100 
101  def fit(self, outRecord):
102  """Re-fit the object indicated by the given record sequential index or source ID,
103  returning the record.
104  """
105  likelihood = self.task.makeLikelihood(self.inputs, outRecord)
106  self.task.fitter.run(likelihood, outRecord)
107  return outRecord
108 
109  def plotDistribution(self, *records):
110  """Plot a representation of the posterior distribution from a ModelFitRecord.
111  """
112  import matplotlib
113  recordId = records[0].getId()
114  figure = matplotlib.pyplot.figure(recordId, figsize=(10, 10))
115  data = {}
116  layers = {}
117  for record in records:
118  assert record.getId() == recordId
119  if modelfitLib.MarginalSamplingInterpreter.cast(record.getInterpreter()):
120  data["marginal"] = SamplingDataAdapter(record)
121  layers["marginal.samples"] = HistogramLayer("direct")
122  layers["marginal.proposal"] = SurfaceLayer("direct")
123  elif modelfitLib.DirectSamplingInterpreter.cast(record.getInterpreter()):
124  data["direct"] = SamplingDataAdapter(record)
125  layers["direct.samples"] = HistogramLayer("direct")
126  layers["direct.proposal"] = SurfaceLayer("direct")
127  elif modelfitLib.OptimizerInterpreter.cast(record.getInterpreter()):
128  data["optimizer"] = OptimizerDataAdapter(record)
129  layers["optimizer.track"] = OptimizerTrackLayer("optimizer")
130  layers["optimizer.pdf"] = SurfaceLayer("optimizer",
131  kwds1d=dict(color='g'),
132  kwds2d=dict(cmap=matplotlib.cm.Greens))
133  layers["optimizer.points"] = CrossPointsLayer("optimizer")
134  else:
135  raise ValueError("Unknown or missing interpreter")
136  p = DensityPlot(figure, **data)
137  p.layers.update(layers)
138  p.draw()
139  return p
140 
141  def displayOptimizer(self, record, **kwds):
142  likelihood = self.task.makeLikelihood(self.inputs, record)
143  objective = modelfitLib.OptimizerObjective.makeFromLikelihood(likelihood, self.task.prior)
144  return OptimizerDisplay(record.getSamples(), self.task.model, objective)
145 
146  def displayResiduals(self, record, nonlinear="fit", amplitudes="fit", doApplyWeights=False):
147  """Display the data postage stamp along with the model image and residuals in ds9.
148 
149  @param[in] record ModelFitRecord defining the object to display
150  @param[in] nonlinear Vector of nonlinear parameters, or a string prefix (see below)
151  @param[in] amplitudes Vector of linear parameters, or a string prefix (see below)
152  @param[in] doApplyWeights Whether to show the weighted images used directly in the fit
153  or the original unweighted data.
154 
155  String prefixes are used to extract the parameters from the record. Usually the following
156  are available:
157  fit ------- use record.get("fit.*"); the best-fit parameters
158  initial --- use record.get("initial.*"); the initial parameters
159  """
160  likelihood = self.task.makeLikelihood(self.inputs, record)
161 
162  if isinstance(nonlinear, basestring):
163  nonlinear = record.get(nonlinear + ".nonlinear")
164  else:
165  assert nonlinear.shape == (likelihood.getNonlinearDim(),)
166 
167  matrix = numpy.zeros((likelihood.getAmplitudeDim(), likelihood.getDataDim()),
168  dtype=modelfitLib.Pixel).transpose()
169  likelihood.computeModelMatrix(matrix, nonlinear, doApplyWeights)
170 
171  if isinstance(amplitudes, basestring):
172  amplitudes = record.get(amplitudes + ".amplitudes")
173  else:
174  assert amplitudes.shape == (likelihood.getAmplitudeDim(),)
175 
176  bbox = record.getFootprint().getBBox()
177  bbox.grow(2)
178  flatModel = numpy.zeros(likelihood.getDataDim(), dtype=modelfitLib.Pixel)
179  flatModel[:] = numpy.dot(matrix, amplitudes)
180 
181  imgData = lsst.afw.image.MaskedImageF(self.inputs.exposure.getMaskedImage(), bbox,
182  lsst.afw.image.PARENT, True)
183  bitmask = imgData.getMask().addMaskPlane("FIT_REGION")
184  regionMask = lsst.afw.image.MaskU(bbox)
185  lsst.afw.detection.setMaskFromFootprint(regionMask, record.getFootprint(), bitmask)
186  dataMask = imgData.getMask()
187  dataMask |= regionMask
188  if doApplyWeights:
189  imgData.getImage().set(0.0)
190  imgData.getVariance().set(0.0)
191  flatData = likelihood.getData()
192  lsst.afw.detection.expandArray(record.getFootprint(), flatData, imgData.getImage().getArray(),
193  imgData.getXY0())
194  imgModel = lsst.afw.image.MaskedImageF(lsst.afw.image.ImageF(bbox), regionMask)
195  lsst.afw.detection.expandArray(record.getFootprint(), flatModel, imgModel.getImage().getArray(),
196  imgModel.getXY0())
197  imgResiduals = lsst.afw.image.MaskedImageF(imgData, True)
198  imgResiduals -= imgModel
200  mosaic.setMode("x")
201  mosaic.append(imgData, "data")
202  mosaic.append(imgModel, "model")
203  mosaic.append(imgResiduals, "data-model")
204  grid = mosaic.makeMosaic()
def setMaskTransparency(name, frame=None)
def __init__(self, root, tag=None, config=None, dataId=None, mode="ccd")
Definition: interactive.py:53
def mtv(data, frame=None, title="", wcs=None, args, kwargs)
def displayResiduals(self, record, nonlinear="fit", amplitudes="fit", doApplyWeights=False)
Definition: interactive.py:146