def lanczos_shift_image(img, dx, dy, inplace=False, force_python=False): global mp_fourier if mp_fourier == -1: try: from tractor import mp_fourier except: print( 'tractor.psf: failed to import C version of mp_fourier library. Falling back to python version.' ) mp_fourier = None H, W = img.shape if (mp_fourier is None or force_python or W <= 8 or H <= 8 or H > work_corr7f.shape[0] or W > work_corr7f.shape[1]): # fallback to python: from scipy.ndimage import correlate1d from astrometry.util.miscutils import lanczos_filter L = 3 Lx = lanczos_filter(L, np.arange(-L, L + 1) + dx) Ly = lanczos_filter(L, np.arange(-L, L + 1) + dy) # Normalize the Lanczos interpolants (preserve flux) Lx /= Lx.sum() Ly /= Ly.sum() sx = correlate1d(img, Lx, axis=1, mode='constant') outimg = correlate1d(sx, Ly, axis=0, mode='constant') return outimg outimg = np.empty(img.shape, np.float32) mp_fourier.lanczos_shift_3f(img, outimg, dx, dy, work_corr7f) # yuck! (don't change this without ensuring the "restrict" keyword still applies # in lanczos_shift_3f!) if inplace: img[:, :] = outimg return outimg
def lanczos_shift_image(img, dx, dy, inplace=False, force_python=False): from scipy.ndimage import correlate1d from astrometry.util.miscutils import lanczos_filter L = 3 Lx = lanczos_filter(L, np.arange(-L, L + 1) + dx) Ly = lanczos_filter(L, np.arange(-L, L + 1) + dy) # Normalize the Lanczos interpolants (preserve flux) Lx /= Lx.sum() Ly /= Ly.sum() H, W = img.shape #print('lanczos_shift_image: size', W, H) #print('mp_fourier:', mp_fourier) if (mp_fourier is None or force_python or W <= 8 or H <= 8 or H > work_corr7f.shape[0] or W > work_corr7f.shape[1]): sx = correlate1d(img, Lx, axis=1, mode='constant') outimg = correlate1d(sx, Ly, axis=0, mode='constant') else: assert (len(Lx) == 7) assert (len(Ly) == 7) if inplace: assert (img.dtype == np.float32) outimg = img else: outimg = np.empty(img.shape, np.float32) outimg[:, :] = img mp_fourier.correlate7f(outimg, Lx, Ly, work_corr7f) assert (np.all(np.isfinite(outimg))) return outimg
def getPointSourcePatch(self, px, py, minval=0., modelMask=None, **kwargs): from scipy.ndimage.filters import correlate1d from astrometry.util.miscutils import get_overlapping_region img = self.getImage(px, py) H,W = img.shape ix = int(np.round(px)) iy = int(np.round(py)) dx = px - ix dy = py - iy x0 = ix - W/2 y0 = iy - H/2 if modelMask is not None: mh,mw = modelMask.shape mx0,my0 = modelMask.x0, modelMask.y0 # print 'PixelizedPSF + modelMask' # print 'mx0,my0', mx0,my0, '+ mw,mh', mw,mh # print 'PSF image x0,y0', x0,y0, '+ W,H', W,H if (mx0 >= x0 + W or my0 >= y0 + H or mx0 + mw <= x0 or my0 + mh <= y0): # No overlap return None # Otherwise, we'll just produce the Lanczos-shifted PSF image as usual, # and then copy it into the modelMask space. L = self.Lorder Lx = lanczos_filter(L, np.arange(-L, L+1) + dx) Ly = lanczos_filter(L, np.arange(-L, L+1) + dy) # Normalize the Lanczos interpolants (preserve flux) Lx /= Lx.sum() Ly /= Ly.sum() sx = correlate1d(img, Lx, axis=1, mode='constant') shifted = correlate1d(sx, Ly, axis=0, mode='constant') if modelMask is None: return Patch(x0, y0, shifted) # Pad or clip to modelMask size mm = np.zeros((mh,mw), shifted.dtype) yo = y0 - my0 yi = 0 ny = min(y0+H, my0+mh) - max(y0, my0) if yo < 0: yi = -yo yo = 0 xo = x0 - mx0 xi = 0 nx = min(x0+W, mx0+mw) - max(x0, mx0) if xo < 0: xi = -xo xo = 0 mm[yo:yo+ny, xo:xo+nx] = shifted[yi:yi+ny, xi:xi+nx] return Patch(mx0, my0, mm)
def getPointSourcePatch(self, px, py, minval=0., modelMask=None, **kwargs): from scipy.ndimage.filters import correlate1d from astrometry.util.miscutils import get_overlapping_region img = self.getImage(px, py) H, W = img.shape ix = int(np.round(px)) iy = int(np.round(py)) dx = px - ix dy = py - iy x0 = ix - W / 2 y0 = iy - H / 2 if modelMask is not None: mh, mw = modelMask.shape mx0, my0 = modelMask.x0, modelMask.y0 # print 'PixelizedPSF + modelMask' # print 'mx0,my0', mx0,my0, '+ mw,mh', mw,mh # print 'PSF image x0,y0', x0,y0, '+ W,H', W,H if (mx0 >= x0 + W or my0 >= y0 + H or mx0 + mw <= x0 or my0 + mh <= y0): # No overlap return None # Otherwise, we'll just produce the Lanczos-shifted PSF image as usual, # and then copy it into the modelMask space. L = self.Lorder Lx = lanczos_filter(L, np.arange(-L, L + 1) + dx) Ly = lanczos_filter(L, np.arange(-L, L + 1) + dy) # Normalize the Lanczos interpolants (preserve flux) Lx /= Lx.sum() Ly /= Ly.sum() sx = correlate1d(img, Lx, axis=1, mode='constant') shifted = correlate1d(sx, Ly, axis=0, mode='constant') if modelMask is None: return Patch(x0, y0, shifted) # Pad or clip to modelMask size mm = np.zeros((mh, mw), shifted.dtype) yo = y0 - my0 yi = 0 ny = min(y0 + H, my0 + mh) - max(y0, my0) if yo < 0: yi = -yo yo = 0 xo = x0 - mx0 xi = 0 nx = min(x0 + W, mx0 + mw) - max(x0, mx0) if xo < 0: xi = -xo xo = 0 mm[yo:yo + ny, xo:xo + nx] = shifted[yi:yi + ny, xi:xi + nx] return Patch(mx0, my0, mm)
def test_gal(self): if ps is not None: import pylab as plt pos = PixPos(49.5, 50.) pos0 = pos bright = NanoMaggies(g=1., r=2.) shape = GalaxyShape(2., 0.5, 45.) #psf = GaussianMixturePSF(1., 0., 0., 4., 4., 0.) psf = GaussianMixturePSF(1., 0., 0., 6., 6., -1.) #psf = GaussianMixturePSF(1., 0., 0., 9., 9., -1.) #psf = GaussianMixturePSF(1., 0., 0., 16., 16., -1.) H, W = 100, 100 tim = Image( data=np.zeros((H, W), np.float32), inverr=np.ones((H, W), np.float32), psf=psf, photocal=LinearPhotoCal(1., band='r'), ) psf0 = tim.psf # base class #gal1 = Galaxy(pos, bright, shape) gal1 = ExpGalaxy(pos, bright, shape) self.assertEqual(gal1.shape.ab, 0.5) print('gal:', gal1) print('gal:', str(gal1)) # harsh self.assertEqual( str(gal1), 'ExpGalaxy at pixel (49.50, 50.00) with NanoMaggies: g=22.5, r=21.7 and Galaxy Shape: re=2.00, ab=0.50, phi=45.0' ) self.assertEqual( repr(gal1), 'ExpGalaxy(pos=PixPos[49.5, 50.0], brightness=NanoMaggies: g=22.5, r=21.7, shape=re=2, ab=0.5, phi=45)' ) derivs = gal1.getParamDerivatives(tim) print('Derivs:', derivs) self.assertEqual(len(derivs), 7) self.assertEqual(len(derivs), gal1.numberOfParams()) self.assertEqual(len(derivs), len(gal1.getParams())) for d in derivs: self.assertIsNotNone(d) # Set one of the fluxes to zero. gal1.brightness.r = 0. derivs = gal1.getParamDerivatives(tim) print('Derivs:', derivs) self.assertEqual(len(derivs), 7) for i, d in enumerate(derivs): # flux derivatives still non-None if i in [2, 3]: self.assertIsNotNone(derivs[i]) else: # other derivatives should be None self.assertIsNone(derivs[i]) gal1.brightness.r = 100. mod = np.zeros((H, W), np.float32) p1 = gal1.getModelPatch(tim) print('Model patch:', p1) print('patch sum:', p1.patch.sum()) # Very specific tests... self.assertEqual(p1.x0, 16) self.assertEqual(p1.y0, 17) self.assertEqual(p1.shape, (68, 69)) self.assertTrue(np.abs(p1.patch.sum() - 100.) < 1e-3) p1.addTo(mod) print('Mod sum:', mod.sum()) mh, mw = mod.shape xx, yy = np.meshgrid(np.arange(mw), np.arange(mh)) cx, cy = np.sum(xx * mod) / np.sum(mod), np.sum(yy * mod) / np.sum(mod) mxx = np.sum((xx - cx)**2 * mod) / np.sum(mod) myy = np.sum((yy - cy)**2 * mod) / np.sum(mod) mxy = np.sum((xx - cx) * (yy - cy) * mod) / np.sum(mod) print('mod centroid:', cx, cy) print('moments:', mxx, myy, mxy) self.assertTrue(np.abs(mod.sum() - 100.) < 1e-3) if ps is not None: plt.clf() plt.imshow(mod, interpolation='nearest', origin='lower') plt.title('mod') plt.colorbar() ps.savefig() def show_model(modN, mod, name): plt.clf() sy, sx = slice(40, 60), slice(40, 60) plt.subplot(2, 3, 1) plt.imshow(modN[sy, sx], interpolation='nearest', origin='lower') plt.colorbar() plt.title(name) if mod is not None: plt.subplot(2, 3, 2) plt.imshow(mod[sy, sx], interpolation='nearest', origin='lower') plt.colorbar() plt.title('mod') plt.subplot(2, 3, 3) mx = np.abs(modN - mod).max() plt.imshow((modN - mod)[sy, sx], interpolation='nearest', origin='lower', vmin=-mx, vmax=mx) plt.colorbar() plt.title('%s - mod' % name) plt.subplot(2, 3, 6) plt.imshow(modN - mod, interpolation='nearest', origin='lower') plt.colorbar() plt.title('%s - mod' % name) plt.subplot(2, 3, 4) mx = modN.max() plt.imshow(np.log10(modN), vmin=np.log10(mx) - 6, vmax=np.log10(mx), interpolation='nearest', origin='lower') plt.colorbar() plt.title('log %s' % name) if mod is not None: plt.subplot(2, 3, 5) plt.imshow(np.log10(mod), vmin=np.log10(mx) - 6, vmax=np.log10(mx), interpolation='nearest', origin='lower') plt.colorbar() plt.title('log mod') ps.savefig() # Test with ModelMask mm = ModelMask(25, 25, 50, 50) p2 = gal1.getModelPatch(tim, modelMask=mm) mod2 = np.zeros((H, W), np.float32) p2.addTo(mod2) print('Patch:', p2) self.assertEqual(p2.x0, 25) self.assertEqual(p2.y0, 25) self.assertEqual(p2.shape, (50, 50)) print('patch sum:', p2.patch.sum()) print('Mod sum:', mod2.sum()) self.assertTrue(np.abs(mod2.sum() - 100.) < 1e-3) if ps is not None: show_model(mod2, mod, 'mod2') print('Diff between mods:', np.abs(mod - mod2).max()) self.assertTrue(np.abs(mod - mod2).max() < 1e-6) # Test with a ModelMask with a binary map of pixels of interest mm3 = ModelMask(30, 29, np.ones((40, 40), bool)) p3 = gal1.getModelPatch(tim, modelMask=mm3) mod3 = np.zeros((H, W), np.float32) p3.addTo(mod3) print('Patch:', p3) self.assertEqual(p3.x0, 30) self.assertEqual(p3.y0, 29) self.assertEqual(p3.shape, (40, 40)) print('patch sum:', p3.patch.sum()) print('Mod sum:', mod3.sum()) self.assertTrue(np.abs(mod3.sum() - 100.) < 1e-3) print('Diff between mods:', np.abs(mod3 - mod).max()) self.assertTrue(np.abs(mod3 - mod).max() < 1e-6) if ps is not None: show_model(mod3, mod, 'mod3') # Test with a PixelizedPSF (FFT method), created from the Gaussian PSF # image (so we can check consistency) psfpatch = tim.psf.getPointSourcePatch(24., 24., modelMask=ModelMask( 0, 0, 50, 50)) print('PSF patch:', psfpatch) tim.psf = PixelizedPSF(psfpatch.patch[:49, :49]) pixpsf = tim.psf # No modelmask print() print('Rendering mod4') p4 = gal1.getModelPatch(tim) mod4 = np.zeros((H, W), np.float32) p4.addTo(mod4) print('Patch:', p4) cx, cy = np.sum(xx * mod4) / np.sum(mod4), np.sum( yy * mod4) / np.sum(mod4) mxx = np.sum((xx - cx)**2 * mod4) / np.sum(mod4) myy = np.sum((yy - cy)**2 * mod4) / np.sum(mod4) mxy = np.sum((xx - cx) * (yy - cy) * mod4) / np.sum(mod4) print('mod centroid:', cx, cy) print('moments:', mxx, myy, mxy) if ps is not None: show_model(mod4, mod, 'mod4') # These assertions are fairly arbitrary... self.assertEqual(p4.x0, 6) self.assertEqual(p4.y0, 7) self.assertEqual(p4.shape, (88, 89)) print('patch sum:', p4.patch.sum()) print('Mod sum:', mod4.sum()) self.assertTrue(np.abs(mod4.sum() - 100.) < 1e-3) print('Diff between mods:', np.abs(mod4 - mod).max()) #self.assertTrue(np.abs(mod4 - mod).max() < 1e-6) self.assertTrue(np.abs(mod4 - mod).max() < 2e-3) import tractor.galaxy if ps is not None: #pp = [49.0, 49.1, 49.2, 49.3, 49.4, 49.5, 49.6, 49.7, 49.8, 49.9, 50.] #pp = np.arange(48, 51, 0.1) plt.clf() for L in [3, 5, 7]: tractor.galaxy.fft_lanczos_order = L CX = [] pp = np.arange(49, 50.1, 0.1) gal1copy = gal1.copy() for p in pp: gal1copy.pos = PixPos(p, 50.) tim.psf = psf newmod = np.zeros((H, W), np.float32) p1 = gal1copy.getModelPatch(tim) p1.addTo(newmod) #mod[:,:] = newmod tim.psf = pixpsf modX = np.zeros((H, W), np.float32) p1 = gal1copy.getModelPatch(tim) p1.addTo(modX) print('p=', p) cx, cy = np.sum(xx * modX) / np.sum(modX), np.sum( yy * modX) / np.sum(modX) mxx = np.sum((xx - cx)**2 * modX) / np.sum(modX) myy = np.sum((yy - cy)**2 * modX) / np.sum(modX) mxy = np.sum((xx - cx) * (yy - cy) * modX) / np.sum(modX) print('mod centroid:', cx, cy) print('moments:', mxx, myy, mxy) CX.append(cx) plt.plot(pp, np.array(CX) - np.array(pp), '-', label='Lanczos-%i' % L) #show_model(modX, newmod, 'mod4(%.1f)' % p) # plt.clf() # plt.subplot(2,1,1) # plt.plot(mod[H/2,:], 'k-') # plt.plot(modX[H/2,:], 'r-') # plt.subplot(2,1,2) # plt.plot(modX[H/2,:] - mod[H/2,:], 'r-') # plt.suptitle('mod4(%.1f)' % p) # ps.savefig() # plt.clf() # plt.plot(pp, CX, 'b-') # plt.plot(pp, pp, 'k-', alpha=0.25) # plt.xlabel('Pixel position') # plt.ylabel('Centroid') # plt.title('Lanczos-3 interpolation of galaxy profile') # ps.savefig() plt.axhline(0, color='k', alpha=0.25) plt.xlabel('Pixel position') plt.ylabel('Centroid - Pixel position') plt.title('Lanczos interpolation of galaxy profile') plt.legend(loc='upper left') ps.savefig() from astrometry.util.miscutils import lanczos_filter plt.clf() xx = np.linspace(-(7 + 1), 7 + 1, 300) for L in [3, 5, 7]: plt.plot(xx, lanczos_filter(L, xx), '-', label='Lancoz-%i' % L) plt.title('Lanczos') ps.savefig() tractor.galaxy.fft_lanczos_order = 3 # Test with ModelMask with "mm" p5 = gal1.getModelPatch(tim, modelMask=mm) mod5 = np.zeros((H, W), np.float32) p5.addTo(mod5) print('Patch:', p5) if ps is not None: show_model(mod5, mod, 'mod5') self.assertEqual(p5.x0, 25) self.assertEqual(p5.y0, 25) self.assertEqual(p5.shape, (50, 50)) print('patch sum:', p5.patch.sum()) print('Mod sum:', mod5.sum()) self.assertTrue(np.abs(mod5.sum() - 100.) < 1e-3) print('Diff between mods:', np.abs(mod5 - mod).max()) #self.assertTrue(np.abs(mod5 - mod).max() < 1e-6) self.assertTrue(np.abs(mod5 - mod).max() < 2e-3) # Test with a source center outside the ModelMask. # Way outside the ModelMask -> model is None gal1.pos = PixPos(200, -50.) p6 = gal1.getModelPatch(tim, modelMask=mm) self.assertIsNone(p6) # Slightly outside the ModelMask gal1.pos = PixPos(20., 25.) p7 = gal1.getModelPatch(tim, modelMask=mm) mod7 = np.zeros((H, W), np.float32) p7.addTo(mod7) print('Patch:', p7) if ps is not None: show_model(mod7, mod, 'mod7') self.assertEqual(p7.x0, 25) self.assertEqual(p7.y0, 25) self.assertEqual(p7.shape, (50, 50)) print('patch sum:', p7.patch.sum()) print('Mod sum:', mod7.sum()) #self.assertTrue(np.abs(mod7.sum() - 1.362) < 1e-3) self.assertTrue(np.abs(mod7.sum() - 1.963) < 1e-3) # Test a HybridPSF tim.psf = HybridPixelizedPSF(tim.psf) hybridpsf = tim.psf # Slightly outside the ModelMask gal1.pos = PixPos(20., 25.) p8 = gal1.getModelPatch(tim, modelMask=mm) mod8 = np.zeros((H, W), np.float32) p8.addTo(mod8) print('Patch:', p8) if ps is not None: show_model(mod8, mod, 'mod8') self.assertEqual(p8.x0, 25) self.assertEqual(p8.y0, 25) self.assertEqual(p8.shape, (50, 50)) print('patch sum:', p8.patch.sum()) print('Mod sum:', mod8.sum()) #self.assertTrue(np.abs(mod8.sum() - 1.362) < 1e-3) self.assertTrue(np.abs(mod7.sum() - 1.963) < 1e-3) if ps is not None: plt.clf() plt.imshow(mod7, interpolation='nearest', origin='lower') plt.colorbar() plt.title('Source outside mask') ps.savefig() plt.clf() plt.imshow(mod8, interpolation='nearest', origin='lower') plt.colorbar() plt.title('Source outside mask, Hybrid PSF') ps.savefig() # Put the source close to the image edge. gal1.pos = PixPos(5., 5.) # No model mask p9 = gal1.getModelPatch(tim) mod9 = np.zeros((H, W), np.float32) p9.addTo(mod9) print('Patch:', p9) if ps is not None: show_model(mod9, None, 'mod9') #self.assertEqual(p8.x0, 25) #self.assertEqual(p8.y0, 25) #self.assertEqual(p8.shape, (50,50)) print('Mod sum:', mod9.sum()) #self.assertTrue(np.abs(mod9.sum() - 96.98) < 1e-2) self.assertTrue(np.abs(mod9.sum() - 94.33) < 1e-2) # Zero outside (0,50),(0,50) self.assertEqual(np.sum(np.abs(mod9[50:, :])), 0.) self.assertEqual(np.sum(np.abs(mod9[:, 50:])), 0.) if ps is not None: plt.clf() plt.imshow(mod9, interpolation='nearest', origin='lower', vmin=0, vmax=1e-12) plt.colorbar() plt.title('Source near image edge') ps.savefig() # Source back in the middle. # Tight ModelMask gal1.pos = pos0 mm10 = ModelMask(45, 45, 10, 10) p10 = gal1.getModelPatch(tim, modelMask=mm10) mod10 = np.zeros((H, W), np.float32) p10.addTo(mod10) print('Patch:', p10) self.assertEqual(p10.x0, 45) self.assertEqual(p10.y0, 45) self.assertEqual(p10.shape, (10, 10)) print('Mod sum:', mod10.sum()) #self.assertTrue(np.abs(mod10.sum() - 96.98) < 1e-2) # Larger modelMask mm11 = ModelMask(30, 30, 40, 40) p11 = gal1.getModelPatch(tim, modelMask=mm11) mod11 = np.zeros((H, W), np.float32) p11.addTo(mod11) print('Patch:', p11) print('Mod sum:', mod11.sum()) self.assertTrue(np.abs(mod11.sum() - 100.) < 1e-3) if ps is not None: plt.clf() plt.imshow(mod10, interpolation='nearest', origin='lower') plt.colorbar() ps.savefig() plt.clf() plt.imshow(mod11, interpolation='nearest', origin='lower') plt.colorbar() ps.savefig() diff = (mod11 - mod10)[45:55, 45:55] print('Max diff:', np.abs(diff).max()) self.assertTrue(np.abs(diff).max() < 1e-6) # DevGalaxy test gal1.pos = pos0 bright2 = bright shape2 = GalaxyShape(3., 0.4, 60.) gal2 = DevGalaxy(pos, bright2, shape2) p12 = gal2.getModelPatch(tim, modelMask=mm) mod12 = np.zeros((H, W), np.float32) p12.addTo(mod12) print('Patch:', p12) print('patch sum:', p12.patch.sum()) print('Mod sum:', mod12.sum()) self.assertTrue(np.abs(mod12.sum() - 99.95) < 1e-2) # Test FixedCompositeGalaxy shapeExp = shape shapeDev = shape2 #modExp = mod2 modExp = mod4 modDev = mod12 # Set FracDev = 0 --> equals gal1 in patch2. gal3 = FixedCompositeGalaxy(pos, bright, FracDev(0.), shapeExp, shapeDev) print('Testing galaxy:', gal3) print('repr', repr(gal3)) p13 = gal3.getModelPatch(tim, modelMask=mm) mod13 = np.zeros((H, W), np.float32) p13.addTo(mod13) print('Patch:', p13) print('patch sum:', p13.patch.sum()) print('Mod sum:', mod13.sum()) if ps is not None: show_model(mod13, modExp, 'mod13') self.assertTrue(np.abs(mod13.sum() - 100.00) < 1e-2) print('SAD:', np.sum(np.abs(mod13 - modExp))) #self.assertTrue(np.sum(np.abs(mod13 - modExp)) < 1e-8) self.assertTrue(np.sum(np.abs(mod13 - modExp)) < 1e-5) # Set FracDev = 1 --> equals gal2 in patch12. gal3.fracDev.setValue(1.) p14 = gal3.getModelPatch(tim, modelMask=mm) mod14 = np.zeros((H, W), np.float32) p14.addTo(mod14) print('Patch:', p14) print('patch sum:', p14.patch.sum()) print('Mod sum:', mod14.sum()) self.assertTrue(np.abs(mod14.sum() - 99.95) < 1e-2) print('SAD:', np.sum(np.abs(mod14 - modDev))) #self.assertTrue(np.sum(np.abs(mod14 - modDev)) < 1e-8) self.assertTrue(np.sum(np.abs(mod14 - modDev)) < 1e-5) # Set FracDev = 0.5 --> equals mean gal3.fracDev = SoftenedFracDev(0.5) p15 = gal3.getModelPatch(tim, modelMask=mm) mod15 = np.zeros((H, W), np.float32) p15.addTo(mod15) print('Patch:', p15) print('patch sum:', p15.patch.sum()) print('Mod sum:', mod15.sum()) self.assertTrue(np.abs(mod15.sum() - 99.98) < 1e-2) target = (modDev + modExp) / 2. print('SAD:', np.sum(np.abs(mod15 - target))) self.assertTrue(np.sum(np.abs(mod15 - target)) < 1e-5) derivs = gal3.getParamDerivatives(tim) print('Derivs:', derivs) self.assertEqual(len(derivs), 11) # CompositeGalaxy gal4 = CompositeGalaxy(pos, bright, shapeExp, bright, shapeDev) print('Testing galaxy:', gal4) print('repr', repr(gal4)) p16 = gal4.getModelPatch(tim, modelMask=mm) mod16 = np.zeros((H, W), np.float32) p16.addTo(mod16) print('Patch:', p16) print('patch sum:', p16.patch.sum()) print('Mod sum:', mod16.sum()) self.assertTrue(np.abs(mod16.sum() - 199.95) < 1e-2) target = (modDev + modExp) print('SAD:', np.sum(np.abs(mod16 - target))) self.assertTrue(np.sum(np.abs(mod16 - target)) < 1e-5) derivs = gal4.getParamDerivatives(tim) print('Derivs:', derivs) self.assertEqual(len(derivs), 12) p17, p18 = gal4.getUnitFluxModelPatches(tim, modelMask=mm) mod17 = np.zeros((H, W), np.float32) mod18 = np.zeros((H, W), np.float32) p17.addTo(mod17) p18.addTo(mod18) print('SAD', np.sum(np.abs(mod17 * 100. - modExp))) print('SAD', np.sum(np.abs(mod18 * 100. - modDev))) self.assertTrue(np.abs(mod17 * 100. - modExp).sum() < 1e-5) self.assertTrue(np.abs(mod18 * 100. - modDev).sum() < 1e-5) # SersicGalaxy # gal5 = SersicGalaxy(pos, bright, shapeExp, SersicIndex(1.)) # # tim.psf = psf0 # # p19 = gal5.getModelPatch(tim, modelMask=mm) # mod19 = np.zeros((H,W), np.float32) # p19.addTo(mod19) # # if ps is not None: # plt.clf() # plt.imshow(mod19, interpolation='nearest', origin='lower') # plt.colorbar() # plt.title('Sersic n=1') # ps.savefig() # # plt.clf() # plt.imshow(mod19 - modExp, interpolation='nearest', origin='lower') # plt.colorbar() # plt.title('Sersic n=1 - EXP') # ps.savefig() # # print('Patch:', p19) # print('patch sum:', p19.patch.sum()) # print('Mod sum:', mod19.sum()) # self.assertTrue(np.abs(mod19.sum() - 100.00) < 1e-2) # target = modExp # # print('SAD:', np.sum(np.abs(mod19 - target))) # # self.assertTrue(np.sum(np.abs(mod19 - target)) < 1e-5) # # gal5.sersicindex.setValue(4.) # gal5.shape = shapeDev # # p20 = gal5.getModelPatch(tim, modelMask=mm) # mod20 = np.zeros((H,W), np.float32) # p20.addTo(mod20) # print('Patch:', p20) # print('patch sum:', p20.patch.sum()) # print('Mod sum:', mod20.sum()) # # if ps is not None: # plt.clf() # plt.imshow(mod20, interpolation='nearest', origin='lower') # plt.colorbar() # plt.title('Sersic n=4') # ps.savefig() # # plt.clf() # plt.imshow(mod20 - modDev, interpolation='nearest', origin='lower') # plt.colorbar() # plt.title('Sersic n=4 - DEV') # ps.savefig() # # self.assertTrue(np.abs(mod20.sum() - 99.95) < 1e-2) # target = modDev # print('SAD:', np.sum(np.abs(mod20 - target))) # self.assertTrue(np.sum(np.abs(mod20 - target)) < 1e-5) # A galaxy that will wrap around from tractor.ellipses import EllipseE mmX = ModelMask(20, 20, 60, 60) shapeX = EllipseE(20., 0.7, 0.7) tim.psf = pixpsf gal6 = DevGalaxy(pos0, bright, shapeX) p21 = gal6.getModelPatch(tim, modelMask=mmX) mod21 = np.zeros((H, W), np.float32) p21.addTo(mod21) if ps is not None: plt.clf() plt.imshow(mod21, interpolation='nearest', origin='lower') plt.colorbar() plt.title('Pixelized PSF') ps.savefig() tim.psf = hybridpsf p22 = gal6.getModelPatch(tim, modelMask=mmX) mod22 = np.zeros((H, W), np.float32) p22.addTo(mod22) # Horizontal slice through the middle of the galaxy m21 = mod21[49, :] m22 = mod22[49, :] if ps is not None: plt.clf() plt.imshow(mod22, interpolation='nearest', origin='lower') plt.colorbar() plt.title('Hybrid PSF') ps.savefig() #print('m22', m22) plt.clf() plt.plot(m21, 'r-') plt.plot(m22, 'b-') plt.yscale('symlog', linthreshy=1e-8) ps.savefig() imx = np.argmax(m22) diff = np.diff(m22[:imx + 1]) # Assert monotonic up to the peak (from the left) # (low-level jitter/wrap-around is allowed) self.assertTrue(np.all(np.logical_or(np.abs(diff) < 1e-9, diff > 0))) diff = np.diff(m22[imx:]) # Assert monotonic decreasing after to the peak # (low-level jitter/wrap-around is allowed) self.assertTrue(np.all(np.logical_or(np.abs(diff) < 1e-9, diff < 0))) # Assert that wrap-around exists for PixelizedPsf model diff = np.diff(m21[:imx + 1]) self.assertFalse(np.all(np.logical_or(np.abs(diff) < 1e-9, diff > 0))) diff = np.diff(m21[imx:]) self.assertFalse(np.all(np.logical_or(np.abs(diff) < 1e-9, diff < 0)))
cat = tractor.getCatalog() mask = ModelMask(0, 0, w, h) mm = [{rex: mask, psf: mask}] tractor.setModelMasks(mm) plt.clf() row = psfimg[:, psfw // 2] * flux row = np.hstack((row, np.zeros(5))) plt.plot(row, 'k.-') from astrometry.util.miscutils import lanczos_filter from scipy.ndimage.filters import correlate1d for mux in [0.1, 0.25, 0.5]: L = 3 Lx = lanczos_filter(L, np.arange(-L, L + 1) + mux) Lx /= Lx.sum() cx = correlate1d(row, Lx, mode='constant') plt.plot(cx, '.-') plt.yscale('symlog', linthreshy=1e-10) ps.savefig() for re in [10., 1, 1e-1, 1e-2, 1e-3, 1e-4, 1e-6, 1e-10]: #for re in [2e-3, 1.05e-3, 1e-3, 0.95e-3, 5e-4]: #for re in np.linspace(0.9e-3, 1.1e-3, 25): rex.pos.x = psf.pos.x = 12. rex.pos.y = psf.pos.y = 16. rex.shape.logre = np.log(re) print('Rex:', rex) cat[0] = rex rexmod = tractor.getModelImage(0)