def test_make_random_models_table(): model = Moffat2D(amplitude=1) param_ranges = { 'x_0': (0, 300), 'y_0': (0, 500), 'gamma': (1, 3), 'alpha': (1.5, 3) } source_table = make_random_models_table(10, param_ranges) # most of the make_model_sources_image options are exercised in the # make_gaussian_sources_image tests image = make_model_sources_image((300, 500), model, source_table) assert image.sum() > 1
def test_moffat_fitting(moffimg): """ Test that the Moffat to be fit in test_psf_adapter is behaving correctly """ from astropy.modeling.fitting import LevMarLSQFitter from astropy.modeling.models import Moffat2D mof, (xg, yg, img) = moffimg # a closeish-but-wrong "guessed Moffat" guess_moffat = Moffat2D(x_0=.1, y_0=-.05, gamma=1.05, amplitude=mof.amplitude*1.06, alpha=4.75) f = LevMarLSQFitter() fit_mof = f(guess_moffat, xg, yg, img) assert_allclose(fit_mof.parameters, mof.parameters, rtol=.01, atol=.0005)
def moffat_psf_integration(self, xloc, yloc, seeing, boxsize=14., scale=0.1, alpha=3.5): ''' Based on Remedy extract.py code from G. Zeimann https://github.com/grzeimann/Remedy/blob/master/extract.py Moffat PSF profile image Parameters ---------- seeing: float FWHM of the Moffat profile boxsize: float Size of image on a side for Moffat profile scale: float Pixel scale for image alpha: float Power index in Moffat profile function Returns ------- zarray: numpy 3d array An array with length 3 for the first axis: PSF image, xgrid, ygrid ''' M = Moffat2D() M.alpha.value = alpha M.gamma.value = 0.5 * seeing / np.sqrt(2**(1. / M.alpha.value) - 1.) xl, xh = (0. - boxsize / 2., 0. + boxsize / 2. + scale) yl, yh = (0. - boxsize / 2., 0. + boxsize / 2. + scale) x, y = (np.arange(xl, xh, scale), np.arange(yl, yh, scale)) xgrid, ygrid = np.meshgrid(x, y) Z = M(xgrid, ygrid) Z = Z / Z.sum() V = xloc * 0. cnt = 0 for xl, yl in zip(xloc, yloc): d = np.sqrt((xgrid - xl)**2 + (ygrid - yl)**2) sel = d <= 0.75 adj = np.pi * 0.75**2 / (sel.sum() * scale**2) V[cnt] = np.sum(Z[sel]) * adj cnt += 1 return V
def test_prfadapter_integrates(adapterkwargs): from scipy.integrate import dblquad mof = Moffat2D(gamma=1.5, alpha=4.8) if not adapterkwargs['renormalize_psf']: mof = normalize_moffat(mof) prf1 = PRFAdapter(mof, **adapterkwargs) # first check that the PRF over a central grid ends up summing to the # integrand over the whole PSF xg, yg = np.meshgrid(*([(-1, 0, 1)]*2)) evalmod = prf1(xg, yg) if adapterkwargs['renormalize_psf']: mof = normalize_moffat(mof) integrando, itol = dblquad(mof, -1.5, 1.5, lambda x: -1.5, lambda x: 1.5) assert_allclose(np.sum(evalmod), integrando, atol=itol * 10)
def test_prepare_psf_model(moffimg, prepkwargs, tols): """ Test that prepare_psf_model behaves as expected for fitting (don't worry about full-on psf photometry for now) """ from astropy.modeling.fitting import LevMarLSQFitter from astropy.modeling.models import Moffat2D mof, (xg, yg, img) = moffimg f = LevMarLSQFitter() # a close-but-wrong "guessed Moffat" guess_moffat = Moffat2D(x_0=.1, y_0=-.05, gamma=1.01, amplitude=mof.amplitude * 1.01, alpha=4.79) if prepkwargs['renormalize_psf']: # definitely very wrong, so this ensures the re-normalization # stuff works guess_moffat.amplitude = 5. if prepkwargs['xname'] is None: guess_moffat.x_0 = 0 if prepkwargs['yname'] is None: guess_moffat.y_0 = 0 psfmod = prepare_psf_model(guess_moffat, **prepkwargs) xytol, fluxtol = tols fit_psfmod = f(psfmod, xg, yg, img) if xytol is not None: assert np.abs(getattr(fit_psfmod, fit_psfmod.xname)) < xytol assert np.abs(getattr(fit_psfmod, fit_psfmod.yname)) < xytol if fluxtol is not None: assert np.abs(1 - getattr(fit_psfmod, fit_psfmod.fluxname)) < fluxtol # ensure the amplitude and shape parameters did *not* change assert fit_psfmod.psfmodel.gamma == guess_moffat.gamma assert fit_psfmod.psfmodel.alpha == guess_moffat.alpha if prepkwargs['fluxname'] is None: assert fit_psfmod.psfmodel.amplitude == guess_moffat.amplitude
def test_psf_photometry_moffat(): """ Test psf_photometry with Moffat PSF model from Astropy. """ psf = Moffat2D(1. / (2 * np.pi * GAUSSIAN_WIDTH ** 2), PSF_SIZE // 2, PSF_SIZE // 2, 1, 1) psf = prepare_psf_model(psf, xname='x_0', yname='y_0', renormalize_psf=False) basic_phot = BasicPSFPhotometry(group_maker=DAOGroup(2), bkg_estimator=None, psf_model=psf, fitshape=7) f = basic_phot(image=image, init_guesses=INTAB) f.pprint(max_width=-1) for n in ['x', 'y']: assert_allclose(f[n + '_0'], f[n + '_fit'], rtol=1e-3) # image was created with a gaussian, so flux won't match exactly assert_allclose(f['flux_0'], f['flux_fit'], rtol=1e-1)
def moffimg(): """ This fixture requires scipy so don't call it from non-scipy tests """ from scipy import integrate from astropy.modeling.models import Moffat2D mof = Moffat2D(alpha=4.8) # this is the analytic value needed to get a total flux of 1 mof.amplitude = (mof.alpha-1)/(np.pi*mof.gamma**2) # first make sure it really is normalized assert (1 - integrate.dblquad(mof, -10, 10, lambda x: -10, lambda x: 10)[0]) < 1e-6 # now create an "image" of the PSF xg, yg = np.meshgrid(*([np.linspace(-2, 2, 100)]*2)) return mof, (xg, yg, mof(xg, yg))
def moffat_psf(self, seeing, boxsize, scale, alpha=3.5): """ Moffat PSF profile image Parameters ---------- seeing: float FWHM of the Moffat profile boxsize: float Size of image on a side for Moffat profile scale: float Pixel scale for image alpha: float Power index in Moffat profile function Returns ------- zarray: numpy 3d array An array with length 3 for the first axis: PSF image, xgrid, ygrid """ M = Moffat2D() M.alpha.value = alpha M.gamma.value = 0.5 * seeing / np.sqrt(2**(1.0 / M.alpha.value) - 1.0) xl, xh = (0.0 - boxsize / 2.0, 0.0 + boxsize / 2.0 + scale) yl, yh = (0.0 - boxsize / 2.0, 0.0 + boxsize / 2.0 + scale) x, y = (np.arange(xl, xh, scale), np.arange(yl, yh, scale)) xgrid, ygrid = np.meshgrid(x, y) Z = self.moffat_psf_integration(xgrid.ravel(), ygrid.ravel(), seeing, boxsize=boxsize + 1.5, alpha=alpha) Z = np.reshape(Z, xgrid.shape) zarray = np.array([Z, xgrid, ygrid]) #zarray[0] /= zarray[0].sum() return zarray