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