24 from __future__
import absolute_import, division, print_function
28 "GeneralPsfFitterComponentConfig",
29 "GeneralPsfFitterConfig" 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"]
75 def setDefaults(self):
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()
100 if len(self.sequence) < 1:
101 raise ValueError(
"sequence must have at least one element")
102 for m
in self.sequence:
103 if m
not in self.models:
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():
150 "GeneralShapeletPsfApprox requires Exposure to have a Psf")
151 psf = exposure.getPsf()
152 psfImage = psf.computeKernelImage(measRecord.getCentroid())
153 psfShape = psf.computeShape(measRecord.getCentroid())
162 if lastModel
is None:
163 fitter.measure(measRecord, psfImage, psfShape)
165 fitter.measure(measRecord, psfImage,
166 fitter.adapt(lastResult, lastModel))
167 lastResult = measRecord.get(fitter.getKey())
168 lastModel = fitter.getModel()
169 except lsst.meas.base.baseMeasurement.FATAL_EXCEPTIONS:
172 fitter.fail(measRecord, error.cpp)
174 except Exception
as error:
175 fitter.fail(measRecord)
180 if lastError
is not None:
185 def fail(self, measRecord, error=None):
189 class GeneralShapeletPsfApproxSingleFrameConfig(
190 lsst.meas.base.SingleFramePluginConfig,
191 GeneralShapeletPsfApproxConfig
195 lsst.meas.base.SingleFramePluginConfig.setDefaults(self)
196 GeneralShapeletPsfApproxConfig.setDefaults(self)
199 @lsst.meas.base.register(
"modelfit_GeneralShapeletPsfApprox")
201 lsst.meas.base.SingleFramePlugin,
202 GeneralShapeletPsfApproxMixin
204 """Minimal subclass of GeneralShapeletPsfApproxMixin to conform to the 205 single-frame measurement API. 207 This class simply provides __init__ and measure methods that matched the 208 SingleFramePlugin signatures and delegate to the 209 GeneralShapeletPsfApproxMixin's implementations. 211 ConfigClass = GeneralShapeletPsfApproxSingleFrameConfig
217 def __init__(self, config, name, schema, metadata):
218 GeneralShapeletPsfApproxMixin.__init__(self, config, name, schema)
219 lsst.meas.base.SingleFramePlugin.__init__(self, config, name, schema,
223 GeneralShapeletPsfApproxMixin.measure(self, measRecord, exposure)
225 def fail(self, measRecord, error=None):
226 GeneralShapeletPsfApproxMixin.fail(self, measRecord, error)
230 lsst.meas.base.ForcedPluginConfig,
231 GeneralShapeletPsfApproxConfig
235 lsst.meas.base.ForcedPluginConfig.setDefaults(self)
236 GeneralShapeletPsfApproxConfig.setDefaults(self)
239 @lsst.meas.base.register(
"modelfit_GeneralShapeletPsfApprox")
241 lsst.meas.base.ForcedPlugin,
242 GeneralShapeletPsfApproxMixin
244 """Minimal subclass of GeneralShapeletPsfApproxMixin to conform to the 245 forced measurement API. 247 This class simply provides __init__ and measure methods that matched the 248 ForcedPlugin signatures and delegate to the 249 GeneralShapeletPsfApproxMixin's implementations. 251 ConfigClass = GeneralShapeletPsfApproxForcedConfig
257 def __init__(self, config, name, schemaMapper, metadata):
258 GeneralShapeletPsfApproxMixin.__init__(self, config, name,
259 schemaMapper.editOutputSchema())
260 lsst.meas.base.ForcedPlugin.__init__(self, config, name, schemaMapper,
263 def measure(self, measRecord, exposure, refRecord, refWcs):
264 GeneralShapeletPsfApproxMixin.measure(self, measRecord, exposure)
266 def fail(self, measRecord, error=None):
267 GeneralShapeletPsfApproxMixin.fail(self, measRecord, error)
def __init__(self, config, name, schemaMapper, metadata)
def fail(self, measRecord, error=None)
def measure(self, measRecord, exposure)
def __init__(self, config, name, schema, metadata)
def __init__(self, config, name, schema)
def measure(self, measRecord, exposure)
def measure(self, measRecord, exposure, refRecord, refWcs)
def fail(self, measRecord, error=None)
def fail(self, measRecord, error=None)