def measure(self, measRecord, exposure): """Run the Veres trailed source measurement plugin. Parameters ---------- measRecord : `lsst.afw.table.SourceRecord` Record describing the object being measured. exposure : `lsst.afw.image.Exposure` Pixel data to be measured. See also -------- lsst.meas.base.SingleFramePlugin.measure """ xc, yc = self.centroidExtractor(measRecord, self.flagHandler) # Look at measRecord for Naive measurements # ASSUMES NAIVE ALREADY RAN F = measRecord.get("ext_trailedSources_Naive_flux") L = measRecord.get("ext_trailedSources_Naive_length") theta = measRecord.get("ext_trailedSources_Naive_angle") if np.isnan(F) or np.isnan(L) or np.isnan(theta): raise MeasurementError(self.NO_NAIVE.doc, self.NO_NAIVE.number) # Make VeresModel model = VeresModel(exposure) # Do optimization with scipy params = np.array([xc, yc, F, L, theta]) results = minimize(model, params, method=self.config.optimizerMethod, jac=model.gradient) # Check if optimizer converged if not results.success: raise MeasurementError(self.NON_CONVERGE.doc, self.NON_CONVERGE.number) # Calculate end points and reduced chi-squared xc_fit, yc_fit, F_fit, L_fit, theta_fit = results.x a = L_fit / 2 x0_fit = xc_fit - a * np.cos(theta_fit) y0_fit = yc_fit - a * np.sin(theta_fit) x1_fit = xc_fit + a * np.cos(theta_fit) y1_fit = yc_fit + a * np.sin(theta_fit) rChiSq = results.fun / (exposure.image.array.size - 6) # Set keys measRecord.set(self.keyXC, xc_fit) measRecord.set(self.keyYC, yc_fit) measRecord.set(self.keyX0, x0_fit) measRecord.set(self.keyY0, y0_fit) measRecord.set(self.keyX1, x1_fit) measRecord.set(self.keyY1, y1_fit) measRecord.set(self.keyFlux, F_fit) measRecord.set(self.keyL, L_fit) measRecord.set(self.keyTheta, theta_fit) measRecord.set(self.keyRChiSq, rChiSq)
def testFlagHandler(self): """ Standalone test to create a flaghandler and call it This is not a real world example, just a simple unit test """ schema = lsst.afw.table.SourceTable.makeMinimalSchema() # This is a FlagDefinition structure like a plugin might have flagDefs = FlagDefinitionList() FAILURE = flagDefs.addFailureFlag() FIRST = flagDefs.add("1st error", "this is the first failure type") SECOND = flagDefs.add("2nd error", "this is the second failure type") fh = FlagHandler.addFields(schema, "test", flagDefs) # Check to be sure that the FlagHandler was correctly initialized for index in range(len(flagDefs)): self.assertEqual( flagDefs.getDefinition(index).name, fh.getFlagName(index)) catalog = lsst.afw.table.SourceCatalog(schema) # Now check to be sure that all of the known failures set the bits correctly record = catalog.addNew() fh.handleFailure(record) self.assertTrue(fh.getValue(record, FAILURE.number)) self.assertFalse(fh.getValue(record, FIRST.number)) self.assertFalse(fh.getValue(record, SECOND.number)) record = catalog.addNew() error = MeasurementError(FAILURE.doc, FAILURE.number) fh.handleFailure(record, error.cpp) self.assertTrue(fh.getValue(record, FAILURE.number)) self.assertFalse(fh.getValue(record, FIRST.number)) self.assertFalse(fh.getValue(record, SECOND.number)) record = catalog.addNew() error = MeasurementError(FIRST.doc, FIRST.number) fh.handleFailure(record, error.cpp) self.assertTrue(fh.getValue(record, FAILURE.number)) self.assertTrue(fh.getValue(record, FIRST.number)) self.assertFalse(fh.getValue(record, SECOND.number)) record = catalog.addNew() error = MeasurementError(SECOND.doc, SECOND.number) fh.handleFailure(record, error.cpp) self.assertTrue(fh.getValue(record, FAILURE.number)) self.assertFalse(fh.getValue(record, FIRST.number)) self.assertTrue(fh.getValue(record, SECOND.number))
def measure(self, measRecord, exposure): """Perform measurement. The measure method is called by the measurement framework when `run` is called. If a `MeasurementError` is raised during this method, the `fail` method will be called to set the error flags. """ # Call the SafeCentroidExtractor to get a centroid, even if one has # not been supplied by the centroid slot. Normally, the centroid is # supplied by the centroid slot, but if that fails, the footprint is # used as a fallback. If the fallback is needed, the fail flag will # be set on this record. center = self.centroidExtractor(measRecord, self.flagHandler) # create a square bounding box of size = config.size around the center centerPoint = lsst.geom.Point2I(int(center.getX()), int(center.getY())) bbox = lsst.geom.Box2I(centerPoint, lsst.geom.Extent2I(1, 1)) bbox.grow(self.config.size) # If the measurement box falls outside the exposure, raise the edge # MeasurementError if not exposure.getBBox().contains(bbox): raise MeasurementError(self.EDGE.doc, self.EDGE.number) # Sum the pixels inside the bounding box instFlux = lsst.afw.image.ImageF(exposure.getMaskedImage().getImage(), bbox).getArray().sum() measRecord.set(self.instFluxKey, instFlux) # If there was a NaN inside the bounding box, the instFlux will still # be NaN if np.isnan(instFlux): raise MeasurementError(self.CONTAINS_NAN.doc, self.CONTAINS_NAN.number) if self.config.flux0 is not None: if self.config.flux0 == 0: raise ZeroDivisionError("self.config.flux0 is zero in divisor") mag = -2.5 * np.log10(instFlux / self.config.flux0) measRecord.set(self.magKey, mag)
def measure(self, measRecord, exposure): """ The measure method is called by the measurement framework when task.run is called If a MeasurementError is raised during this method, the fail() method will be called to set the error flags. """ lsst.log.Log.getLogger(self.getLogName()).info("%s plugin measuring." % (self.name, )) # Sum the pixels inside the bounding box centerPoint = lsst.afw.geom.Point2I(int(measRecord.getX()), int(measRecord.getY())) bbox = lsst.afw.geom.Box2I(centerPoint, lsst.afw.geom.Extent2I(1, 1)) flux = lsst.afw.image.ImageF(exposure.getMaskedImage().getImage(), bbox).getArray().sum() measRecord.set(self.fluxKey, flux) # If there was a nan inside the bounding box, the flux will still be nan if numpy.isnan(flux): raise MeasurementError(self.CONTAINS_NAN.doc, self.CONTAINS_NAN.number)
def measure(self, measRecord, exposure): """Perform measurement. Notes ----- The `measure` method is called by the measurement framework when `run` is called. If a `MeasurementError` is raised during this method, the `fail` method will be called to set the error flags. """ logging.getLogger(self.getLogName()).info("%s plugin measuring.", self.name) # Sum the pixels inside the bounding box centerPoint = lsst.geom.Point2I(int(measRecord.getX()), int(measRecord.getY())) bbox = lsst.geom.Box2I(centerPoint, lsst.geom.Extent2I(1, 1)) instFlux = lsst.afw.image.ImageF(exposure.getMaskedImage().getImage(), bbox).getArray().sum() measRecord.set(self.instFluxKey, instFlux) # If there was a NaN inside the bounding box, the instFlux will still # be NaN if numpy.isnan(instFlux): raise MeasurementError(self.CONTAINS_NAN.doc, self.CONTAINS_NAN.number)
def calculate(self, measRecord): # note: flagbit doesn't matter, since a FlagHandler isn't used raise MeasurementError("Supposed to fail", 0)
def measure(self, measRecord, exposure): """Run the Naive trailed source measurement algorithm. Parameters ---------- measRecord : `lsst.afw.table.SourceRecord` Record describing the object being measured. exposure : `lsst.afw.image.Exposure` Pixel data to be measured. See also -------- lsst.meas.base.SingleFramePlugin.measure """ xc, yc = self.centriodExtractor(measRecord, self.flagHandler) Ixx, Iyy, Ixy = measRecord.getShape().getParameterVector() xmy = Ixx - Iyy xpy = Ixx + Iyy xmy2 = xmy * xmy xy2 = Ixy * Ixy a = np.sqrt(0.5 * (xpy + np.sqrt((xmy)**2 + 4.0 * xy2))) L = 2 * a theta = 0.5 * np.arctan2(2.0 * Ixy, xmy) x0 = xc - a * np.cos(theta) y0 = yc - a * np.sin(theta) x1 = xc + a * np.cos(theta) y1 = yc + a * np.sin(theta) # For now, use the shape flux. F = measRecord.get("base_SdssShape_instFlux") # Fall back to aperture flux if np.isnan(F): if not np.isnan(measRecord.getInstApFlux()): F = measRecord.getInstApFlux() else: raise MeasurementError(self.NO_FLUX.doc, self.NO_FLUX.number) # Propagate errors from second moments xcErr2, ycErr2 = np.diag(measRecord.getCentroidErr()) IxxErr2, IyyErr2, IxyErr2 = np.diag(measRecord.getShapeErr()) desc = np.sqrt(xmy2 + 4.0 * xy2) # Descriminant^1/2 of EV equation denom = 2 * np.sqrt(2.0 * (Ixx + np.sqrt(4.0 * xy2 + xmy2 + Iyy)) ) # Denominator for dadIxx and dadIyy dadIxx = (1.0 + (xmy / desc)) / denom dadIyy = (1.0 - (xmy / desc)) / denom dadIxy = (4.0 * Ixy) / (desc * denom) aErr2 = IxxErr2 * dadIxx * dadIxx + IyyErr2 * dadIyy * dadIyy + IxyErr2 * dadIxy * dadIxy thetaErr2 = ((IxxErr2 + IyyErr2) * xy2 + xmy2 * IxyErr2) / (desc * desc * desc * desc) dxda = np.cos(theta) dxdt = a * np.sin(theta) dyda = np.sin(theta) dydt = a * np.cos(theta) xErr2 = aErr2 * dxda * dxda + thetaErr2 * dxdt * dxdt yErr2 = aErr2 * dyda * dyda + thetaErr2 * dydt * dydt x0Err = np.sqrt(xErr2 + xcErr2) # Same for x1 y0Err = np.sqrt(yErr2 + ycErr2) # Same for y1 # Set flags measRecord.set(self.keyX0, x0) measRecord.set(self.keyY0, y0) measRecord.set(self.keyX1, x1) measRecord.set(self.keyY1, y1) measRecord.set(self.keyFlux, F) measRecord.set(self.keyL, L) measRecord.set(self.keyAngle, theta) measRecord.set(self.keyX0Err, x0Err) measRecord.set(self.keyY0Err, y0Err) measRecord.set(self.keyX1Err, x0Err) measRecord.set(self.keyY1Err, y0Err)