90 def __init__(self, config, name, schema, metadata, logName=None):
93 super().
__init__(config, name, schema, metadata, logName=logName)
96 self.
keyRa = schema.addField(name +
"_ra", type=
"D", doc=
"Trail centroid right ascension.")
97 self.
keyDec = schema.addField(name +
"_dec", type=
"D", doc=
"Trail centroid declination.")
98 self.
keyX0 = schema.addField(name +
"_x0", type=
"D", doc=
"Trail head X coordinate.", units=
"pixel")
99 self.
keyY0 = schema.addField(name +
"_y0", type=
"D", doc=
"Trail head Y coordinate.", units=
"pixel")
100 self.
keyX1 = schema.addField(name +
"_x1", type=
"D", doc=
"Trail tail X coordinate.", units=
"pixel")
101 self.
keyY1 = schema.addField(name +
"_y1", type=
"D", doc=
"Trail tail Y coordinate.", units=
"pixel")
102 self.
keyFlux = schema.addField(name +
"_flux", type=
"D", doc=
"Trailed source flux.", units=
"count")
103 self.
keyLength = schema.addField(name +
"_length", type=
"D", doc=
"Trail length.", units=
"pixel")
104 self.
keyAngle = schema.addField(name +
"_angle", type=
"D", doc=
"Angle measured from +x-axis.")
107 self.
keyX0Err = schema.addField(name +
"_x0Err", type=
"D",
108 doc=
"Trail head X coordinate error.", units=
"pixel")
109 self.
keyY0Err = schema.addField(name +
"_y0Err", type=
"D",
110 doc=
"Trail head Y coordinate error.", units=
"pixel")
111 self.
keyX1Err = schema.addField(name +
"_x1Err", type=
"D",
112 doc=
"Trail tail X coordinate error.", units=
"pixel")
113 self.
keyY1Err = schema.addField(name +
"_y1Err", type=
"D",
114 doc=
"Trail tail Y coordinate error.", units=
"pixel")
115 self.
keyFluxErr = schema.addField(name +
"_fluxErr", type=
"D",
116 doc=
"Trail flux error.", units=
"count")
118 doc=
"Trail length error.", units=
"pixel")
119 self.
keyAngleErr = schema.addField(name +
"_angleErr", type=
"D", doc=
"Trail angle error.")
122 self.
FAILURE = flagDefs.addFailureFlag(
"No trailed-source measured")
123 self.
NO_FLUX = flagDefs.add(
"flag_noFlux",
"No suitable prior flux measurement")
124 self.
NO_CONVERGE = flagDefs.add(
"flag_noConverge",
"The root finder did not converge")
125 self.
NO_SIGMA = flagDefs.add(
"flag_noSigma",
"No PSF width (sigma)")
126 self.
SAFE_CENTROID = flagDefs.add(
"flag_safeCentroid",
"Fell back to safe centroid extractor")
130 self.
log = logging.getLogger(self.logName)
133 """Run the Naive trailed source measurement algorithm.
137 measRecord : `lsst.afw.table.SourceRecord`
138 Record describing the object being measured.
139 exposure : `lsst.afw.image.Exposure`
140 Pixel data to be measured.
144 lsst.meas.base.SingleFramePlugin.measure
149 xc = measRecord.get(
"base_SdssShape_x")
150 yc = measRecord.get(
"base_SdssShape_y")
151 if not np.isfinite(xc)
or not np.isfinite(yc):
152 xc, yc = self.centroidExtractor(measRecord, self.
flagHandler)
160 Ixx, Iyy, Ixy = measRecord.getShape().getParameterVector()
165 a2 = 0.5 * (xpy + sqrt(xmy2 + 4.0*xy2))
166 b2 = 0.5 * (xpy - sqrt(xmy2 + 4.0*xy2))
170 if measRecord.get(
"base_SdssShape_flag_unweighted"):
171 self.
log.debug(
"Unweighted")
174 self.
log.debug(
"Weighted")
175 length, gradLength, results = self.
findLength(a2, b2)
176 if not results.converged:
177 self.
log.info(
"Results not converged: %s", results.flag)
183 theta = 0.5 * np.arctan2(2.0 * Ixy, xmy)
187 dydtheta = radius*np.cos(theta)
188 dxdtheta = radius*np.sin(theta)
195 cutout = getMeasurementCutout(measRecord, exposure)
198 params = np.array([xc, yc, 1.0, length, theta])
199 model = VeresModel(cutout)
200 flux, gradFlux = model.computeFluxWithGradient(params)
203 if not np.isfinite(flux):
204 if np.isfinite(measRecord.getApInstFlux()):
205 flux = measRecord.getApInstFlux()
212 IxxErr2, IyyErr2, IxyErr2 = np.diag(measRecord.getShapeErr())
216 xcErr2, ycErr2 = np.diag(measRecord.getCentroidErr())
219 desc = sqrt(xmy2 + 4.0*xy2)
220 da2dIxx = 0.5*(1.0 + (xmy/desc))
221 da2dIyy = 0.5*(1.0 - (xmy/desc))
222 da2dIxy = 2.0*Ixy / desc
223 a2Err2 = IxxErr2*da2dIxx*da2dIxx + IyyErr2*da2dIyy*da2dIyy + IxyErr2*da2dIxy*da2dIxy
224 b2Err2 = IxxErr2*da2dIyy*da2dIyy + IyyErr2*da2dIxx*da2dIxx + IxyErr2*da2dIxy*da2dIxy
225 dLda2, dLdb2 = gradLength
226 lengthErr = np.sqrt(dLda2*dLda2*a2Err2 + dLdb2*dLdb2*b2Err2)
229 dThetadIxx = -Ixy / (xmy2 + 4.0*xy2)
230 dThetadIxy = xmy / (xmy2 + 4.0*xy2)
231 thetaErr = sqrt(dThetadIxx*dThetadIxx*(IxxErr2 + IyyErr2) + dThetadIxy*dThetadIxy*IxyErr2)
234 dFdxc, dFdyc, _, dFdL, dFdTheta = gradFlux
235 fluxErr = sqrt(dFdL*dFdL*lengthErr*lengthErr + dFdTheta*dFdTheta*thetaErr*thetaErr
236 + dFdxc*dFdxc*xcErr2 + dFdyc*dFdyc*ycErr2)
239 dxdradius = np.cos(theta)
240 dydradius = np.sin(theta)
241 radiusErr2 = lengthErr*lengthErr/4.0
242 xErr2 = sqrt(xcErr2 + radiusErr2*dxdradius*dxdradius + thetaErr*thetaErr*dxdtheta*dxdtheta)
243 yErr2 = sqrt(ycErr2 + radiusErr2*dydradius*dydradius + thetaErr*thetaErr*dydtheta*dydtheta)
248 measRecord.set(self.
keyRa, ra)
249 measRecord.set(self.
keyDec, dec)
250 measRecord.set(self.
keyX0, x0)
251 measRecord.set(self.
keyY0, y0)
252 measRecord.set(self.
keyX1, x1)
253 measRecord.set(self.
keyY1, y1)
254 measRecord.set(self.
keyFlux, flux)
256 measRecord.set(self.
keyAngle, theta)
257 measRecord.set(self.
keyX0Err, x0Err)
258 measRecord.set(self.
keyY0Err, y0Err)
259 measRecord.set(self.
keyX1Err, x0Err)
260 measRecord.set(self.
keyY1Err, y0Err)