LSST Applications  21.0.0-172-gfb10e10a+18fedfabac,22.0.0+297cba6710,22.0.0+80564b0ff1,22.0.0+8d77f4f51a,22.0.0+a28f4c53b1,22.0.0+dcf3732eb2,22.0.1-1-g7d6de66+2a20fdde0d,22.0.1-1-g8e32f31+297cba6710,22.0.1-1-geca5380+7fa3b7d9b6,22.0.1-12-g44dc1dc+2a20fdde0d,22.0.1-15-g6a90155+515f58c32b,22.0.1-16-g9282f48+790f5f2caa,22.0.1-2-g92698f7+dcf3732eb2,22.0.1-2-ga9b0f51+7fa3b7d9b6,22.0.1-2-gd1925c9+bf4f0e694f,22.0.1-24-g1ad7a390+a9625a72a8,22.0.1-25-g5bf6245+3ad8ecd50b,22.0.1-25-gb120d7b+8b5510f75f,22.0.1-27-g97737f7+2a20fdde0d,22.0.1-32-gf62ce7b1+aa4237961e,22.0.1-4-g0b3f228+2a20fdde0d,22.0.1-4-g243d05b+871c1b8305,22.0.1-4-g3a563be+32dcf1063f,22.0.1-4-g44f2e3d+9e4ab0f4fa,22.0.1-42-gca6935d93+ba5e5ca3eb,22.0.1-5-g15c806e+85460ae5f3,22.0.1-5-g58711c4+611d128589,22.0.1-5-g75bb458+99c117b92f,22.0.1-6-g1c63a23+7fa3b7d9b6,22.0.1-6-g50866e6+84ff5a128b,22.0.1-6-g8d3140d+720564cf76,22.0.1-6-gd805d02+cc5644f571,22.0.1-8-ge5750ce+85460ae5f3,master-g6e05de7fdc+babf819c66,master-g99da0e417a+8d77f4f51a,w.2021.48
LSST Data Management Base Package
VeresPlugin.py
Go to the documentation of this file.
1 #
2 # This file is part of meas_extensions_trailedSources.
3 #
4 # Developed for the LSST Data Management System.
5 # This product includes software developed by the LSST Project
6 # (http://www.lsst.org).
7 # See the COPYRIGHT file at the top-level directory of this distribution
8 # for details of code ownership.
9 #
10 # This program is free software: you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # the Free Software Foundation, either version 3 of the License, or
13 # (at your option) any later version.
14 #
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
19 #
20 # You should have received a copy of the GNU General Public License
21 # along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #
23 
24 import numpy as np
25 import scipy.optimize as sciOpt
26 
27 from lsst.pex.config import Field
28 
29 from lsst.meas.base.pluginRegistry import register
30 from lsst.meas.base import SingleFramePlugin, SingleFramePluginConfig
31 from lsst.meas.base import FlagHandler, FlagDefinitionList, SafeCentroidExtractor
32 from lsst.meas.base import MeasurementError
33 
34 from ._trailedSources import VeresModel
35 from .NaivePlugin import SingleFrameNaiveTrailPlugin
36 
37 __all__ = ("SingleFrameVeresTrailConfig", "SingleFrameVeresTrailPlugin")
38 
39 
41  """Config class for SingleFrameVeresTrailPlugin
42  """
43 
44  optimizerMethod = Field(
45  doc="Optimizer method for scipy.optimize.minimize",
46  dtype=str,
47  default="L-BFGS-B"
48  )
49 
50 
51 @register("ext_trailedSources_Veres")
53  """Veres trailed source characterization plugin.
54 
55  Measures the length, angle, flux, centroid, and end points of a trailed
56  source using the Veres et al. 2012 model [1]_.
57 
58  Parameters
59  ----------
60  config: `SingleFrameNaiveTrailConfig`
61  Plugin configuration.
62  name: `str`
63  Plugin name.
64  schema: `lsst.afw.table.Schema`
65  Schema for the output catalog.
66  metadata: `lsst.daf.base.PropertySet`
67  Metadata to be attached to output catalog.
68 
69  Notes
70  -----
71  This plugin is designed to refine the measurements of trail length,
72  angle, and end points from `NaivePlugin`, and of flux and centroid from
73  previous measurement algorithms. Vereš et al. 2012 [1]_ derive a model for
74  the flux in a given image pixel by convolving an axisymmetric Gaussian with
75  a line. The model is parameterized by the total flux, trail length, angle
76  from the x-axis, and the centroid. The best estimates are computed using a
77  chi-squared minimization.
78 
79  References
80  ----------
81  .. [1] Vereš, P., et al. "Improved Asteroid Astrometry and Photometry with
82  Trail Fitting" PASP, vol. 124, 2012.
83 
84  See also
85  --------
86  lsst.meas.base.SingleFramePlugin
87  """
88 
89  ConfigClass = SingleFrameVeresTrailConfig
90 
91  @classmethod
93  # Needs centroids, shape, flux, and NaivePlugin measurements.
94  # Make sure this always runs after NaivePlugin.
95  return SingleFrameNaiveTrailPlugin.getExecutionOrder() + 0.1
96 
97  def __init__(self, config, name, schema, metadata):
98  super().__init__(config, name, schema, metadata)
99 
100  self.keyXCkeyXC = schema.addField(
101  name + "_centroid_x", type="D", doc="Trail centroid X coordinate.", units="pixel")
102  self.keyYCkeyYC = schema.addField(
103  name + "_centroid_y", type="D", doc="Trail centroid Y coordinate.", units="pixel")
104  self.keyX0keyX0 = schema.addField(name + "_x0", type="D", doc="Trail head X coordinate.", units="pixel")
105  self.keyY0keyY0 = schema.addField(name + "_y0", type="D", doc="Trail head Y coordinate.", units="pixel")
106  self.keyX1keyX1 = schema.addField(name + "_x1", type="D", doc="Trail tail X coordinate.", units="pixel")
107  self.keyY1keyY1 = schema.addField(name + "_y1", type="D", doc="Trail tail Y coordinate.", units="pixel")
108  self.keyLkeyL = schema.addField(name + "_length", type="D", doc="Length of trail.", units="pixel")
109  self.keyThetakeyTheta = schema.addField(name + "_angle", type="D", doc="Angle of trail from +x-axis.")
110  self.keyFluxkeyFlux = schema.addField(name + "_flux", type="D", doc="Trailed source flux.", units="count")
111  self.keyRChiSqkeyRChiSq = schema.addField(name + "_rChiSq", type="D", doc="Reduced chi-squared of fit")
112 
113  flagDefs = FlagDefinitionList()
114  flagDefs.addFailureFlag("No trailed-sources measured")
115  self.NON_CONVERGENON_CONVERGE = flagDefs.add("flag_nonConvergence", "Optimizer did not converge")
116  self.NO_NAIVENO_NAIVE = flagDefs.add("flag_noNaive", "Naive measurement contains NaNs")
117  self.flagHandlerflagHandler = FlagHandler.addFields(schema, name, flagDefs)
118 
119  self.centroidExtractorcentroidExtractor = SafeCentroidExtractor(schema, name)
120 
121  def measure(self, measRecord, exposure):
122  """Run the Veres trailed source measurement plugin.
123 
124  Parameters
125  ----------
126  measRecord : `lsst.afw.table.SourceRecord`
127  Record describing the object being measured.
128  exposure : `lsst.afw.image.Exposure`
129  Pixel data to be measured.
130 
131  See also
132  --------
133  lsst.meas.base.SingleFramePlugin.measure
134  """
135  xc, yc = self.centroidExtractorcentroidExtractor(measRecord, self.flagHandlerflagHandler)
136 
137  # Look at measRecord for Naive measurements
138  # ASSUMES NAIVE ALREADY RAN
139  F = measRecord.get("ext_trailedSources_Naive_flux")
140  L = measRecord.get("ext_trailedSources_Naive_length")
141  theta = measRecord.get("ext_trailedSources_Naive_angle")
142  if not np.isfinite(F) or not np.isfinite(L) or not np.isfinite(theta):
143  raise MeasurementError(self.NO_NAIVENO_NAIVE.doc, self.NO_NAIVENO_NAIVE.number)
144 
145  # Make VeresModel
146  model = VeresModel(exposure)
147 
148  # Do optimization with scipy
149  params = np.array([xc, yc, F, L, theta])
150  results = sciOpt.minimize(
151  model, params, method=self.configconfig.optimizerMethod, jac=model.gradient)
152 
153  # Check if optimizer converged
154  if not results.success:
155  raise MeasurementError(self.NON_CONVERGENON_CONVERGE.doc, self.NON_CONVERGENON_CONVERGE.number)
156 
157  # Calculate end points and reduced chi-squared
158  xc_fit, yc_fit, F_fit, L_fit, theta_fit = results.x
159  a = L_fit/2
160  x0_fit = xc_fit - a * np.cos(theta_fit)
161  y0_fit = yc_fit - a * np.sin(theta_fit)
162  x1_fit = xc_fit + a * np.cos(theta_fit)
163  y1_fit = yc_fit + a * np.sin(theta_fit)
164  rChiSq = results.fun / (exposure.image.array.size - 6)
165 
166  # Set keys
167  measRecord.set(self.keyXCkeyXC, xc_fit)
168  measRecord.set(self.keyYCkeyYC, yc_fit)
169  measRecord.set(self.keyX0keyX0, x0_fit)
170  measRecord.set(self.keyY0keyY0, y0_fit)
171  measRecord.set(self.keyX1keyX1, x1_fit)
172  measRecord.set(self.keyY1keyY1, y1_fit)
173  measRecord.set(self.keyFluxkeyFlux, F_fit)
174  measRecord.set(self.keyLkeyL, L_fit)
175  measRecord.set(self.keyThetakeyTheta, theta_fit)
176  measRecord.set(self.keyRChiSqkeyRChiSq, rChiSq)
177 
178  def fail(self, measRecord, error=None):
179  """Record failure
180 
181  See also
182  --------
183  lsst.meas.base.SingleFramePlugin.fail
184  """
185  if error is None:
186  self.flagHandlerflagHandler.handleFailure(measRecord)
187  else:
188  self.flagHandlerflagHandler.handleFailure(measRecord, error.cpp)
vector-type utility class to build a collection of FlagDefinitions
Definition: FlagHandler.h:60
Exception to be thrown when a measurement algorithm experiences a known failure mode.
Definition: exceptions.h:48
Utility class for measurement algorithms that extracts a position from the Centroid slot and handles ...