def finalize(self, idFactory): """Finalize construction of the catalog. Create a SourceCatalog from the MultiMatch object and compute the corresponding merged footprint. @param[in] idFactory Used to generate ids. @return SourceCatalog of DIAObjects """ if self.multi_matches is None: return None schema = afwTable.SourceTable.makeMinimalSchema() nobsKey = schema.addField("nobs", type=np.int32, doc='Number of times observed') fluxKey = schema.addField("flux", type=float, doc='Average flux') raKey = schema['coord_ra'].asKey() decKey = schema['coord_dec'].asKey() table = afwTable.SourceTable.make(schema, idFactory) cat = afwTable.SourceCatalog(table) results = self.multi_matches.finish(removeAmbiguous=False) allMatches = afwTable.GroupView.build(results) psfMagKey = allMatches.schema.find(self.config.fluxType).key raKey = allMatches.schema.find("coord_ra").key decKey = allMatches.schema.find("coord_dec").key ave_ra = allMatches.aggregate(np.mean, field=raKey) ave_dec = allMatches.aggregate(np.mean, field=decKey) ave_flux = allMatches.aggregate(np.mean, field=psfMagKey) # Merge the footprints from the same object together object_ids = np.unique(results['object']) footprints = [] for id in object_ids: mask = results['object'] == id footprint = None for rec in results[mask]: if footprint is None: footprint = rec.getFootprint() else: footprint = afwDet.mergeFootprints(footprint, rec.getFootprint()) footprints.append(footprint) for i in range(len(ave_ra)): rec = cat.addNew() rec.setFootprint(footprints[i]) rec.set(raKey, ave_ra[i] * geom.radians) rec.set(decKey, ave_dec[i] * geom.radians) rec.set(fluxKey, ave_flux[i]) return cat
def testMergeFootprints(self): f1 = self.foot f2 = afwDetect.Footprint() spanList1 = [(10, 10, 20), (10, 30, 40), (10, 50, 60), (11, 30, 50), (12, 30, 50), (13, 10, 20), (13, 30, 40), (13, 50, 60), (15, 10, 20), (15, 31, 40), (15, 51, 60)] spanSet1 = afwGeom.SpanSet([afwGeom.Span(*span) for span in spanList1]) f1.spans = spanSet1 spanList2 = [(8, 10, 20), (9, 20, 30), (10, 0, 9), (10, 35, 65), (10, 70, 80), (13, 49, 54), (14, 10, 30), (15, 21, 30), (15, 41, 50), (15, 61, 70)] spanSet2 = afwGeom.SpanSet([afwGeom.Span(*span) for span in spanList2]) f2.spans = spanSet2 fA = afwDetect.mergeFootprints(f1, f2) fB = afwDetect.mergeFootprints(f2, f1) ims = [] for i, f in enumerate([f1, f2, fA, fB]): im1 = afwImage.ImageU(100, 100) im1.set(0) imbb = im1.getBBox() f.setRegion(imbb) f.spans.setImage(im1, 1) ims.append(im1) for i, merged in enumerate([ims[2], ims[3]]): m = merged.getArray() a1 = ims[0].getArray() a2 = ims[1].getArray() # Slightly looser tests to start... # Every pixel in f1 is in f[AB] self.assertTrue(np.all(m.flat[np.flatnonzero(a1)] == 1)) # Every pixel in f2 is in f[AB] self.assertTrue(np.all(m.flat[np.flatnonzero(a2)] == 1)) # merged == a1 | a2. self.assertTrue(np.all(m == np.maximum(a1, a2)))
def _fig8Test(self, x1, y1, x2, y2): # Construct a "figure of 8" consisting of two circles touching at the # centre of an image, then demonstrate that it shrinks correctly. # (Helper method for tests below.) radius = 3 imwidth, imheight = 100, 100 nshrink = 1 # These are the correct values for footprint sizes given the paramters # above. circle_npix = 29 initial_npix = circle_npix * 2 - 1 # touch at one pixel shrunk_npix = 26 box = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(imwidth, imheight)) e1 = afwGeom.Ellipse(afwGeomEllipses.Axes(radius, radius, 0), lsst.geom.Point2D(x1, y1)) spanSet1 = afwGeom.SpanSet.fromShape(e1) f1 = afwDetect.Footprint(spanSet1, box) self.assertEqual(f1.getArea(), circle_npix) e2 = afwGeom.Ellipse(afwGeomEllipses.Axes(radius, radius, 0), lsst.geom.Point2D(x2, y2)) spanSet2 = afwGeom.SpanSet.fromShape(e2) f2 = afwDetect.Footprint(spanSet2, box) self.assertEqual(f2.getArea(), circle_npix) initial = afwDetect.mergeFootprints(f1, f2) initial.setRegion( f2.getRegion()) # merge does not propagate the region self.assertEqual(initial_npix, initial.getArea()) shrunk = afwDetect.Footprint().assign(initial) shrunk.erode(nshrink) self.assertEqual(shrunk_npix, shrunk.getArea()) if display: idImage = afwImage.ImageU(imwidth, imheight) for i, foot in enumerate([initial, shrunk]): print(foot.getArea()) foot.spans.setImage(idImage, i + 1) afwDisplay.Display(frame=1).mtv(idImage, title=self._testMethodName + " image")
def _fig8Test(self, x1, y1, x2, y2): # Construct a "figure of 8" consisting of two circles touching at the # centre of an image, then demonstrate that it shrinks correctly. # (Helper method for tests below.) radius = 3 imwidth, imheight = 100, 100 nshrink = 1 # These are the correct values for footprint sizes given the paramters # above. circle_npix = 29 initial_npix = circle_npix * 2 - 1 # touch at one pixel shrunk_npix = 26 box = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(imwidth, imheight)) e1 = afwGeomEllipses.Ellipse(afwGeomEllipses.Axes(radius, radius, 0), afwGeom.Point2D(x1, y1)) f1 = afwDetect.Footprint(e1, box) self.assertEqual(f1.getNpix(), circle_npix) e2 = afwGeomEllipses.Ellipse(afwGeomEllipses.Axes(radius, radius, 0), afwGeom.Point2D(x2, y2)) f2 = afwDetect.Footprint(e2, box) self.assertEqual(f2.getNpix(), circle_npix) initial = afwDetect.mergeFootprints(f1, f2) initial.setRegion( f2.getRegion()) # merge does not propagate the region self.assertEqual(initial_npix, initial.getNpix()) shrunk = afwDetect.shrinkFootprint(initial, nshrink, True) self.assertEqual(shrunk_npix, shrunk.getNpix()) if display: idImage = afwImage.ImageU(imwidth, imheight) for i, foot in enumerate([initial, shrunk]): print(foot.getNpix()) foot.insertIntoImage(idImage, i + 1) ds9.mtv(idImage)
def _fig8Test(self, x1, y1, x2, y2): # Construct a "figure of 8" consisting of two circles touching at the # centre of an image, then demonstrate that it shrinks correctly. # (Helper method for tests below.) radius = 3 imwidth, imheight = 100, 100 nshrink = 1 # These are the correct values for footprint sizes given the paramters # above. circle_npix = 29 initial_npix = circle_npix * 2 - 1 # touch at one pixel shrunk_npix = 26 box = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(imwidth, imheight)) e1 = afwGeomEllipses.Ellipse(afwGeomEllipses.Axes(radius, radius, 0), afwGeom.Point2D(x1, y1)) f1 = afwDetect.Footprint(e1,box) self.assertEqual(f1.getNpix(), circle_npix) e2 = afwGeomEllipses.Ellipse(afwGeomEllipses.Axes(radius, radius, 0), afwGeom.Point2D(x2, y2)) f2 = afwDetect.Footprint(e2,box) self.assertEqual(f2.getNpix(), circle_npix) initial = afwDetect.mergeFootprints(f1, f2) initial.setRegion(f2.getRegion()) # merge does not propagate the region self.assertEqual(initial_npix, initial.getNpix()) shrunk = afwDetect.shrinkFootprint(initial, nshrink, True) self.assertEqual(shrunk_npix, shrunk.getNpix()) if display: idImage = afwImage.ImageU(imwidth, imheight) for i, foot in enumerate([initial, shrunk]): print foot.getNpix() foot.insertIntoImage(idImage, i+1); ds9.mtv(idImage)
def testMergeFootprints(self): f1 = self.foot f2 = afwDetect.Footprint() f1.addSpan(10, 10, 20) f1.addSpan(10, 30, 40) f1.addSpan(10, 50, 60) f1.addSpan(11, 30, 50) f1.addSpan(12, 30, 50) f1.addSpan(13, 10, 20) f1.addSpan(13, 30, 40) f1.addSpan(13, 50, 60) f1.addSpan(15, 10, 20) f1.addSpan(15, 31, 40) f1.addSpan(15, 51, 60) f2.addSpan(8, 10, 20) f2.addSpan(9, 20, 30) f2.addSpan(10, 0, 9) f2.addSpan(10, 35, 65) f2.addSpan(10, 70, 80) f2.addSpan(13, 49, 54) f2.addSpan(14, 10, 30) f2.addSpan(15, 21, 30) f2.addSpan(15, 41, 50) f2.addSpan(15, 61, 70) f1.normalize() f2.normalize() fA = afwDetect.mergeFootprints(f1, f2) fB = afwDetect.mergeFootprints(f2, f1) ims = [] for i, f in enumerate([f1, f2, fA, fB]): im1 = afwImage.ImageU(100, 100) im1.set(0) imbb = im1.getBBox() f.setRegion(imbb) f.insertIntoImage(im1, 1) ims.append(im1) for i, merged in enumerate([ims[2], ims[3]]): m = merged.getArray() a1 = ims[0].getArray() a2 = ims[1].getArray() # Slightly looser tests to start... # Every pixel in f1 is in f[AB] self.assertTrue(np.all(m.flat[np.flatnonzero(a1)] == 1)) # Every pixel in f2 is in f[AB] self.assertTrue(np.all(m.flat[np.flatnonzero(a2)] == 1)) # merged == a1 | a2. self.assertTrue(np.all(m == np.maximum(a1, a2))) if False: import matplotlib matplotlib.use('Agg') import pylab as plt plt.clf() for i, im1 in enumerate(ims): plt.subplot(4, 1, i + 1) plt.imshow(im1.getArray(), interpolation='nearest', origin='lower') plt.axis([0, 100, 0, 20]) plt.savefig('merge2.png')
def finalize(self, idFactory): """Finalize construction of the catalog. Create a SourceCatalog from the MultiMatch object and compute the corresponding merged footprint. @param[in] idFactory Used to generate ids. @return SourceCatalog of DIAObjects """ if self.multi_matches is None: return None schema = afwTable.SourceTable.makeMinimalSchema() nobsKey = schema.addField("nobs", type=np.int32, doc='Number of times observed') keys = {} for filter in self.config.filters: flux = self.config.fluxType keys[f'{flux}_Mean_{filter}'] = schema.addField( f"{flux}_Mean_{filter}", type=float, doc=f'Mean {flux} in filter {filter}') keys[f'{flux}_MeanErr_{filter}'] = schema.addField( f"{flux}_MeanErr_{filter}", type=float, doc=f'MeanErr {flux} in filter {filter}') keys[f'{flux}_Sigma_{filter}'] = schema.addField( f"{flux}_Sigma_{filter}", type=float, doc=f'Sigma {flux} in filter {filter}') keys[f'{flux}_Ndata_{filter}'] = schema.addField( f"{flux}_NData_{filter}", type=np.int32, doc=f'Number of observations in filter {filter}') keys[f'{flux}_Chi2_{filter}'] = schema.addField( f"{flux}_Chi2_{filter}", type=float, doc=f'Chi2 of {flux} for {filter}') raKey = schema['coord_ra'].asKey() decKey = schema['coord_dec'].asKey() table = afwTable.SourceTable.make(schema, idFactory) cat = afwTable.SourceCatalog(table) results = self.multi_matches.finish(removeAmbiguous=False) allMatches = afwTable.GroupView.build(results) raKey = allMatches.schema.find("coord_ra").key decKey = allMatches.schema.find("coord_dec").key ave_ra = allMatches.aggregate(np.mean, field=raKey) ave_dec = allMatches.aggregate(np.mean, field=decKey) # Merge the footprints from the same object together and accumulate # information object_ids = np.unique(results['object']) footprints = [] all_fluxes = [] all_flux_errs = [] num_nobs = [] self.diaSrcIds = [] self.diaObjectIds = [] for id in object_ids: mask = results['object'] == id num_nobs.append(np.sum(mask)) footprint = None src_ids = [] fluxes = defaultdict(list) flux_errs = defaultdict(list) for rec in results[mask]: if footprint is None: footprint = rec.getFootprint() else: footprint = afwDet.mergeFootprints(footprint, rec.getFootprint()) src_ids.append(rec.get('id')) flux = rec.get(self.config.fluxType) if np.isfinite(flux) is False: continue filter = self.config.filters[rec.get('filter')] calib = self.calibDict[rec.get('visit')][rec.get('ccd')] flux_err = rec.get(self.config.fluxType + "Err") new_val, new_val_err = scaleFlux(flux, flux_err, calib, self.calib) fluxes[filter].append(new_val) flux_errs[filter].append(new_val_err) self.diaSrcIds.append(src_ids) footprints.append(footprint) all_fluxes.append(fluxes) all_flux_errs.append(flux_errs) for i in range(len(ave_ra)): rec = cat.addNew() self.diaObjectIds.append(rec.get('id')) rec.setFootprint(footprints[i]) rec.set(raKey, ave_ra[i] * geom.radians) rec.set(decKey, ave_dec[i] * geom.radians) rec.set(nobsKey, num_nobs[i]) for filter in self.config.filters: fluxes = np.array(all_fluxes[i][filter]) if len(fluxes) == 0: continue flux_errs = np.array(all_flux_errs[i][filter]) flux = self.config.fluxType rec.set(keys[f'{flux}_Mean_{filter}'], np.mean(fluxes)) rec.set(keys[f'{flux}_Sigma_{filter}'], np.std(fluxes, ddof=1)) rec.set(keys[f'{flux}_Ndata_{filter}'], len(fluxes)) rec.set( keys[f'{flux}_MeanErr_{filter}'], rec.get(f'{flux}_Sigma_{filter}') / np.sqrt(len(fluxes))) residuals = fluxes - rec.get(keys[f'{flux}_Mean_{filter}']) rec.set(keys[f'{flux}_Chi2_{filter}'], np.sum((residuals / flux_errs)**2)) return cat
def testMergeFootprints(self): f1 = self.foot f2 = afwDetect.Footprint() f1.addSpan(10, 10, 20) f1.addSpan(10, 30, 40) f1.addSpan(10, 50, 60) f1.addSpan(11, 30, 50) f1.addSpan(12, 30, 50) f1.addSpan(13, 10, 20) f1.addSpan(13, 30, 40) f1.addSpan(13, 50, 60) f1.addSpan(15, 10,20) f1.addSpan(15, 31,40) f1.addSpan(15, 51,60) f2.addSpan(8, 10, 20) f2.addSpan(9, 20, 30) f2.addSpan(10, 0, 9) f2.addSpan(10, 35, 65) f2.addSpan(10, 70, 80) f2.addSpan(13, 49, 54) f2.addSpan(14, 10, 30) f2.addSpan(15, 21,30) f2.addSpan(15, 41,50) f2.addSpan(15, 61,70) f1.normalize() f2.normalize() fA = afwDetect.mergeFootprints(f1, f2) fB = afwDetect.mergeFootprints(f2, f1) ims = [] for i,f in enumerate([f1,f2,fA,fB]): im1 = afwImage.ImageU(100, 100) im1.set(0) imbb = im1.getBBox() f.setRegion(imbb) f.insertIntoImage(im1, 1) ims.append(im1) for i,merged in enumerate([ims[2],ims[3]]): m = merged.getArray() a1 = ims[0].getArray() a2 = ims[1].getArray() # Slightly looser tests to start... # Every pixel in f1 is in f[AB] self.assertTrue(numpy.all(m.flat[numpy.flatnonzero(a1)] == 1)) # Every pixel in f2 is in f[AB] self.assertTrue(numpy.all(m.flat[numpy.flatnonzero(a2)] == 1)) # merged == a1 | a2. self.assertTrue(numpy.all(m == numpy.maximum(a1, a2))) if False: import matplotlib matplotlib.use('Agg') import pylab as plt plt.clf() for i,im1 in enumerate(ims): plt.subplot(4,1, i+1) plt.imshow(im1.getArray(), interpolation='nearest', origin='lower') plt.axis([0, 100, 0, 20]) plt.savefig('merge2.png')