Coverage for python/lsst/meas/modelfit/display/cModelDisplay.py: 9%
102 statements
« prev ^ index » next coverage.py v6.4.2, created at 2022-07-27 02:29 -0700
« prev ^ index » next coverage.py v6.4.2, created at 2022-07-27 02:29 -0700
1__all__ = ("displayReconstructedCmodel", "displayReconstrucedCmodelMpl",
2 "buildCModelImages", "reconstructCModel")
4import numpy as np
5import matplotlib.pyplot as plt
7import lsst.afw.image as afwImage
8from lsst.geom import Point2D
9import lsst.meas.modelfit as measMod
10import lsst.shapelet as shapelet
13def displayReconstructedCmodel(exposure, record, config, display="mpl"):
14 """ Display an image, the Cmodel, and residuals
16 Parameters
17 ----------
18 exposure : `lsst.afw.image.Exposure`
19 Exposure object that contains the source which was modeled
20 record : `lsst.afw.table.SourceRecord`
21 Record object which contains the measurements made on the source
22 config : `lsst.meas.modelfit.CModel(SingleFrame/Forced)Config`
23 Configuration object of the CModel plugin used in the measurement
24 process
25 display : `str`, optional
26 Display in which to render the data, may be mpl for matplotlib or afw
27 for afwDisplay, defaults to mpl
29 Raises
30 ------
31 `NotImplementedError`
32 If the display backend specified is not implemented
33 """
35 if display == "mpl":
36 displayReconstrucedCmodelMpl(exposure, record, config)
37 elif display == "afw":
38 raise NotImplementedError("The afw display backend is not yet "
39 "implemented")
40 else:
41 raise NotImplementedError("The display backend '{}' is not a supported"
42 "backend".format(display))
45def displayReconstrucedCmodelMpl(exposure, record, config):
46 """ Display an image, the Cmodel, and residuals using matplotlib
48 Parameters
49 ----------
50 exposure : `lsst.afw.image.Exposure`
51 Exposure object that contains the source which was modeled
52 record : `lsst.afw.table.SourceRecord`
53 Record object which contains the measurements made on the source
54 config : `lsst.meas.modelfit.CModel(SingleFrame/Forced)Config`
55 Configuration object of the CModel plugin used in the measurement
56 process
57 """
59 subImage, devIm, expIm, jointIm = buildCModelImages(exposure, record,
60 config)
61 # Get the min and max values for the sub image to use for scaling
62 subImMin = subImage.array.min()
63 subImMax = subImage.array.max()
65 # Calculate the scaling to use for the residual images
66 devResidual = subImage.array-devIm.array
67 expResidual = subImage.array-expIm.array
68 jointResidual = subImage.array-jointIm.array
69 residualList = (devResidual, expResidual, jointResidual)
71 differences = [(x.max()-x.max()) for x in residualList]
72 maxDifferenceIndex = np.argmax(differences)
73 resImMin = residualList[maxDifferenceIndex].min()
74 resImMax = residualList[maxDifferenceIndex].max()
76 # Build the image figure
77 fig, axes = plt.subplots(3, 3, sharex='col', sharey='row', figsize=(8, 5))
78 fig.subplots_adjust(left=0.25, right=0.8)
79 lCBar = fig.add_axes([0.1, 0.15, 0.05, 0.7])
80 rCBar = fig.add_axes([0.85, 0.15, 0.05, 0.7])
82 # Populate just the exposures in the appropriate places
83 for i in range(3):
84 axes[i, 0].imshow(subImage.array, vmin=subImMin, vmax=subImMax)
86 # Populate dev panels
87 axes[0, 1].imshow(devIm.array, vmin=subImMin, vmax=subImMax)
88 axes[0, 2].imshow(devResidual, vmin=resImMin, vmax=resImMax, cmap="BrBG")
90 # Populate exp panels
91 axes[1, 1].imshow(expIm.array, vmin=subImMin, vmax=subImMax)
92 axes[1, 2].imshow(expResidual, vmin=resImMin, vmax=resImMax, cmap="BrBG")
94 # Populate joint panels
95 axes[2, 1].imshow(jointIm.array, vmin=subImMin, vmax=subImMax)
96 axes[2, 2].imshow(jointResidual, vmin=resImMin, vmax=resImMax, cmap="BrBG")
98 axes[0, 0].set_title("Image")
99 axes[0, 1].set_title("Model")
100 axes[0, 2].set_title('Residuals')
102 axes[0, 0].set_ylabel("Dev")
103 axes[1, 0].set_ylabel("Exp")
104 axes[2, 0].set_ylabel("Joint")
106 fig.colorbar(axes[0, 0].get_images()[0], lCBar)
107 lCBar.yaxis.set_ticks_position('left')
108 fig.colorbar(axes[maxDifferenceIndex, 2].get_images()[0], rCBar)
110 plt.show()
113def buildCModelImages(exposure, record, config):
114 """ Create Images out of the CModel for the given record
116 Parameters
117 ----------
118 exposure : `lsst.afw.image.Exposure`
119 Exposure object that contains the source which was modeled
120 record : `lsst.afw.table.SourceRecord`
121 Record object which contains the measurements made on the source
122 config : `lsst.meas.modelfit.CModel(SingleFrame/Forced)Config`
123 Configuration object of the CModel plugin used in the measurement
124 process
126 Returns
127 -------
128 subImage : `lsst.afw.image.ImageD`
129 Sub image of the original data taken from a region defined by the
130 bounding box of the footprint for the object defined in the given
131 source record
132 devIm : `lsst.afw.image.ImageD`
133 Image created from the dev component of the CModel for the supplied
134 record at the same pixel locations as subImage
135 expIm: `lsst.afw.image.ImageD`
136 Image created from the exp component of the CModel for the supplied
137 record at the same pixel locations as subImage
138 jointIm :
139 Image created from the joint fit of the dev and exp components of the
140 CModel for the supplied record at the same pixel locations as subImage
141 """
143 dev, exp, jointDev, jointExp = reconstructCModel(exposure, record, config)
144 # Get exposure cutout
145 footBBox = record.getFootprint().getBBox()
146 subImage = afwImage.ImageD(exposure.getImage().convertD(), footBBox)
148 # Build the psf
149 shapeletPsfKey = shapelet.MultiShapeletFunctionKey(
150 record.schema[config.psfName])
151 psfApprox = record.get(shapeletPsfKey)
153 # Build the dev Image from the shapelet function
154 devIm = afwImage.ImageD(footBBox)
155 dev = dev.convolve(psfApprox)
156 dev.evaluate().addToImage(devIm)
158 # Build the exp image from the shapelet function
159 expIm = afwImage.ImageD(footBBox)
160 exp = exp.convolve(psfApprox)
161 exp.evaluate().addToImage(expIm)
163 # Build the joint image from the shapelet function
164 jointIm = afwImage.ImageD(footBBox)
165 jointDev = jointDev.convolve(psfApprox)
166 jointExp = jointExp.convolve(psfApprox)
167 jointDev.evaluate().addToImage(jointIm)
168 jointExp.evaluate().addToImage(jointIm)
170 return subImage, devIm, expIm, jointIm
173def reconstructCModel(exposure, record, config):
174 """ Reconstruct the CModel for the given record
176 Parameters
177 ----------
178 exposure : `lsst.afw.image.Exposure`
179 Exposure object that contains the source which was modeled
180 record : `lsst.afw.table.SourceRecord`
181 Record object which contains the measurements made on the source
182 config : `lsst.meas.modelfit.CModel(SingleFrame/Forced)Config`
183 Configuration object of the CModel plugin used in the measurement
184 process
186 Returns
187 -------
188 devShapelet : `lsst.shapelet.MultiShapeletFunction`
189 Multi-component shapelet model of the dev component of CModel
190 expShapelet : `lsst.shapelet.MultiShapeletFunction`
191 Multi-component shapelet model fo the exp component of CModel
192 devJointShapelet : `lsst.shapelet.MultiShapeletFunction`
193 Multi-component shapelet model of the dev component of CModel jointly
194 fit with the exp component
195 expJointShapelet : `lsst.shapelet.MultiShapeletFunction`
196 Multi-component shapelet model of the exp component of Cmodel jointly
197 fit with the dev component
198 """
200 # build a unit system transformation object
201 center = record.getCentroid()
202 position = exposure.getWcs().pixelToSky(center)
203 measSys = measMod.UnitSystem(exposure)
204 approxFlux = record.get("base_PsfFlux_instFlux")
205 fitSys = measMod.UnitSystem(position, exposure.getPhotoCalib(), approxFlux)
206 fitSysToMeasSys = measMod.LocalUnitTransform(Point2D(0, 0), fitSys, measSys)
208 # Build the Shapelet objects
209 ctrl = config.makeControl()
210 baseName = "modelfit_CModel"
211 nonlinearKeys = ["{}_{{model}}_nonlinear_{p}".format(baseName, p=p)
212 for p in range(3)]
213 fixedKeys = ["{}_{{model}}_fixed_{p}".format(baseName, p=p)
214 for p in range(2)]
215 fluxKey = "{}_{{model}}_instFlux".format(baseName)
217 # fetch the aperture corrections, if this fails set it to one
218 try:
219 apCorr = record.get("{}_apCorr".format(baseName))
220 except Exception:
221 print("Warning, problem retrieving aperture correction, using a value"
222 " of 1")
223 apCorr = 1
225 # Get parameters for the dev model
226 devNonLinearParams = np.array([record.get(key.format(model="dev"))
227 for key in nonlinearKeys])
228 devFixedParams = np.array([record.get(key.format(model="dev"))
229 for key in fixedKeys])
230 devAmp = np.array([record.get(fluxKey.format(model="dev"))])
231 devAmp /= apCorr
232 devShapelet = ctrl.dev.getModel().makeShapeletFunction(devNonLinearParams,
233 devAmp,
234 devFixedParams)
235 devShapelet.transformInPlace(fitSysToMeasSys.geometric)
237 # Get parameters for the exp model
238 expNonLinearParams = np.array([record.get(key.format(model="exp"))
239 for key in nonlinearKeys])
240 expFixedParams = np.array([record.get(key.format(model="exp"))
241 for key in fixedKeys])
242 expAmp = np.array([record.get(fluxKey.format(model="exp"))])
243 expAmp /= apCorr
244 expShapelet = ctrl.exp.getModel().makeShapeletFunction(expNonLinearParams,
245 expAmp,
246 expFixedParams)
247 expShapelet.transformInPlace(fitSysToMeasSys.geometric)
249 # Get joint shapelet model
250 fracDev = record.get("{}_fracDev".format(baseName))
251 jointFlux = np.array([record.get("{}_instFlux".format(baseName))])
252 jointFlux /= apCorr
253 devJointShapelet = ctrl.dev.getModel()\
254 .makeShapeletFunction(devNonLinearParams, jointFlux*fracDev,
255 devFixedParams)
256 devJointShapelet.transformInPlace(fitSysToMeasSys.geometric)
258 expJointShapelet = ctrl.exp.getModel()\
259 .makeShapeletFunction(expNonLinearParams, jointFlux*(1-fracDev),
260 expFixedParams)
261 expJointShapelet.transformInPlace(fitSysToMeasSys.geometric)
263 return devShapelet, expShapelet, devJointShapelet, expJointShapelet