32from ..measureCcd
import MeasureCcdTask
33from ..measureCoadd
import MeasureCoaddTask
34from ..measureMulti
import MeasureMultiTask
35from ..
import modelfitLib
37from .densityPlot
import CrossPointsLayer, DensityPlot, HistogramLayer, SurfaceLayer
38from .modelFitAdapters
import OptimizerDataAdapter, OptimizerTrackLayer, SamplingDataAdapter
39from .optimizerDisplay
import OptimizerDisplay
41__all__ = (
"Interactive", )
45 """Interactive analysis helper class
47 This class manages
a butler, calexp, modelfits catalog, and an instance
48 of a Measure*Task, allowing individual objects to be re-fit
and plotted.
51 def __init__(self, root, tag=None, config=None, dataId=None, mode="ccd"):
52 """Construct an interactive analysis object.
54 @param[
in] rerun Output directory, relative to $S13_DATA_DIR/output.
55 measureCcd.py (
or measureCoadd.py
if mode=
'coadd') must
56 have been run (possibly
with prepOnly=
True) previously
57 with this output directory.
58 @param[
in] tag Tag associated
with the run; see BaseMeasureConfig.tag.
59 If
None, config must
not be (
and config.tag will be used).
60 @param[
in] config ConfigClass instance;
if None, it will be loaded
from disk.
61 @param[
in] dataId Butler data ID of the image to analyze.
62 @param[
in] mode One of
"ccd",
"coadd",
or "multi", indicating whether
63 to use MeasureCcdTask, MeasureCoaddTask,
or MeasureMultiTask.
65 self.modemode = mode.lower()
69 if self.
modemode ==
"ccd":
71 dataId = dict(visit=100, raft=
"2,2", sensor=
"1,1")
73 configName =
"measureCcd_config"
74 TaskClass = MeasureCcdTask
75 elif self.
modemode ==
"coadd":
77 dataId = dict(tract=0, patch=
"2,2", filter=
"i")
79 configName =
"deep_measureCoadd_config"
80 TaskClass = MeasureCoaddTask
81 elif self.
modemode.startswith(
"multi"):
83 dataId = dict(tract=0, patch=
"2,2", filter=
"i")
85 configName =
"deep_measureMulti_config"
86 TaskClass = MeasureMultiTask
88 config = self.
butlerbutler.get(configName, tag=tag, immediate=
True)
92 raise ValueError(
"tag and config arguments cannot both be None")
95 config.tag =
"intermediate"
96 self.
tasktask = TaskClass(config=config, butler=self.
butlerbutler)
99 def fit(self, outRecord):
100 """Re-fit the object indicated by the given record sequential index or source ID,
101 returning the record.
103 likelihood = self.tasktask.makeLikelihood(self.inputsinputs, outRecord)
104 self.tasktask.fitter.run(likelihood, outRecord)
108 """Plot a representation of the posterior distribution from a ModelFitRecord.
111 recordId = records[0].getId()
112 figure = matplotlib.pyplot.figure(recordId, figsize=(10, 10))
115 for record
in records:
116 assert record.getId() == recordId
117 if modelfitLib.MarginalSamplingInterpreter.cast(record.getInterpreter()):
121 elif modelfitLib.DirectSamplingInterpreter.cast(record.getInterpreter()):
125 elif modelfitLib.OptimizerInterpreter.cast(record.getInterpreter()):
129 kwds1d=dict(color=
'g'),
130 kwds2d=dict(cmap=matplotlib.cm.Greens))
133 raise ValueError(
"Unknown or missing interpreter")
135 p.layers.update(layers)
140 likelihood = self.
tasktask.makeLikelihood(self.
inputsinputs, record)
141 objective = modelfitLib.OptimizerObjective.makeFromLikelihood(likelihood, self.
tasktask.prior)
144 def displayResiduals(self, record, nonlinear="fit", amplitudes="fit", doApplyWeights=False):
145 """Display the data postage stamp along with the model image and residuals in ds9.
147 @param[
in] record ModelFitRecord defining the object to display
148 @param[
in] nonlinear Vector of nonlinear parameters,
or a string prefix (see below)
149 @param[
in] amplitudes Vector of linear parameters,
or a string prefix (see below)
150 @param[
in] doApplyWeights Whether to show the weighted images used directly
in the fit
151 or the original unweighted data.
153 String prefixes are used to extract the parameters
from the record. Usually the following
155 fit ------- use record.get(
"fit.*"); the best-fit parameters
156 initial --- use record.get(
"initial.*"); the initial parameters
158 likelihood = self.tasktask.makeLikelihood(self.inputsinputs, record)
160 if isinstance(nonlinear, str):
161 nonlinear = record.get(nonlinear +
".nonlinear")
163 assert nonlinear.shape == (likelihood.getNonlinearDim(),)
165 matrix = numpy.zeros((likelihood.getAmplitudeDim(), likelihood.getDataDim()),
166 dtype=modelfitLib.Pixel).transpose()
167 likelihood.computeModelMatrix(matrix, nonlinear, doApplyWeights)
169 if isinstance(amplitudes, str):
170 amplitudes = record.get(amplitudes +
".amplitudes")
172 assert amplitudes.shape == (likelihood.getAmplitudeDim(),)
174 bbox = record.getFootprint().getBBox()
176 flatModel = numpy.zeros(likelihood.getDataDim(), dtype=modelfitLib.Pixel)
177 flatModel[:] = numpy.dot(matrix, amplitudes)
179 imgData = lsst.afw.image.MaskedImageF(self.
inputsinputs.exposure.getMaskedImage(), bbox,
180 lsst.afw.image.PARENT,
True)
181 bitmask = imgData.getMask().addMaskPlane(
"FIT_REGION")
182 regionMask = lsst.afw.image.MaskU(bbox)
183 lsst.afw.detection.setMaskFromFootprint(regionMask, record.getFootprint(), bitmask)
184 dataMask = imgData.getMask()
185 dataMask |= regionMask
187 imgData.getImage().
set(0.0)
188 imgData.getVariance().
set(0.0)
189 flatData = likelihood.getData()
190 lsst.afw.detection.expandArray(record.getFootprint(), flatData, imgData.getImage().getArray(),
192 imgModel = lsst.afw.image.MaskedImageF(lsst.afw.image.ImageF(bbox), regionMask)
193 lsst.afw.detection.expandArray(record.getFootprint(), flatModel, imgModel.getImage().getArray(),
195 imgResiduals = lsst.afw.image.MaskedImageF(imgData,
True)
196 imgResiduals -= imgModel
199 mosaic.append(imgData,
"data")
200 mosaic.append(imgModel,
"model")
201 mosaic.append(imgResiduals,
"data-model")
202 grid = mosaic.makeMosaic()
def displayOptimizer(self, record, **kwds)
def displayResiduals(self, record, nonlinear="fit", amplitudes="fit", doApplyWeights=False)
def plotDistribution(self, *records)
def __init__(self, root, tag=None, config=None, dataId=None, mode="ccd")
daf::base::PropertySet * set
def setMaskTransparency(name, frame=None)
def mtv(data, frame=None, title="", wcs=None, *args, **kwargs)
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.