26 "GeneralPsfFitterComponentConfig",
27 "GeneralPsfFitterConfig"
30 import lsst.pex.config
33 GeneralPsfFitterControl, GeneralPsfFitterComponentControl,
34 GeneralPsfFitter, GeneralPsfFitterAlgorithm,
35 DoubleShapeletPsfApproxAlgorithm, DoubleShapeletPsfApproxControl
39 lsst.meas.base.wrapSimpleAlgorithm(
40 DoubleShapeletPsfApproxAlgorithm,
41 Control=DoubleShapeletPsfApproxControl,
42 module=
'lsst.meas.modelfit',
43 name=
'modelfit_DoubleShapeletPsfApprox',
44 executionOrder=lsst.meas.base.BasePlugin.SHAPE_ORDER
48 GeneralPsfFitterComponentConfig = lsst.pex.config.makeConfigClass(
49 GeneralPsfFitterComponentControl,
50 module=
'lsst.meas.modelfit'
52 GeneralPsfFitterConfig = lsst.pex.config.makeConfigClass(
53 GeneralPsfFitterControl,
54 module=
'lsst.meas.modelfit'
56 GeneralPsfFitter.ConfigClass = GeneralPsfFitterConfig
60 models = lsst.pex.config.ConfigDictField(
62 itemtype=GeneralPsfFitterConfig,
63 doc=
"a dictionary of models that can be used to fit the PSF",
66 sequence = lsst.pex.config.ListField(
68 doc=(
"a sequence of model names indicating which models should be fit,"
70 default=[
"DoubleShapelet"]
74 super(GeneralShapeletPsfApproxConfig, self).
setDefaults()
76 self.models[
"SingleGaussian"].inner.order = -1
77 self.models[
"SingleGaussian"].primary.order = 0
78 self.models[
"SingleGaussian"].wings.order = -1
79 self.models[
"SingleGaussian"].outer.order = -1
81 self.models[
"DoubleGaussian"].inner.order = -1
82 self.models[
"DoubleGaussian"].primary.order = 0
83 self.models[
"DoubleGaussian"].wings.order = 0
84 self.models[
"DoubleGaussian"].outer.order = -1
86 self.models[
"DoubleShapelet"].inner.order = -1
87 self.models[
"DoubleShapelet"].primary.order = 2
88 self.models[
"DoubleShapelet"].wings.order = 1
89 self.models[
"DoubleShapelet"].outer.order = -1
91 self.models[
"Full"].inner.order = 0
92 self.models[
"Full"].primary.order = 4
93 self.models[
"Full"].wings.order = 4
94 self.models[
"Full"].outer.order = 0
97 super(GeneralShapeletPsfApproxConfig, self).
validate()
98 if len(self.sequence) < 1:
99 raise ValueError(
"sequence must have at least one element")
100 for m
in self.sequence:
101 if m
not in self.models:
103 "All elements in sequence must be keys in models dict"
108 """Mixin base class for fitting shapelet approximations to the PSF model
110 This class does almost all of the work for its two derived classes,
111 GeneralShapeletPsfApproxSingleFramePlugin and
112 GeneralShapeletPsfApproxForcedPlugin, which simply adapt it to the
113 slightly different interfaces for single-frame and forced measurement. It
114 in turn delegates its work to the C++ GeneralPsfFitter class; it holds
115 sequence of these corresponding to different models (generally with
116 increasing complexity). Each GeneralPsfFitter starts with the result of
117 the previous one as an input, using GeneralPsfFitter::adapt to hopefully
118 allow these previous fits to reduce the time spent on the next one.
120 At present, this plugin does not define any failure flags, which will
121 almost certainly have to be changed in the future. So far, however, I
122 haven't actually seen it fail on any PSFs I've given it, so I'll wait
123 until we can run on large enough data volumes to see what the actual
124 failure modes are, instead of trying to guess them in advance.
128 """Initialize the plugin, creating a sequence of GeneralPsfFitter
129 instances to do the fitting and MultiShapeletFunctionKey instances to
130 save the results to a record.
133 for m
in config.sequence:
134 fitter = GeneralPsfFitterAlgorithm(
137 schema[name][m].getPrefix()
142 """Fit the configured sequence of models the given Exposure's Psf, as
143 evaluated at measRecord.getCentroid(), then save the results to
146 if not exposure.hasPsf():
148 "GeneralShapeletPsfApprox requires Exposure to have a Psf")
149 psf = exposure.getPsf()
150 psfImage = psf.computeKernelImage(measRecord.getCentroid())
151 psfShape = psf.computeShape(measRecord.getCentroid())
160 if lastModel
is None:
161 fitter.measure(measRecord, psfImage, psfShape)
163 fitter.measure(measRecord, psfImage,
164 fitter.adapt(lastResult, lastModel))
165 lastResult = measRecord.get(fitter.getKey())
166 lastModel = fitter.getModel()
167 except lsst.meas.base.baseMeasurement.FATAL_EXCEPTIONS:
170 fitter.fail(measRecord, error.cpp)
172 except Exception
as error:
173 fitter.fail(measRecord)
178 if lastError
is not None:
183 def fail(self, measRecord, error=None):
187 class GeneralShapeletPsfApproxSingleFrameConfig(
189 GeneralShapeletPsfApproxConfig
193 lsst.meas.base.SingleFramePluginConfig.setDefaults(self)
194 GeneralShapeletPsfApproxConfig.setDefaults(self)
197 @lsst.meas.base.register(
"modelfit_GeneralShapeletPsfApprox")
200 GeneralShapeletPsfApproxMixin
202 """Minimal subclass of GeneralShapeletPsfApproxMixin to conform to the
203 single-frame measurement API.
205 This class simply provides __init__ and measure methods that matched the
206 SingleFramePlugin signatures and delegate to the
207 GeneralShapeletPsfApproxMixin's implementations.
209 ConfigClass = GeneralShapeletPsfApproxSingleFrameConfig
215 def __init__(self, config, name, schema, metadata):
216 GeneralShapeletPsfApproxMixin.__init__(self, config, name, schema)
217 lsst.meas.base.SingleFramePlugin.__init__(self, config, name, schema,
221 GeneralShapeletPsfApproxMixin.measure(self, measRecord, exposure)
223 def fail(self, measRecord, error=None):
224 GeneralShapeletPsfApproxMixin.fail(self, measRecord, error)
229 GeneralShapeletPsfApproxConfig
233 lsst.meas.base.ForcedPluginConfig.setDefaults(self)
234 GeneralShapeletPsfApproxConfig.setDefaults(self)
237 @lsst.meas.base.register(
"modelfit_GeneralShapeletPsfApprox")
240 GeneralShapeletPsfApproxMixin
242 """Minimal subclass of GeneralShapeletPsfApproxMixin to conform to the
243 forced measurement API.
245 This class simply provides __init__ and measure methods that matched the
246 ForcedPlugin signatures and delegate to the
247 GeneralShapeletPsfApproxMixin's implementations.
249 ConfigClass = GeneralShapeletPsfApproxForcedConfig
255 def __init__(self, config, name, schemaMapper, metadata):
256 GeneralShapeletPsfApproxMixin.__init__(self, config, name,
257 schemaMapper.editOutputSchema())
258 lsst.meas.base.ForcedPlugin.__init__(self, config, name, schemaMapper,
261 def measure(self, measRecord, exposure, refRecord, refWcs):
262 GeneralShapeletPsfApproxMixin.measure(self, measRecord, exposure)
264 def fail(self, measRecord, error=None):
265 GeneralShapeletPsfApproxMixin.fail(self, measRecord, error)