24 from __future__
import absolute_import, division, print_function
28 "GeneralPsfFitterComponentConfig",
29 "GeneralPsfFitterConfig"
32 import lsst.pex.config
35 GeneralPsfFitterControl, GeneralPsfFitterComponentControl,
36 GeneralPsfFitter, GeneralPsfFitterAlgorithm,
37 DoubleShapeletPsfApproxAlgorithm, DoubleShapeletPsfApproxControl
41 lsst.meas.base.wrapSimpleAlgorithm(
42 DoubleShapeletPsfApproxAlgorithm,
43 Control=DoubleShapeletPsfApproxControl,
44 module=
'lsst.meas.modelfit',
45 name=
'modelfit_DoubleShapeletPsfApprox',
46 executionOrder=lsst.meas.base.BasePlugin.SHAPE_ORDER
50 GeneralPsfFitterComponentConfig = lsst.pex.config.makeConfigClass(
51 GeneralPsfFitterComponentControl,
52 module=
'lsst.meas.modelfit'
54 GeneralPsfFitterConfig = lsst.pex.config.makeConfigClass(
55 GeneralPsfFitterControl,
56 module=
'lsst.meas.modelfit'
58 GeneralPsfFitter.ConfigClass = GeneralPsfFitterConfig
62 models = lsst.pex.config.ConfigDictField(
64 itemtype=GeneralPsfFitterConfig,
65 doc=
"a dictionary of models that can be used to fit the PSF",
68 sequence = lsst.pex.config.ListField(
70 doc=(
"a sequence of model names indicating which models should be fit,"
72 default=[
"DoubleShapelet"]
76 super(GeneralShapeletPsfApproxConfig, self).
setDefaults()
78 self.
models[
"SingleGaussian"].inner.order = -1
79 self.
models[
"SingleGaussian"].primary.order = 0
80 self.
models[
"SingleGaussian"].wings.order = -1
81 self.
models[
"SingleGaussian"].outer.order = -1
83 self.
models[
"DoubleGaussian"].inner.order = -1
84 self.
models[
"DoubleGaussian"].primary.order = 0
85 self.
models[
"DoubleGaussian"].wings.order = 0
86 self.
models[
"DoubleGaussian"].outer.order = -1
88 self.
models[
"DoubleShapelet"].inner.order = -1
89 self.
models[
"DoubleShapelet"].primary.order = 2
90 self.
models[
"DoubleShapelet"].wings.order = 1
91 self.
models[
"DoubleShapelet"].outer.order = -1
93 self.
models[
"Full"].inner.order = 0
94 self.
models[
"Full"].primary.order = 4
95 self.
models[
"Full"].wings.order = 4
96 self.
models[
"Full"].outer.order = 0
99 super(GeneralShapeletPsfApproxConfig, self).
validate()
101 raise ValueError(
"sequence must have at least one element")
105 "All elements in sequence must be keys in models dict"
110 """Mixin base class for fitting shapelet approximations to the PSF model
112 This class does almost all of the work for its two derived classes,
113 GeneralShapeletPsfApproxSingleFramePlugin and
114 GeneralShapeletPsfApproxForcedPlugin, which simply adapt it to the
115 slightly different interfaces for single-frame and forced measurement. It
116 in turn delegates its work to the C++ GeneralPsfFitter class; it holds
117 sequence of these corresponding to different models (generally with
118 increasing complexity). Each GeneralPsfFitter starts with the result of
119 the previous one as an input, using GeneralPsfFitter::adapt to hopefully
120 allow these previous fits to reduce the time spent on the next one.
122 At present, this plugin does not define any failure flags, which will
123 almost certainly have to be changed in the future. So far, however, I
124 haven't actually seen it fail on any PSFs I've given it, so I'll wait
125 until we can run on large enough data volumes to see what the actual
126 failure modes are, instead of trying to guess them in advance.
130 """Initialize the plugin, creating a sequence of GeneralPsfFitter
131 instances to do the fitting and MultiShapeletFunctionKey instances to
132 save the results to a record.
135 for m
in config.sequence:
137 config.models[m].makeControl(),
139 schema[name][m].getPrefix()
141 self.sequence.append((fitter, schema[name][m].getPrefix()))
144 """Fit the configured sequence of models the given Exposure's Psf, as
145 evaluated at measRecord.getCentroid(), then save the results to
148 if not exposure.hasPsf():
149 raise lsst.meas.base.FatalAlgorithmError(
150 "GeneralShapeletPsfApprox requires Exposure to have a Psf")
151 psf = exposure.getPsf()
152 psfImage = psf.computeKernelImage(measRecord.getCentroid())
153 psfShape = psf.computeShape(measRecord.getCentroid())
161 if lastModel
is None:
162 fitter.measure(measRecord, psfImage, psfShape)
164 fitter.measure(measRecord, psfImage,
165 fitter.adapt(lastResult, lastModel))
166 lastResult = measRecord.get(fitter.getKey())
167 lastModel = fitter.getModel()
168 except lsst.meas.base.baseMeasurement.FATAL_EXCEPTIONS:
170 except lsst.meas.base.MeasurementError
as error:
171 fitter.fail(measRecord, error.cpp)
173 except Exception
as error:
174 fitter.fail(measRecord)
179 if not lastError
is None:
184 def fail(self, measRecord, error=None):
188 class GeneralShapeletPsfApproxSingleFrameConfig(
189 lsst.meas.base.SingleFramePluginConfig,
190 GeneralShapeletPsfApproxConfig
194 lsst.meas.base.SingleFramePluginConfig.setDefaults(self)
195 GeneralShapeletPsfApproxConfig.setDefaults(self)
198 @lsst.meas.base.register(
"modelfit_GeneralShapeletPsfApprox")
200 lsst.meas.base.SingleFramePlugin,
201 GeneralShapeletPsfApproxMixin
203 """Minimal subclass of GeneralShapeletPsfApproxMixin to conform to the
204 single-frame measurement API.
206 This class simply provides __init__ and measure methods that matched the
207 SingleFramePlugin signatures and delegate to the
208 GeneralShapeletPsfApproxMixin's implementations.
210 ConfigClass = GeneralShapeletPsfApproxSingleFrameConfig
216 def __init__(self, config, name, schema, metadata):
217 GeneralShapeletPsfApproxMixin.__init__(self, config, name, schema)
218 lsst.meas.base.SingleFramePlugin.__init__(self, config, name, schema,
222 GeneralShapeletPsfApproxMixin.measure(self, measRecord, exposure)
224 def fail(self, measRecord, error=None):
225 GeneralShapeletPsfApproxMixin.fail(self, measRecord, error)
229 lsst.meas.base.ForcedPluginConfig,
230 GeneralShapeletPsfApproxConfig
234 lsst.meas.base.ForcedPluginConfig.setDefaults(self)
235 GeneralShapeletPsfApproxConfig.setDefaults(self)
238 @lsst.meas.base.register(
"modelfit_GeneralShapeletPsfApprox")
240 lsst.meas.base.ForcedPlugin,
241 GeneralShapeletPsfApproxMixin
243 """Minimal subclass of GeneralShapeletPsfApproxMixin to conform to the
244 forced measurement API.
246 This class simply provides __init__ and measure methods that matched the
247 ForcedPlugin signatures and delegate to the
248 GeneralShapeletPsfApproxMixin's implementations.
250 ConfigClass = GeneralShapeletPsfApproxForcedConfig
256 def __init__(self, config, name, schemaMapper, metadata):
257 GeneralShapeletPsfApproxMixin.__init__(self, config, name,
258 schemaMapper.editOutputSchema())
259 lsst.meas.base.ForcedPlugin.__init__(self, config, name, schemaMapper,
262 def measure(self, measRecord, exposure, refRecord, refWcs):
263 GeneralShapeletPsfApproxMixin.measure(self, measRecord, exposure)
265 def fail(self, measRecord, error=None):
266 GeneralShapeletPsfApproxMixin.fail(self, measRecord, error)
tuple GeneralPsfFitterConfig