def test_realspace_distorted_convolve(): """ The same as above, but both the Moffat and the Box are sheared, rotated and shifted to stress test the code that deals with this for real-space convolutions that wouldn't be tested otherwise. """ import time t1 = time.time() fwhm_backwards_compatible = 1.0927449310213702 psf = galsim.SBMoffat(beta=1.5, half_light_radius=1, trunc=4 * fwhm_backwards_compatible, flux=1) #psf = galsim.SBMoffat(beta=1.5, fwhm=fwhm_backwards_compatible, #trunc=4*fwhm_backwards_compatible, flux=1) psf.applyShear(galsim.Shear(g1=0.11, g2=0.17)._shear) psf.applyRotation(13 * galsim.degrees) pixel = galsim.SBBox(xw=0.2, yw=0.2, flux=1.) pixel.applyShear(galsim.Shear(g1=0.2, g2=0.0)._shear) pixel.applyRotation(80 * galsim.degrees) pixel.applyShift(0.13, 0.27) conv = galsim.SBConvolve([psf, pixel], real_space=True) # Note: Using an image created from Maple "exact" calculations. saved_img = galsim.fits.read( os.path.join(imgdir, "moffat_pixel_distorted.fits")) img = galsim.ImageF(saved_img.bounds, scale=0.2) conv.draw(img.view()) printval(img, saved_img) np.testing.assert_array_almost_equal( img.array, saved_img.array, 5, err_msg= "distorted Moffat convolved with distorted Box disagrees with expected result" ) # Repeat with the GSObject version of this: psf = galsim.Moffat(beta=1.5, half_light_radius=1, trunc=4 * fwhm_backwards_compatible, flux=1) #psf = galsim.Moffat(beta=1.5, fwhm=fwhm_backwards_compatible, #trunc=4*fwhm_backwards_compatible, flux=1) psf.applyShear(g1=0.11, g2=0.17) psf.applyRotation(13 * galsim.degrees) pixel = galsim.Pixel(xw=0.2, yw=0.2, flux=1.) pixel.applyShear(g1=0.2, g2=0.0) pixel.applyRotation(80 * galsim.degrees) pixel.applyShift(0.13, 0.27) # NB: real-space is chosen automatically conv = galsim.Convolve([psf, pixel]) conv.draw(img, dx=0.2, normalization="surface brightness", use_true_center=False) np.testing.assert_array_almost_equal( img.array, saved_img.array, 5, err_msg= "Using Convolve([psf,pixel]) (distorted) disagrees with expected result" ) # Check with default_params conv = galsim.Convolve([psf, pixel], gsparams=default_params) conv.draw(img, dx=0.2, normalization="surface brightness", use_true_center=False) np.testing.assert_array_almost_equal( img.array, saved_img.array, 5, err_msg= "Using Convolve([psf,pixel]) (distorted) with default_params disagrees with " "expected result") conv = galsim.Convolve([psf, pixel], gsparams=galsim.GSParams()) conv.draw(img, dx=0.2, normalization="surface brightness", use_true_center=False) np.testing.assert_array_almost_equal( img.array, saved_img.array, 5, err_msg= "Using Convolve([psf,pixel]) (distorted) with GSParams() disagrees with " "expected result") # Other ways to do the convolution: conv = galsim.Convolve(psf, pixel) conv.draw(img, dx=0.2, normalization="surface brightness", use_true_center=False) np.testing.assert_array_almost_equal( img.array, saved_img.array, 5, err_msg= "Using Convolve(psf,pixel) (distorted) disagrees with expected result") # The real-space convolution algorithm is not (trivially) independent of the order of # the two things being convolved. So check the opposite order. conv = galsim.Convolve([pixel, psf]) conv.draw(img, dx=0.2, normalization="surface brightness", use_true_center=False) np.testing.assert_array_almost_equal( img.array, saved_img.array, 5, err_msg= "Using Convolve([pixel,psf]) (distorted) disagrees with expected result" ) t2 = time.time() print 'time for %s = %.2f' % (funcname(), t2 - t1)
def test_exponential(): """Test the generation of a specific exp profile against a known result. """ re = 1.0 # Note the factor below should really be 1.6783469900166605, but the value of 1.67839 is # retained here as it was used by SBParse to generate the original known result (this changed # in commit b77eb05ab42ecd31bc8ca03f1c0ae4ee0bc0a78b. # The value of this test for regression purposes is not harmed by retaining the old scaling, it # just means that the half light radius chosen for the test is not really 1, but 0.999974... r0 = re / 1.67839 savedImg = galsim.fits.read(os.path.join(imgdir, "exp_1.fits")) dx = 0.2 myImg = galsim.ImageF(savedImg.bounds, scale=dx) myImg.setCenter(0, 0) expon = galsim.Exponential(flux=1., scale_radius=r0) expon.drawImage(myImg, scale=dx, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 5, err_msg="Using GSObject Exponential disagrees with expected result") # Check with default_params expon = galsim.Exponential(flux=1., scale_radius=r0, gsparams=default_params) expon.drawImage(myImg, scale=dx, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 5, err_msg= "Using GSObject Exponential with default_params disagrees with expected result" ) expon = galsim.Exponential(flux=1., scale_radius=r0, gsparams=galsim.GSParams()) expon.drawImage(myImg, scale=dx, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 5, err_msg= "Using GSObject Exponential with GSParams() disagrees with expected result" ) # Use non-unity values. expon = galsim.Exponential(flux=1.7, scale_radius=0.91) gsp = galsim.GSParams(xvalue_accuracy=1.e-8, kvalue_accuracy=1.e-8) expon2 = galsim.Exponential(flux=1.7, scale_radius=0.91, gsparams=gsp) assert expon2 != expon assert expon2 == expon.withGSParams(gsp) check_basic(expon, "Exponential") # Test photon shooting. do_shoot(expon, myImg, "Exponential") # Test kvalues do_kvalue(expon, myImg, "Exponential") # Check picklability do_pickle(expon, lambda x: x.drawImage(method='no_pixel')) do_pickle(expon) # Should raise an exception if both scale_radius and half_light_radius are provided. assert_raises(TypeError, galsim.Exponential, scale_radius=3, half_light_radius=1) # Or neither. assert_raises(TypeError, galsim.Exponential)
def test_ne(): # Use some very forgiving settings to speed up this test. We're not actually going to draw # any images (other than internally the PSF), so should be okay. gsp1 = galsim.GSParams(maxk_threshold=5.e-2, folding_threshold=5e-2, kvalue_accuracy=1e-3, xvalue_accuracy=1e-3) gsp2 = galsim.GSParams(maxk_threshold=5.1e-2, folding_threshold=5e-2, kvalue_accuracy=1e-3, xvalue_accuracy=1e-3) pupil_plane_im = galsim.fits.read(os.path.join(imgdir, pp_file)) # Params include: lam_over_diam, (lam/diam), aberrations by name, aberrations by list, nstruts, # strut_thick, strut_angle, obscuration, oversampling, pad_factor, flux, gsparams, # circular_pupil, interpolant, pupil_plane_im, pupil_angle, scale_unit objs = [ galsim.OpticalPSF(lam_over_diam=1.0, gsparams=gsp1), galsim.OpticalPSF(lam_over_diam=1.0, gsparams=gsp2), galsim.OpticalPSF(lam=1.0, diam=1.0, gsparams=gsp1), galsim.OpticalPSF(lam=1.0, diam=1.0, scale_unit=galsim.arcmin, gsparams=gsp1), galsim.OpticalPSF(lam_over_diam=1.0, defocus=0.1, gsparams=gsp1), galsim.OpticalPSF(lam_over_diam=1.0, aberrations=[0, 0, 0, 0, 0.2], gsparams=gsp1), galsim.OpticalPSF(lam_over_diam=1.0, nstruts=2, gsparams=gsp1), galsim.OpticalPSF(lam_over_diam=1.0, nstruts=2, strut_thick=0.3, gsparams=gsp1), galsim.OpticalPSF(lam_over_diam=1.0, nstruts=2, strut_angle=10. * galsim.degrees, gsparams=gsp1), galsim.OpticalPSF(lam_over_diam=1.0, obscuration=0.5, gsparams=gsp1), galsim.OpticalPSF(lam_over_diam=1.0, oversampling=2.0, gsparams=gsp1), galsim.OpticalPSF(lam_over_diam=1.0, pad_factor=2.0, gsparams=gsp1), galsim.OpticalPSF(lam_over_diam=1.0, flux=2.0, gsparams=gsp1), galsim.OpticalPSF(lam_over_diam=1.0, circular_pupil=False, gsparams=gsp1), galsim.OpticalPSF(lam_over_diam=1.0, interpolant='Linear', gsparams=gsp1) ] if __name__ == do_slow_tests: objs += [ galsim.OpticalPSF(lam_over_diam=1.0, pupil_plane_im=pupil_plane_im, gsparams=gsp1, suppress_warning=True), galsim.OpticalPSF(lam_over_diam=1.0, pupil_plane_im=pupil_plane_im, gsparams=gsp1, pupil_angle=10 * galsim.degrees, suppress_warning=True) ] all_obj_diff(objs)
def test_tophat(): """Test the generation of a specific tophat profile against a known result. """ savedImg = galsim.fits.read(os.path.join(imgdir, "tophat_101.fits")) myImg = galsim.ImageF(savedImg.bounds, scale=0.2) myImg.setCenter(0,0) test_flux = 1.8 # There are numerical issues with using radius = 1, since many points are right on the edge # of the circle. e.g. (+-1,0), (0,+-1), (+-0.6,+-0.8), (+-0.8,+-0.6). And in practice, some # of these end up getting drawn and not others, which means it's not a good choice for a unit # test since it wouldn't be any less correct for a different subset of these points to be # drawn. Using r = 1.01 solves this problem and makes the result symmetric. tophat = galsim.TopHat(radius=1.01, flux=1) tophat.drawImage(myImg, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 5, err_msg="Using GSObject TopHat disagrees with expected result") np.testing.assert_array_equal( tophat.radius, 1.01, err_msg="TopHat radius returned wrong value") # Check with default_params tophat = galsim.TopHat(radius=1.01, flux=1, gsparams=default_params) tophat.drawImage(myImg, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 5, err_msg="Using GSObject TopHat with default_params disagrees with expected result") tophat = galsim.TopHat(radius=1.01, flux=1, gsparams=galsim.GSParams()) tophat.drawImage(myImg, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 5, err_msg="Using GSObject TopHat with GSParams() disagrees with expected result") # Use non-unity values. tophat = galsim.TopHat(flux=1.7, radius=2.3) gsp = galsim.GSParams(xvalue_accuracy=1.e-8, kvalue_accuracy=1.e-8) tophat2 = galsim.TopHat(flux=1.7, radius=2.3, gsparams=gsp) assert tophat2 != tophat assert tophat2 == tophat.withGSParams(gsp) # Test photon shooting. do_shoot(tophat,myImg,"TopHat") # Test shoot and kvalue scale = 0.2939 im = galsim.ImageF(16,16, scale=scale) # The choices of radius here are fairly specific. If the edge of the circle comes too close # to the center of one of the pixels, then the test will fail, since the Fourier draw method # will blur the edge a bit and give some flux to that pixel. for radius in [ 1.2, 0.93, 2.11 ]: tophat = galsim.TopHat(radius=radius, flux=test_flux) check_basic(tophat, "TopHat with radius = %f"%radius) do_shoot(tophat,im,"TopHat with radius = %f"%radius) do_kvalue(tophat,im,"TopHat with radius = %f"%radius) # This is also a profile that may be convolved using real space convolution, so test that. conv = galsim.Convolve(tophat, galsim.Pixel(scale=scale), real_space=True) check_basic(conv, "TopHat convolved with pixel in real space", approx_maxsb=True, scale=0.2) do_kvalue(conv,im, "TopHat convolved with pixel in real space") cen = galsim.PositionD(0, 0) np.testing.assert_equal(tophat.centroid, cen) np.testing.assert_almost_equal(tophat.kValue(cen), (1+0j) * test_flux) np.testing.assert_almost_equal(tophat.flux, test_flux) np.testing.assert_almost_equal(tophat.xValue(cen), tophat.max_sb) np.testing.assert_almost_equal(tophat.xValue(radius-0.001, 0.), tophat.max_sb) np.testing.assert_almost_equal(tophat.xValue(0., radius-0.001), tophat.max_sb) np.testing.assert_almost_equal(tophat.xValue(radius+0.001, 0.), 0.) np.testing.assert_almost_equal(tophat.xValue(0., radius+0.001), 0.) # Check picklability do_pickle(tophat, lambda x: x.drawImage(method='no_pixel')) do_pickle(tophat) do_pickle(galsim.TopHat(1)) # Check sheared tophat the same way tophat = galsim.TopHat(radius=1.2, flux=test_flux) # Again, the test is very sensitive to the choice of shear here. Most values fail because # some pixel center gets too close to the resulting ellipse for the fourier draw to match # the real-space draw at the required accuracy. tophat = tophat.shear(galsim.Shear(g1=0.15, g2=-0.33)) check_basic(tophat, "Sheared TopHat") do_shoot(tophat,im, "Sheared TopHat") do_kvalue(tophat,im, "Sheared TopHat") cen = galsim.PositionD(0, 0) np.testing.assert_equal(tophat.centroid, cen) np.testing.assert_almost_equal(tophat.kValue(cen), (1+0j) * test_flux) np.testing.assert_almost_equal(tophat.flux, test_flux) np.testing.assert_almost_equal(tophat.xValue(cen), tophat.max_sb) # Check picklability do_pickle(tophat, lambda x: x.drawImage(method='no_pixel')) do_pickle(tophat) # Check real-space convolution of the sheared tophat. conv = galsim.Convolve(tophat, galsim.Pixel(scale=scale), real_space=True) check_basic(conv, "Sheared TopHat convolved with pixel in real space", approx_maxsb=True, scale=0.2) do_kvalue(conv,im, "Sheared TopHat convolved with pixel in real space")
def main(argv): logging.basicConfig(format="%(message)s", level=logging.INFO, stream=sys.stdout) logger = logging.getLogger("demo7") ### Make output directory if not already present. if not os.path.isdir('output'): os.mkdir('output') file_name = os.path.join('output', 'cube_phot.fits.gz') scaleimg_y = [] scaleimg_x_DFT = [] scaleimg_x_Photon = [] ranges = np.linspace(2.e-6, 2.e-1, 5) for num in ranges: ### Define some parameters we'll use below. random_seed = 553728 sky_level = 1.e4 # ADU / arcsec^2 pixel_scale = .28 # arcsec* nx = 64 ny = 64 gal_flux_min = 1.e1 # Range for galaxy flux gal_flux_max = 1.e5 gal_hlr_min = 0.3 # arcsec gal_hlr_max = 1.3 # arcsec gal_e_min = 0. # Range for ellipticity gal_e_max = 0.8 psf_fwhm = 0.65 # arcsec # We encapsulate these parameters with an object called GSParams. The default values # are intended to be accurate enough for normal precision shear tests, without sacrificing # too much speed.Any PSF or galaxy object can be given a gsparams argument on construction that can # have different values to make the calculation more or less accurate (typically trading # off for speed or memory). gsparams = galsim.GSParams( folding_threshold= 1.e-2, # maximum fractional flux that may be folded around edge of FFT maxk_threshold= num, # k-values less than this may be excluded off edge of FFT xvalue_accuracy= 1.e-4, # approximations in real space aim to be this accurate kvalue_accuracy= 1.e-4, # approximations in fourier space aim to be this accurate shoot_accuracy= 1.e-4, # approximations in photon shooting aim to be this accurate minimum_fft_size=64) # minimum size of ffts logger.info('Starting psf') # Make the PSF profiles: ### psf 1 psf1 = galsim.Gaussian(fwhm=psf_fwhm, gsparams=gsparams) ### psf 2 psf2 = galsim.Moffat(fwhm=psf_fwhm, beta=2.4, gsparams=gsparams) ### psf 3 psf3_inner = galsim.Gaussian(fwhm=psf_fwhm, flux=0.8, gsparams=gsparams) psf3_outer = galsim.Gaussian(fwhm=2 * psf_fwhm, flux=0.2, gsparams=gsparams) psf3 = psf3_inner + psf3_outer atmos = galsim.Gaussian(fwhm=psf_fwhm, gsparams=gsparams) ### defining the telescope # The OpticalPSF and set of Zernike values chosen below correspond to a reasonably well aligned, # smallish ~0.3m / 12 inch diameter telescope with a central obscuration of ~0.12m or 5 inches # diameter, being used in optical wavebands. aberrations = [0.0] * 12 # Set the initial size. aberrations[4] = 0.06 # Noll index 4 = Defocus aberrations[5:7] = [0.12, -0.08] # Noll index 5,6 = Astigmatism aberrations[7:9] = [0.07, 0.04] # Noll index 7,8 = Coma aberrations[11] = -0.13 # Noll index 11 = Spherical optics = galsim.OpticalPSF(lam_over_diam=0.6 * psf_fwhm, obscuration=0.4, aberrations=aberrations, gsparams=gsparams) ### psf 4 psf4 = galsim.Convolve( [atmos, optics]) # Convolve inherits the gsparams from the first # item in the list. (Or you can supply a gsparams # argument explicitly if you want to override this.) atmos = galsim.Kolmogorov(fwhm=psf_fwhm, gsparams=gsparams) optics = galsim.Airy(lam_over_diam=0.3 * psf_fwhm, gsparams=gsparams) ### psf 5 psf5 = galsim.Convolve([atmos, optics]) ### define where to keep the psfs info psfs = [psf1, psf2, psf3, psf4, psf5] psf_names = [ "Gaussian", "Moffat", "Double Gaussian", "OpticalPSF", "Kolmogorov * Airy" ] psf_times = [0, 0, 0, 0, 0] psf_fft_times = [0, 0, 0, 0, 0] psf_phot_times = [0, 0, 0, 0, 0] # Make the galaxy profiles: ### gal 1 gal1 = galsim.Gaussian(half_light_radius=1, gsparams=gsparams) ### gal 2 gal2 = galsim.Exponential(half_light_radius=1, gsparams=gsparams) ### gal 3 gal3 = galsim.DeVaucouleurs(half_light_radius=1, gsparams=gsparams) ### gal 4 gal4 = galsim.Sersic(half_light_radius=1, n=2.5, gsparams=gsparams) bulge = galsim.Sersic(half_light_radius=0.7, n=3.2, trunc=8.5, gsparams=gsparams) disk = galsim.Sersic(half_light_radius=1.2, n=1.5, gsparams=gsparams) ### gal 5 gal5 = 0.4 * bulge + 0.6 * disk # Net half-light radius is only approximate for this one. ### define where to keep the galaxys info gals = [gal1, gal2, gal3, gal4, gal5] gal_names = [ "Gaussian", "Exponential", "Devaucouleurs", "n=2.5 Sersic", "Bulge + Disk" ] gal_times = [0, 0, 0, 0, 0] gal_fft_times = [0, 0, 0, 0, 0] gal_phot_times = [0, 0, 0, 0, 0] ### initial time conditions # Other times to keep track of: setup_times = 0 fft_times = 0 phot_times = 0 noise_times = 0 # Loop over combinations of psf, gal, and make 4 random choices for flux, size, shape. all_images = [] k = 0 n = [] x_DFT = [] x_Photon = [] y = [] all_fluxes = np.linspace(gal_flux_min, gal_flux_max, 100) ### will loop through the numbers (amount) of psfs for ipsf in range(len(psfs)): ### calls on the 5 psfs and their names psf = psfs[ipsf] psf_name = psf_names[ipsf] ### outputs the psf number and the psf information needed to create an object logger.info('psf %d: %s', ipsf + 1, psf) logger.debug('repr = %r', psf) ### will loop through the numbers (amount) of galaxies for igal in range(len(gals)): ### calls on the 5 galaxies and their names gal = gals[igal] gal_name = gal_names[igal] ### outputs the psf number and the psf information needed to create an object logger.info(' galaxy %d: %s', igal + 1, gal) logger.debug(' repr = %r', gal) ### will loop though 0,1,2,3 flux, size, and shape to create 4 images for each ### combination of galaxy and psf for i in range(4): logger.debug(' Start work on image %d', i) all_fluxes_i = all_fluxes[i] image, t1, t2, t3, t4, t5, t6, k, flux, hlr, gal_shape, y_i, psfs, gals, file_name = func( file_name, random_seed, pixel_scale, nx, ny, sky_level, gal_flux_min, gal_flux_max, gal_hlr_min, gal_hlr_max, gal_e_min, gal_e_max, psf_fwhm, gsparams, psf1, psf2, psf3_inner, psf3_outer, psf3, atmos, aberrations, psf4, optics, psf5, psfs, psf_names, psf_times, psf_fft_times, psf_phot_times, gal1, gal2, gal3, gal4, bulge, disk, gal5, gals, gal_names, gal_times, gal_fft_times, gal_phot_times, setup_times, fft_times, phot_times, noise_times, k, all_fluxes_i, psf, psf_name, gal, gal_name) ### Store that into the list of all images all_images += [image] y = np.append(y, y_i) ### add an itteration though the loop for the psf and galaxy combination images k = k + 1 ### express the flux,hlr, and ellip of each image combination,4 for every loop logger.info( ' %d: flux = %.2e, hlr = %.2f, ellip = (%.2f,%.2f)', k, flux, hlr, gal_shape.getE1(), gal_shape.getE2()) logger.debug(' Times: %f, %f, %f, %f, %f', t2 - t1, t3 - t2, t4 - t3, t5 - t4, t6 - t5) psf_times[ipsf] += t6 - t1 psf_fft_times[ipsf] += t3 - t2 psf_phot_times[ipsf] += t5 - t4 gal_times[igal] += t6 - t1 gal_fft_times[igal] += t3 - t2 gal_phot_times[igal] += t5 - t4 setup_times += t2 - t1 fft_times += t3 - t2 phot_times += t5 - t4 noise_times += t4 - t3 + t6 - t5 x_DFT = np.append(x_DFT, gal_fft_times[igal]) x_Photon = np.append(x_Photon, gal_phot_times[igal]) #### flux and time of each galaxy profile with each PSF scaleimg_y = np.append(scaleimg_y, y) scaleimg_x_DFT = np.append(scaleimg_x_DFT, x_DFT) scaleimg_x_Photon = np.append(scaleimg_x_Photon, x_Photon) #### [FOR FIGURES 1-5] the DFT and Photon-Shooting time for the first psf and 5 galaxy profile all at flux 10 x1_DFT_1 = (scaleimg_x_DFT[0], scaleimg_x_DFT[100], scaleimg_x_DFT[200], scaleimg_x_DFT[300], scaleimg_x_DFT[400]) x1_DFT_2 = (scaleimg_x_DFT[4], scaleimg_x_DFT[104], scaleimg_x_DFT[204], scaleimg_x_DFT[304], scaleimg_x_DFT[404]) x1_DFT_3 = (scaleimg_x_DFT[8], scaleimg_x_DFT[108], scaleimg_x_DFT[208], scaleimg_x_DFT[308], scaleimg_x_DFT[408]) x1_DFT_4 = (scaleimg_x_DFT[12], scaleimg_x_DFT[112], scaleimg_x_DFT[212], scaleimg_x_DFT[312], scaleimg_x_DFT[412]) x1_DFT_5 = (scaleimg_x_DFT[16], scaleimg_x_DFT[116], scaleimg_x_DFT[216], scaleimg_x_DFT[316], scaleimg_x_DFT[416]) x1_Photon_1 = (scaleimg_x_Photon[0], scaleimg_x_Photon[100], scaleimg_x_Photon[200], scaleimg_x_Photon[300], scaleimg_x_Photon[400]) x1_Photon_2 = (scaleimg_x_Photon[4], scaleimg_x_Photon[104], scaleimg_x_Photon[204], scaleimg_x_Photon[304], scaleimg_x_Photon[404]) x1_Photon_3 = (scaleimg_x_Photon[8], scaleimg_x_Photon[108], scaleimg_x_Photon[208], scaleimg_x_Photon[308], scaleimg_x_Photon[408]) x1_Photon_4 = (scaleimg_x_Photon[12], scaleimg_x_Photon[112], scaleimg_x_Photon[212], scaleimg_x_Photon[312], scaleimg_x_Photon[412]) x1_Photon_5 = (scaleimg_x_Photon[16], scaleimg_x_Photon[116], scaleimg_x_Photon[216], scaleimg_x_Photon[316], scaleimg_x_Photon[416]) #### [FOR FIGURES 6-10] for the first PSF and 5 galaxy profile for all flux at 1020 x2_DFT_1 = (scaleimg_x_DFT[1], scaleimg_x_DFT[101], scaleimg_x_DFT[201], scaleimg_x_DFT[301], scaleimg_x_DFT[401]) x2_DFT_2 = (scaleimg_x_DFT[5], scaleimg_x_DFT[105], scaleimg_x_DFT[205], scaleimg_x_DFT[305], scaleimg_x_DFT[405]) x2_DFT_3 = (scaleimg_x_DFT[9], scaleimg_x_DFT[109], scaleimg_x_DFT[209], scaleimg_x_DFT[309], scaleimg_x_DFT[409]) x2_DFT_4 = (scaleimg_x_DFT[13], scaleimg_x_DFT[113], scaleimg_x_DFT[213], scaleimg_x_DFT[313], scaleimg_x_DFT[413]) x2_DFT_5 = (scaleimg_x_DFT[17], scaleimg_x_DFT[117], scaleimg_x_DFT[217], scaleimg_x_DFT[317], scaleimg_x_DFT[417]) x2_Photon_1 = (scaleimg_x_Photon[1], scaleimg_x_Photon[101], scaleimg_x_Photon[201], scaleimg_x_Photon[301], scaleimg_x_Photon[401]) x2_Photon_2 = (scaleimg_x_Photon[5], scaleimg_x_Photon[105], scaleimg_x_Photon[205], scaleimg_x_Photon[305], scaleimg_x_Photon[405]) x2_Photon_3 = (scaleimg_x_Photon[9], scaleimg_x_Photon[109], scaleimg_x_Photon[209], scaleimg_x_Photon[309], scaleimg_x_Photon[409]) x2_Photon_4 = (scaleimg_x_Photon[13], scaleimg_x_Photon[113], scaleimg_x_Photon[213], scaleimg_x_Photon[313], scaleimg_x_Photon[413]) x2_Photon_5 = (scaleimg_x_Photon[17], scaleimg_x_Photon[117], scaleimg_x_Photon[217], scaleimg_x_Photon[317], scaleimg_x_Photon[417]) #### [FOR FIGURES 1-5] the DFT and Photon-Shooting time for the first psf and 5 galaxy profile all at flux 10 ###subtraction of points xnew_1 = [] xnew_2 = [] xnew_3 = [] xnew_4 = [] xnew_5 = [] for a, b, c, d, e, f, g, h, i, j in zip(x1_DFT_1, x1_Photon_1, x1_DFT_2, x1_Photon_2, x1_DFT_3, x1_Photon_3, x1_DFT_4, x1_Photon_4, x1_DFT_5, x1_Photon_5): x1 = a - b x2 = c - d x3 = e - f x4 = g - h x5 = i - j xnew_1 = np.append(xnew_1, x1) xnew_2 = np.append(xnew_2, x2) xnew_3 = np.append(xnew_3, x3) xnew_4 = np.append(xnew_4, x4) xnew_5 = np.append(xnew_5, x5) #### [FOR FIGURES 6-10] for the first PSF and 5 galaxy profile for all flux at 1020 xnew_6 = [] xnew_7 = [] xnew_8 = [] xnew_9 = [] xnew_10 = [] for a, b, c, d, e, f, g, h, i, j in zip(x2_DFT_1, x2_Photon_1, x2_DFT_2, x2_Photon_2, x2_DFT_3, x2_Photon_3, x2_DFT_4, x2_Photon_4, x2_DFT_5, x2_Photon_5): x1 = a - b x2 = c - d x3 = e - f x4 = g - h x5 = i - j xnew_6 = np.append(xnew_6, x1) xnew_7 = np.append(xnew_7, x2) xnew_8 = np.append(xnew_8, x3) xnew_9 = np.append(xnew_9, x4) xnew_10 = np.append(xnew_10, x5) y = [0, 0, 0, 0, 0] #fig1 f, (ax1, ax2) = plt.subplots(2, sharex=True, sharey=True) l1, = ax1.plot(ranges, x1_DFT_1, 'b-', label='l1') l2, = ax1.plot(ranges, x1_Photon_1, 'g-', label='l2') l3, = ax1.plot(ranges, y, 'r--', label='l3') plt.legend([l1, l2, l3], ['DFT', 'Photon', 'Y=0'], loc='upper right') ax1.set_title('Gaussian PSF with Gaussian Galaxy Profile at flux=10') l4, = ax2.plot(ranges, xnew_1, 'y-', label='l4') l5, = ax2.plot(ranges, y, 'r--', label='l5') plt.legend([l4, l5], ['DFT - Photon', 'Y=0'], loc='upper right') plt.xlabel('pixel scale') plt.ylabel('time') f.subplots_adjust(hspace=0) plt.setp([a.get_xticklabels() for a in f.axes[:-1]], visible=False) plt.savefig('maxk_1.png') #fig2 f, (ax1, ax2) = plt.subplots(2, sharex=True, sharey=True) l1, = ax1.plot(ranges, x1_DFT_2, 'b-', label='l1') l2, = ax1.plot(ranges, x1_Photon_2, 'g-', label='l2') l3, = ax1.plot(ranges, y, 'r--', label='l3') plt.legend([l1, l2, l3], ['DFT', 'Photon', 'Y=0'], loc='upper right') ax1.set_title('Gaussian PSF with Exponential Galaxy Profile at flux=10') l4, = ax2.plot(ranges, xnew_2, 'y-', label='l4') l5, = ax2.plot(ranges, y, 'r--', label='l5') plt.legend([l4, l5], ['DFT - Photon', 'Y=0'], loc='upper right') plt.xlabel('pixel scale') plt.ylabel('time') plt.legend(loc='best') f.subplots_adjust(hspace=0) plt.setp([a.get_xticklabels() for a in f.axes[:-1]], visible=False) plt.savefig('maxk_2.png') #fig3 f, (ax1, ax2) = plt.subplots(2, sharex=True, sharey=True) l1, = ax1.plot(ranges, x1_DFT_3, 'b-', label='l1') l2, = ax1.plot(ranges, x1_Photon_3, 'g-', label='l2') l3, = ax1.plot(ranges, y, 'r--', label='l3') plt.legend([l1, l2, l3], ['DFT', 'Photon', 'Y=0'], loc='upper right') ax1.set_title('Gaussian PSF with Devaucouleurs Galaxy Profile at flux=10') l4, = ax2.plot(ranges, xnew_3, 'y-', label='l4') l5, = ax2.plot(ranges, y, 'r--', label='l5') plt.legend([l4, l5], ['DFT - Photon', 'Y=0'], loc='upper right') plt.xlabel('pixel scale') plt.ylabel('time') plt.legend(loc='best') f.subplots_adjust(hspace=0) plt.setp([a.get_xticklabels() for a in f.axes[:-1]], visible=False) plt.savefig('maxk_3.png') #fig4 f, (ax1, ax2) = plt.subplots(2, sharex=True, sharey=True) l1, = ax1.plot(ranges, x1_DFT_4, 'b-', label='l1') l2, = ax1.plot(ranges, x1_Photon_4, 'g-', label='l2') l3, = ax1.plot(ranges, y, 'r--', label='l3') plt.legend([l1, l2, l3], ['DFT', 'Photon', 'Y=0'], loc='upper right') ax1.set_title('Gaussian PSF with n=2.5 Sersic Galaxy Profile at flux=10') l4, = ax2.plot(ranges, xnew_4, 'y-', label='l4') l5, = ax2.plot(ranges, y, 'r--', label='l5') plt.legend([l4, l5], ['DFT - Photon', 'Y=0'], loc='upper right') plt.xlabel('pixel scale') plt.ylabel('time') plt.legend(loc='best') f.subplots_adjust(hspace=0) plt.setp([a.get_xticklabels() for a in f.axes[:-1]], visible=False) plt.savefig('maxk_4.png') #fig5 f, (ax1, ax2) = plt.subplots(2, sharex=True, sharey=True) l1, = ax1.plot(ranges, x1_DFT_5, 'b-', label='l1') l2, = ax1.plot(ranges, x1_Photon_5, 'g-', label='l2') l3, = ax1.plot(ranges, y, 'r--', label='l3') plt.legend([l1, l2, l3], ['DFT', 'Photon', 'Y=0'], loc='upper right') ax1.set_title('Gaussian PSF with Bulge + Disk Galaxy Profile at flux=10') l4, = ax2.plot(ranges, xnew_5, 'y-', label='l4') l5, = ax2.plot(ranges, y, 'r--', label='l5') plt.legend([l4, l5], ['DFT - Photon', 'Y=0'], loc='upper right') plt.xlabel('pixel scale') plt.ylabel('time') plt.legend(loc='best') f.subplots_adjust(hspace=0) plt.setp([a.get_xticklabels() for a in f.axes[:-1]], visible=False) plt.savefig('maxk_5.png') #fig6 f, (ax1, ax2) = plt.subplots(2, sharex=True, sharey=True) l1, = ax1.plot(ranges, x2_DFT_1, 'b-', label='l1') l2, = ax1.plot(ranges, x2_Photon_1, 'g-', label='l2') l3, = ax1.plot(ranges, y, 'r--', label='l3') plt.legend([l1, l2, l3], ['DFT', 'Photon', 'Y=0'], loc='upper right') ax1.set_title('Gaussian PSF with Bulge + Disk Galaxy Profile at flux=1020') l4, = ax2.plot(ranges, xnew_6, 'y-', label='l4') l5, = ax2.plot(ranges, y, 'r--', label='l5') plt.legend([l4, l5], ['DFT - Photon', 'Y=0'], loc='upper right') plt.xlabel('pixel scale') plt.ylabel('time') plt.legend(loc='best') f.subplots_adjust(hspace=0) plt.setp([a.get_xticklabels() for a in f.axes[:-1]], visible=False) plt.savefig('maxk_6.png') #fig7 f, (ax1, ax2) = plt.subplots(2, sharex=True, sharey=True) l1, = ax1.plot(ranges, x2_DFT_2, 'b-', label='l1') l2, = ax1.plot(ranges, x2_Photon_2, 'g-', label='l2') l3, = ax1.plot(ranges, y, 'r--', label='l3') plt.legend([l1, l2, l3], ['DFT', 'Photon', 'Y=0'], loc='upper right') ax1.set_title('Gaussian PSF with Bulge + Disk Galaxy Profile at flux=1020') l4, = ax2.plot(ranges, xnew_7, 'y-', label='l4') l5, = ax2.plot(ranges, y, 'r--', label='l5') plt.legend([l4, l5], ['DFT - Photon', 'Y=0'], loc='upper right') plt.xlabel('pixel scale') plt.ylabel('time') plt.legend(loc='best') f.subplots_adjust(hspace=0) plt.setp([a.get_xticklabels() for a in f.axes[:-1]], visible=False) plt.savefig('maxk_7.png') #fig8 f, (ax1, ax2) = plt.subplots(2, sharex=True, sharey=True) l1, = ax1.plot(ranges, x2_DFT_3, 'b-', label='l1') l2, = ax1.plot(ranges, x2_Photon_3, 'g-', label='l2') l3, = ax1.plot(ranges, y, 'r--', label='l3') plt.legend([l1, l2, l3], ['DFT', 'Photon', 'Y=0'], loc='upper right') ax1.set_title('Gaussian PSF with Bulge + Disk Galaxy Profile at flux=1020') l4, = ax2.plot(ranges, xnew_8, 'y-', label='l4') l5, = ax2.plot(ranges, y, 'r--', label='l5') plt.legend([l4, l5], ['DFT - Photon', 'Y=0'], loc='upper right') plt.xlabel('pixel scale') plt.ylabel('time') plt.legend(loc='best') f.subplots_adjust(hspace=0) plt.setp([a.get_xticklabels() for a in f.axes[:-1]], visible=False) plt.savefig('maxk_8.png') #fig9 f, (ax1, ax2) = plt.subplots(2, sharex=True, sharey=True) l1, = ax1.plot(ranges, x2_DFT_4, 'b-', label='l1') l2, = ax1.plot(ranges, x2_Photon_4, 'g-', label='l2') l3, = ax1.plot(ranges, y, 'r--', label='l3') plt.legend([l1, l2, l3], ['DFT', 'Photon', 'Y=0'], loc='upper right') ax1.set_title('Gaussian PSF with Bulge + Disk Galaxy Profile at flux=1020') l4, = ax2.plot(ranges, xnew_9, 'y-', label='l4') l5, = ax2.plot(ranges, y, 'r--', label='l5') plt.legend([l4, l5], ['DFT - Photon', 'Y=0'], loc='upper right') plt.xlabel('pixel scale') plt.ylabel('time') plt.legend(loc='best') f.subplots_adjust(hspace=0) plt.setp([a.get_xticklabels() for a in f.axes[:-1]], visible=False) plt.savefig('maxk_9.png') #fig10 f, (ax1, ax2) = plt.subplots(2, sharex=True, sharey=True) l1, = ax1.plot(ranges, x2_DFT_5, 'b-', label='l1') l2, = ax1.plot(ranges, x2_Photon_5, 'g-', label='l2') l3, = ax1.plot(ranges, y, 'r--', label='l3') plt.legend([l1, l2, l3], ['DFT', 'Photon', 'Y=0'], loc='upper right') ax1.set_title('Gaussian PSF with Bulge + Disk Galaxy Profile at flux=1020') l4, = ax2.plot(ranges, xnew_10, 'y-', label='l4') l5, = ax2.plot(ranges, y, 'r--', label='l5') plt.legend([l4, l5], ['DFT - Photon', 'Y=0'], loc='upper right') plt.xlabel('pixel scale') plt.ylabel('time') plt.legend(loc='best') f.subplots_adjust(hspace=0) plt.setp([a.get_xticklabels() for a in f.axes[:-1]], visible=False) plt.savefig('maxk_10.png') plt.show() ### breakdown of psf and galaxy types as well as overal timing statistics logger.info('') logger.info('Some timing statistics:') logger.info(' Total time for setup steps = %f', setup_times) logger.info(' Total time for regular fft drawing = %f', fft_times) logger.info(' Total time for photon shooting = %f', phot_times) logger.info(' Total time for adding noise = %f', noise_times) logger.info('') logger.info('Breakdown by PSF type:') for ipsf in range(len(psfs)): logger.info(' %s: Total time = %f (fft: %f, phot: %f)', psf_names[ipsf], psf_times[ipsf], psf_fft_times[ipsf], psf_phot_times[ipsf]) logger.info('') logger.info('Breakdown by Galaxy type:') for igal in range(len(gals)): logger.info(' %s: Total time = %f (fft: %f, phot: %f)', gal_names[igal], gal_times[igal], gal_fft_times[igal], gal_phot_times[igal]) logger.info('') ### compress into a gzip file and save a a cube galsim.fits.writeCube(all_images, file_name, compression='gzip') logger.info('Wrote fft image to fits data cube %r', file_name)
self.draw_s() ) # Here, it's called for each catalog, and supercedes the galaxy values. out.update(self.draw_psf()) # Idem, one random PSF for each catalog out.update(self.draw_constants()) return out sp = EuclidLike_statshear(name="figstamps", snc_type=0, shear=0.0) stampsize = 32 psfcat = momentsml.tools.io.readpickle( os.path.join(config.workdir, "psfcat.pkl")) gsparams = galsim.GSParams(maximum_fft_size=20320) # Simulating images momentsml.sim.run.multi(simdir=config.simdir, simparams=sp, drawcatkwargs={ "n": 24, "nc": 4, "stampsize": stampsize }, drawimgkwargs={ "gsparams": gsparams, "sersiccut": 5.0 }, psfcat=psfcat, psfselect="random",
def test_sersic(): """Test the generation of a specific Sersic profile against a known result. """ # Test Sersic savedImg = galsim.fits.read(os.path.join(imgdir, "sersic_3_1.fits")) dx = 0.2 myImg = galsim.ImageF(savedImg.bounds, scale=dx) myImg.setCenter(0,0) sersic = galsim.Sersic(n=3, flux=1, half_light_radius=1) sersic.drawImage(myImg,scale=dx, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 5, err_msg="Using GSObject Sersic disagrees with expected result") # Check with default_params sersic = galsim.Sersic(n=3, flux=1, half_light_radius=1, gsparams=default_params) sersic.drawImage(myImg,scale=dx, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 5, err_msg="Using GSObject Sersic with default_params disagrees with expected result") sersic = galsim.Sersic(n=3, flux=1, half_light_radius=1, gsparams=galsim.GSParams()) sersic.drawImage(myImg,scale=dx, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 5, err_msg="Using GSObject Sersic with GSParams() disagrees with expected result") # Use non-unity values. sersic = galsim.Sersic(n=3, flux=1.7, half_light_radius=2.3) gsp = galsim.GSParams(xvalue_accuracy=1.e-8, kvalue_accuracy=1.e-8) sersic2 = galsim.Sersic(n=3, flux=1.7, half_light_radius=2.3, gsparams=gsp) assert sersic2 != sersic assert sersic2 == sersic.withGSParams(gsp) check_basic(sersic, "Sersic") # Test photon shooting. # Convolve with a small gaussian to smooth out the central peak. sersic2 = galsim.Convolve(sersic, galsim.Gaussian(sigma=0.3)) do_shoot(sersic2,myImg,"Sersic") # Test kvalues do_kvalue(sersic,myImg,"Sersic") # Check picklability do_pickle(sersic, lambda x: x.drawImage(method='no_pixel')) do_pickle(sersic) # Now repeat everything using a truncation. (Above had no truncation.) # Test Truncated Sersic # Don't use an integer truncation, since we don't want the truncation line to pass directly # through the center of a pixel where numerical rounding differences may decide whether the # value is zero or not. # This regression test compares to an image built using the code base at 82259f0 savedImg = galsim.fits.read(os.path.join(imgdir, "sersic_3_1_10.fits")) myImg = galsim.ImageF(savedImg.bounds, scale=dx) myImg.setCenter(0,0) sersic = galsim.Sersic(n=3, flux=1, half_light_radius=1, trunc=9.99) sersic.drawImage(myImg,scale=dx, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 5, err_msg="Using truncated GSObject Sersic disagrees with expected result") # Use non-unity values. test_flux = 1.8 sersic = galsim.Sersic(n=3, flux=test_flux, half_light_radius=2.3, trunc=5.9) cen = galsim.PositionD(0, 0) np.testing.assert_equal(sersic.centroid, cen) np.testing.assert_almost_equal(sersic.kValue(cen), (1+0j) * test_flux) np.testing.assert_almost_equal(sersic.flux, test_flux) np.testing.assert_almost_equal(sersic.xValue(cen), sersic.max_sb) check_basic(sersic, "Truncated Sersic") # Test photon shooting. # Convolve with a small gaussian to smooth out the central peak. sersic2 = galsim.Convolve(sersic, galsim.Gaussian(sigma=0.3)) do_shoot(sersic2,myImg,"Truncated Sersic") # Test kvalues do_kvalue(sersic,myImg, "Truncated Sersic") # Check picklability do_pickle(sersic, lambda x: x.drawImage(method='no_pixel')) do_pickle(sersic) # Check for normalization consistencies with kValue checks. xValues tested in test_sersic_radii. # For half-light radius specified truncated Sersic, with flux_untruncated flag set sersic = galsim.Sersic(n=3, flux=test_flux, half_light_radius=1, trunc=10, flux_untruncated=True) do_kvalue(sersic,myImg, "Truncated Sersic w/ flux_untruncated, half-light radius specified") # For scale radius specified Sersic sersic = galsim.Sersic(n=3, flux=test_flux, scale_radius=0.05) do_kvalue(sersic,myImg, "Sersic w/ scale radius specified") # For scale radius specified truncated Sersic sersic = galsim.Sersic(n=3, flux=test_flux, scale_radius=0.05, trunc=10) do_kvalue(sersic,myImg, "Truncated Sersic w/ scale radius specified") # For scale radius specified truncated Sersic, with flux_untruncated flag set sersic = galsim.Sersic(n=3, flux=test_flux, scale_radius=0.05, trunc=10, flux_untruncated=True) do_kvalue(sersic,myImg, "Truncated Sersic w/ flux_untruncated, scale radius specified") # Test severely truncated Sersic sersic = galsim.Sersic(n=4, flux=test_flux, half_light_radius=1, trunc=1.45) do_kvalue(sersic,myImg, "Severely truncated n=4 Sersic") # Should raise an exception if both scale_radius and half_light_radius are provided. assert_raises(TypeError, galsim.Sersic, n=1.2, scale_radius=3, half_light_radius=1) assert_raises(TypeError, galsim.Sersic, n=1.2) assert_raises(TypeError, galsim.DeVaucouleurs, scale_radius=3, half_light_radius=1) assert_raises(TypeError, galsim.DeVaucouleurs) # Allowed range is [0.3, 6.2] assert_raises(ValueError, galsim.Sersic, n=0.2, scale_radius=3) assert_raises(ValueError, galsim.Sersic, n=6.3, scale_radius=3) # trunc must be > sqrt(2) * hlr assert_raises(ValueError, galsim.Sersic, n=3, half_light_radius=1, trunc=1.4) assert_raises(ValueError, galsim.DeVaucouleurs, half_light_radius=1, trunc=1.4) # Other errors assert_raises(TypeError, galsim.Sersic, scale_radius=3) assert_raises(ValueError, galsim.Sersic, n=3, scale_radius=3, trunc=-1) assert_raises(ValueError, galsim.DeVaucouleurs, scale_radius=3, trunc=-1)
def test_gaussian(): """Test the generation of a specific Gaussian profile against a known result. """ savedImg = galsim.fits.read(os.path.join(imgdir, "gauss_1.fits")) savedImg.setCenter(0,0) dx = 0.2 myImg = galsim.ImageF(savedImg.bounds, scale=dx) myImg.setCenter(0,0) gauss = galsim.Gaussian(flux=1, sigma=1) # Reference images were made with old centering, which is equivalent to use_true_center=False. myImg = gauss.drawImage(myImg, scale=dx, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 5, err_msg="Using GSObject Gaussian disagrees with expected result") np.testing.assert_almost_equal( myImg.array.sum(dtype=float) *dx**2, myImg.added_flux, 5, err_msg="Gaussian profile GSObject::draw returned wrong added_flux") # Check a non-square image print(myImg.bounds) recImg = galsim.ImageF(45,66) recImg.setCenter(0,0) recImg = gauss.drawImage(recImg, scale=dx, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( recImg[savedImg.bounds].array, savedImg.array, 5, err_msg="Drawing Gaussian on non-square image disagrees with expected result") np.testing.assert_almost_equal( recImg.array.sum(dtype=float) *dx**2, recImg.added_flux, 5, err_msg="Gaussian profile GSObject::draw on non-square image returned wrong added_flux") # Check with default_params gauss = galsim.Gaussian(flux=1, sigma=1, gsparams=default_params) gauss.drawImage(myImg,scale=0.2, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 5, err_msg="Using GSObject Gaussian with default_params disagrees with expected result") gauss = galsim.Gaussian(flux=1, sigma=1, gsparams=galsim.GSParams()) gauss.drawImage(myImg,scale=0.2, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 5, err_msg="Using GSObject Gaussian with GSParams() disagrees with expected result") # Use non-unity values. gauss = galsim.Gaussian(flux=1.7, sigma=2.3) gsp = galsim.GSParams(xvalue_accuracy=1.e-8, kvalue_accuracy=1.e-8) gauss2 = galsim.Gaussian(flux=1.7, sigma=2.3, gsparams=gsp) assert gauss2 != gauss assert gauss2 == gauss.withGSParams(gsp) check_basic(gauss, "Gaussian") # Test photon shooting. do_shoot(gauss,myImg,"Gaussian") # Test kvalues do_kvalue(gauss,myImg,"Gaussian") # Check picklability do_pickle(galsim.GSParams()) # Check GSParams explicitly here too. do_pickle(galsim.GSParams( minimum_fft_size = 12, maximum_fft_size = 40, folding_threshold = 1.e-1, maxk_threshold = 2.e-1, kvalue_accuracy = 3.e-1, xvalue_accuracy = 4.e-1, shoot_accuracy = 5.e-1, realspace_relerr = 6.e-1, realspace_abserr = 7.e-1, integration_relerr = 8.e-1, integration_abserr = 9.e-1)) do_pickle(gauss, lambda x: x.drawImage(method='no_pixel')) do_pickle(gauss) # Should raise an exception if >=2 radii are provided. assert_raises(TypeError, galsim.Gaussian, sigma=3, half_light_radius=1, fwhm=2) assert_raises(TypeError, galsim.Gaussian, half_light_radius=1, fwhm=2) assert_raises(TypeError, galsim.Gaussian, sigma=3, fwhm=2) assert_raises(TypeError, galsim.Gaussian, sigma=3, half_light_radius=1) # Or none. assert_raises(TypeError, galsim.Gaussian) # Finally, test the noise property for things that don't have any noise set. assert gauss.noise is None # And accessing the attribute from the class should indicate that it is a lazyproperty assert 'lazy_property' in str(galsim.GSObject._noise) # And check that trying to use GSObject directly is an error. assert_raises(NotImplementedError, galsim.GSObject)
from scipy import optimize import galsim import galsim.wfirst as wfirst filters = wfirst.getBandpasses(AB_zeropoint=True) N = 1 k = 64 base_size = 1.5 * k + 3 ## odd, so peak flux is in one pixel pixel_scale = 0.11 / N flux_dict = {} new_params = galsim.hsm.HSMParams(max_amoment=60000000, max_mom2_iter=1000000000, max_moment_nsig2=25) big_fft_params = galsim.GSParams(maximum_fft_size=int(512 * k)) e = (0., 0.) index_dict = {} i = 0 bandpass = ['Y106', 'J129', 'F184', 'H158'] mags = [18.3] for lam in bandpass: for mag in mags: index_dict[i] = (lam, mag) i += 1 def flux_function(index): lam, mag = index_dict[index] f = filters[lam]
def test_autoconvolve(): """Test that auto-convolution works the same as convolution with itself. """ import time t1 = time.time() mySBP = galsim.SBMoffat(beta=3.8, fwhm=1.3, flux=5) myConv = galsim.SBConvolve([mySBP, mySBP]) myImg1 = galsim.ImageF(80, 80, scale=0.4) myConv.draw(myImg1.view()) myAutoConv = galsim.SBAutoConvolve(mySBP) myImg2 = galsim.ImageF(80, 80, scale=0.4) myAutoConv.draw(myImg2.view()) printval(myImg1, myImg2) np.testing.assert_array_almost_equal( myImg1.array, myImg2.array, 4, err_msg= "Moffat convolved with self disagrees with SBAutoConvolve result") # Repeat with the GSObject version of this: psf = galsim.Moffat(beta=3.8, fwhm=1.3, flux=5) conv = galsim.Convolve([psf, psf]) conv.draw(myImg1) conv2 = galsim.AutoConvolve(psf) conv2.draw(myImg2) printval(myImg1, myImg2) np.testing.assert_array_almost_equal( myImg1.array, myImg2.array, 4, err_msg="Moffat convolved with self disagrees with AutoConvolve result" ) # Check with default_params conv = galsim.AutoConvolve(psf, gsparams=default_params) conv.draw(myImg1) np.testing.assert_array_almost_equal( myImg1.array, myImg2.array, 4, err_msg= "Using AutoConvolve with default_params disagrees with expected result" ) conv = galsim.AutoConvolve(psf, gsparams=galsim.GSParams()) conv.draw(myImg1) np.testing.assert_array_almost_equal( myImg1.array, myImg2.array, 4, err_msg= "Using AutoConvolve with GSParams() disagrees with expected result") # For a symmetric profile, AutoCorrelate is the same thing: conv2 = galsim.AutoCorrelate(psf) conv2.draw(myImg2) printval(myImg1, myImg2) np.testing.assert_array_almost_equal( myImg1.array, myImg2.array, 4, err_msg="Moffat convolved with self disagrees with AutoCorrelate result" ) # And check AutoCorrelate with gsparams: conv2 = galsim.AutoCorrelate(psf, gsparams=default_params) conv2.draw(myImg1) np.testing.assert_array_almost_equal( myImg1.array, myImg2.array, 4, err_msg= "Using AutoCorrelate with default_params disagrees with expected result" ) conv2 = galsim.AutoCorrelate(psf, gsparams=galsim.GSParams()) conv2.draw(myImg1) np.testing.assert_array_almost_equal( myImg1.array, myImg2.array, 4, err_msg= "Using AutoCorrelate with GSParams() disagrees with expected result") # Test photon shooting. do_shoot(conv2, myImg2, "AutoConvolve(Moffat)") # Also check AutoConvolve with an asymmetric profile. # (AutoCorrelate with this profile is done below...) obj1 = galsim.Gaussian(sigma=3., flux=4) obj1.applyShift(-0.2, -0.4) obj2 = galsim.Gaussian(sigma=6., flux=1.3) obj2.applyShift(0.3, 0.3) add = galsim.Add(obj1, obj2) conv = galsim.Convolve([add, add]) conv.draw(myImg1) corr = galsim.AutoConvolve(add) corr.draw(myImg2) printval(myImg1, myImg2) np.testing.assert_array_almost_equal( myImg1.array, myImg2.array, 4, err_msg= "Asymmetric sum of Gaussians convolved with self disagrees with " + "AutoConvolve result") t2 = time.time() print 'time for %s = %.2f' % (funcname(), t2 - t1)
def make_a_galaxy(ud, this_im_wcs, psf, affine): """ Method to make a single galaxy object and return stamp for injecting into larger GalSim image """ # Choose a random RA, Dec around the sky_center. # Note that for this to come out close to a square shape, we need to account for the # cos(dec) part of the metric: ds^2 = dr^2 + r^2 d(dec)^2 + r^2 cos^2(dec) d(ra)^2 # So need to calculate dec first. center_dec = this_im_wcs.center.dec center_ra = this_im_wcs.center.ra dec = center_dec + (ud() - 0.3) * image_ysize_arcsec * galsim.arcsec ra = center_ra + ( ud() - 0.3) * image_xsize_arcsec / numpy.cos(dec) * galsim.arcsec world_pos = galsim.CelestialCoord(ra, dec) # We will need the image position as well, so use the wcs to get that image_pos = this_im_wcs.posToImage(world_pos) # We also need this in the tangent plane, which we call "world coordinates" here, # since the PowerSpectrum class is really defined on that plane, not in (ra,dec). # This is still an x/y corrdinate uv_pos = affine.toWorld(image_pos) # Draw the redshift from a power law distribution: N(f) ~ f^-2 # TAKEN FROM DEMO9.PY redshift_dist = galsim.DistDeviate(ud, function=lambda x: x**-2, x_min=0.3, x_max=1.0) gal_z = redshift_dist() try: # Get the reduced shears and magnification at this point nfw_shear, mu = nfw_lensing(nfw, uv_pos, gal_z) g1 = nfw_shear.g1 g2 = nfw_shear.g2 binom = galsim.BinomialDeviate(ud, N=1, p=0.5) real = binom() if real: # For real galaxies, we will want to whiten the noise in the image (below). gal = cosmos_cat.makeGalaxy(gal_type='real', rng=ud, noise_pad_size=20) else: gal = cosmos_cat.makeGalaxy(gal_type='parametric', rng=ud) # Apply a random rotation theta = ud() * 2.0 * numpy.pi * galsim.radians gal = gal.rotate(theta) # Rescale the flux to match the observed A2218 flux. The flux of gal can't be edited directly, # so we resort to the following kludge. # This automatically scales up the noise variance by flux_scaling**2. gal_flux_dist = galsim.DistDeviate( ud, function= '/Users/jemcclea/Research/GalSim/examples/output/empirical_psfs/v3/gal_flux300_prob.txt' ) gal_flux = gal_flux_dist() flux_scaling = gal_flux / gal.flux * (exp_time / 300.) gal *= flux_scaling # Apply the cosmological (reduced) shear and magnification at this position using a single # GSObject method. try: gal = gal.lens(g1, g2, mu) except: print("could not lens galaxy, setting default values...") g1 = 0.0 g2 = 0.0 mu = 1.0 # Generate PSF at location of galaxy # Convolve galaxy image with the PSF. this_psf = psf.getPSF(image_pos) #final_psf=galsim.Convolve(this_psf,optics) gsp = galsim.GSParams(maximum_fft_size=16384) final = galsim.Convolve([this_psf, gal], gsparams=gsp) # Account for the fractional part of the position # cf. demo9.py for an explanation of this nominal position stuff. x_nominal = image_pos.x + 0.5 y_nominal = image_pos.y + 0.5 ix_nominal = int(math.floor(x_nominal + 0.5)) iy_nominal = int(math.floor(y_nominal + 0.5)) dx = x_nominal - ix_nominal dy = y_nominal - iy_nominal offset = galsim.PositionD(dx, dy) position = [ix_nominal, iy_nominal, ra.deg, dec.deg] except: pdb.set_trace() # We use method='no_pixel' here because the SDSS PSF image that we are using includes the # pixel response already. stamp = final.drawImage(wcs=this_im_wcs.local(image_pos), offset=offset, method='no_pixel') # If desired, one can also draw the PSF and output its moments too, as: # psf_stamp = psf.drawImage(scale=0.206, offset=offset, method='no_pixel') # Recenter the stamp at the desired position: stamp.setCenter(ix_nominal, iy_nominal) new_variance = 0.0 if real: if True: # We use the symmetrizing option here. new_variance = stamp.symmetrizeNoise(final.noise, 8) else: # Here is how you would do it if you wanted to fully whiten the image. new_variance = stamp.whitenNoise(final.noise) print("noise variance is %f" % new_variance) galaxy_truth = truth() galaxy_truth.ra = ra.deg galaxy_truth.dec = dec.deg galaxy_truth.x = ix_nominal galaxy_truth.y = iy_nominal galaxy_truth.g1 = g1 galaxy_truth.g2 = g2 galaxy_truth.mu = mu galaxy_truth.z = gal_z galaxy_truth.flux = stamp.added_flux galaxy_truth.variance = new_variance return stamp, galaxy_truth
def test_add(): """Test the addition of two rescaled Gaussian profiles against a known double Gaussian result. """ import time t1 = time.time() mySBP = galsim.SBGaussian(flux=0.75, sigma=1) mySBP2 = galsim.SBGaussian(flux=0.25, sigma=3) myAdd = galsim.SBAdd([mySBP, mySBP2]) savedImg = galsim.fits.read(os.path.join(imgdir, "double_gaussian.fits")) myImg = galsim.ImageF(savedImg.bounds, scale=0.2) myAdd.draw(myImg.view()) printval(myImg, savedImg) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 5, err_msg= "Addition of two rescaled Gaussian profiles disagrees with expected result" ) # Repeat with the GSObject version of this: gauss1 = galsim.Gaussian(flux=0.75, sigma=1) gauss2 = galsim.Gaussian(flux=0.25, sigma=3) sum = galsim.Add(gauss1, gauss2) sum.draw(myImg, dx=0.2, normalization="surface brightness", use_true_center=False) printval(myImg, savedImg) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 5, err_msg= "Using GSObject Add(gauss1,gauss2) disagrees with expected result") # Check with default_params sum = galsim.Add(gauss1, gauss2, gsparams=default_params) sum.draw(myImg, dx=0.2, normalization="surface brightness", use_true_center=False) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 5, err_msg= "Using GSObject Add(gauss1,gauss2) with default_params disagrees with " "expected result") sum = galsim.Add(gauss1, gauss2, gsparams=galsim.GSParams()) sum.draw(myImg, dx=0.2, normalization="surface brightness", use_true_center=False) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 5, err_msg= "Using GSObject Add(gauss1,gauss2) with GSParams() disagrees with " "expected result") # Other ways to do the sum: sum = gauss1 + gauss2 sum.draw(myImg, dx=0.2, normalization="surface brightness", use_true_center=False) printval(myImg, savedImg) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 5, err_msg="Using GSObject gauss1 + gauss2 disagrees with expected result" ) sum = gauss1.copy() sum += gauss2 sum.draw(myImg, dx=0.2, normalization="surface brightness", use_true_center=False) printval(myImg, savedImg) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 5, err_msg= "Using GSObject sum = gauss1; sum += gauss2 disagrees with expected result" ) sum = galsim.Add([gauss1, gauss2]) sum.draw(myImg, dx=0.2, normalization="surface brightness", use_true_center=False) printval(myImg, savedImg) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 5, err_msg= "Using GSObject Add([gauss1,gauss2]) disagrees with expected result") gauss1 = galsim.Gaussian(flux=1, sigma=1) gauss2 = galsim.Gaussian(flux=1, sigma=3) sum = 0.75 * gauss1 + 0.25 * gauss2 sum.draw(myImg, dx=0.2, normalization="surface brightness", use_true_center=False) printval(myImg, savedImg) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 5, err_msg= "Using GSObject 0.75 * gauss1 + 0.25 * gauss2 disagrees with expected result" ) sum = 0.75 * gauss1 sum += 0.25 * gauss2 sum.draw(myImg, dx=0.2, normalization="surface brightness", use_true_center=False) printval(myImg, savedImg) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 5, err_msg= "Using GSObject sum += 0.25 * gauss2 disagrees with expected result") # Test photon shooting. do_shoot(sum, myImg, "sum of 2 Gaussians") # Test kvalues do_kvalue(sum, "sum of 2 Gaussians") t2 = time.time() print 'time for %s = %.2f' % (funcname(), t2 - t1)
def test_realspace_shearconvolve(): """Test the real-space convolution of a sheared Gaussian and a Box SBProfile against a known result. """ import time t1 = time.time() psf = galsim.SBGaussian(flux=1, sigma=1) e1 = 0.04 e2 = 0.0 myShear = galsim.Shear(e1=e1, e2=e2) psf.applyShear(myShear._shear) pix = galsim.SBBox(xw=0.2, yw=0.2, flux=1.) conv = galsim.SBConvolve([psf, pix], real_space=True) saved_img = galsim.fits.read( os.path.join(imgdir, "gauss_smallshear_convolve_box.fits")) img = galsim.ImageF(saved_img.bounds, scale=0.2) conv.draw(img.view()) printval(img, saved_img) np.testing.assert_array_almost_equal( img.array, saved_img.array, 5, err_msg= "Sheared Gaussian convolved with Box SBProfile disagrees with expected result" ) # Repeat with the GSObject version of this: psf = galsim.Gaussian(flux=1, sigma=1) psf.applyShear(e1=e1, e2=e2) pixel = galsim.Pixel(xw=0.2, yw=0.2, flux=1.) conv = galsim.Convolve([psf, pixel], real_space=True) conv.draw(img, dx=0.2, normalization="surface brightness", use_true_center=False) np.testing.assert_array_almost_equal( img.array, saved_img.array, 5, err_msg= "Using GSObject Convolve([psf,pixel]) disagrees with expected result") # Check with default_params conv = galsim.Convolve([psf, pixel], real_space=True, gsparams=default_params) conv.draw(img, dx=0.2, normalization="surface brightness", use_true_center=False) np.testing.assert_array_almost_equal( img.array, saved_img.array, 5, err_msg= "Using GSObject Convolve([psf,pixel]) with default_params disagrees with " "expected result") conv = galsim.Convolve([psf, pixel], real_space=True, gsparams=galsim.GSParams()) conv.draw(img, dx=0.2, normalization="surface brightness", use_true_center=False) np.testing.assert_array_almost_equal( img.array, saved_img.array, 5, err_msg= "Using GSObject Convolve([psf,pixel]) with GSParams() disagrees with " "expected result") # Other ways to do the convolution: conv = galsim.Convolve(psf, pixel, real_space=True) conv.draw(img, dx=0.2, normalization="surface brightness", use_true_center=False) np.testing.assert_array_almost_equal( img.array, saved_img.array, 5, err_msg= "Using GSObject Convolve(psf,pixel) disagrees with expected result") # The real-space convolution algorithm is not (trivially) independent of the order of # the two things being convolved. So check the opposite order. conv = galsim.Convolve([pixel, psf], real_space=True) conv.draw(img, dx=0.2, normalization="surface brightness", use_true_center=False) np.testing.assert_array_almost_equal( img.array, saved_img.array, 5, err_msg= "Using GSObject Convolve([pixel,psf]) disagrees with expected result") t2 = time.time() print 'time for %s = %.2f' % (funcname(), t2 - t1)
def test_convolve(): """Test the convolution of a Moffat and a Box SBProfile against a known result. """ import time t1 = time.time() # Code was formerly: # mySBP = galsim.SBMoffat(beta=1.5, truncationFWHM=4, flux=1, half_light_radius=1) # # ...but this is no longer quite so simple since we changed the handling of trunc to be in # physical units. However, the same profile can be constructed using # fwhm=1.0927449310213702, # as calculated by interval bisection in devutils/external/calculate_moffat_radii.py fwhm_backwards_compatible = 1.0927449310213702 mySBP = galsim.SBMoffat(beta=1.5, fwhm=fwhm_backwards_compatible, trunc=4 * fwhm_backwards_compatible, flux=1) mySBP2 = galsim.SBBox(xw=0.2, yw=0.2, flux=1.) myConv = galsim.SBConvolve([mySBP, mySBP2]) # Using an exact Maple calculation for the comparison. Only accurate to 4 decimal places. savedImg = galsim.fits.read(os.path.join(imgdir, "moffat_pixel.fits")) myImg = galsim.ImageF(savedImg.bounds, scale=0.2) myConv.draw(myImg.view()) printval(myImg, savedImg) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 4, err_msg= "Moffat convolved with Box SBProfile disagrees with expected result") # Repeat with the GSObject version of this: psf = galsim.Moffat(beta=1.5, fwhm=fwhm_backwards_compatible, trunc=4 * fwhm_backwards_compatible, flux=1) pixel = galsim.Pixel(xw=0.2, yw=0.2, flux=1.) # Note: Since both of these have hard edges, GalSim wants to do this with real_space=True. # Here we are intentionally tesing the Fourier convolution, so we want to suppress the # warning that GalSim emits. import warnings with warnings.catch_warnings(): warnings.simplefilter("ignore") # We'll do the real space convolution below conv = galsim.Convolve([psf, pixel], real_space=False) conv.draw(myImg, dx=0.2, normalization="surface brightness", use_true_center=False) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 4, err_msg= "Using GSObject Convolve([psf,pixel]) disagrees with expected result" ) # Other ways to do the convolution: conv = galsim.Convolve(psf, pixel, real_space=False) conv.draw(myImg, dx=0.2, normalization="surface brightness", use_true_center=False) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 4, err_msg= "Using GSObject Convolve(psf,pixel) disagrees with expected result" ) # Check with default_params conv = galsim.Convolve([psf, pixel], real_space=False, gsparams=default_params) conv.draw(myImg, dx=0.2, normalization="surface brightness", use_true_center=False) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 4, err_msg= "Using GSObject Convolve([psf,pixel]) with default_params disagrees with" "expected result") conv = galsim.Convolve([psf, pixel], real_space=False, gsparams=galsim.GSParams()) conv.draw(myImg, dx=0.2, normalization="surface brightness", use_true_center=False) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 4, err_msg= "Using GSObject Convolve([psf,pixel]) with GSParams() disagrees with" "expected result") # Test photon shooting. do_shoot(conv, myImg, "Moffat * Pixel") t2 = time.time() print 'time for %s = %.2f' % (funcname(), t2 - t1)
def test_psf_config(): """Test building the two PSF types using the config layer. """ data_dir = 'des_data' psfex_file = "DECam_00154912_12_psfcat.psf" fitpsf_file = "DECam_00154912_12_fitpsf.fits" wcs_file = "DECam_00154912_12_header.fits" image_pos = galsim.PositionD(123.45, 543.21) config = { 'input': { 'des_shapelet': { 'dir': data_dir, 'file_name': fitpsf_file }, 'des_psfex': [ { 'dir': data_dir, 'file_name': psfex_file }, { 'dir': data_dir, 'file_name': psfex_file, 'image_file_name': wcs_file }, ] }, 'psf1': { 'type': 'DES_Shapelet' }, 'psf2': { 'type': 'DES_PSFEx', 'num': 0 }, 'psf3': { 'type': 'DES_PSFEx', 'num': 1 }, 'psf4': { 'type': 'DES_Shapelet', 'image_pos': galsim.PositionD(567, 789), 'flux': 179, 'gsparams': { 'folding_threshold': 1.e-4 } }, 'psf5': { 'type': 'DES_PSFEx', 'image_pos': galsim.PositionD(789, 567), 'flux': 388, 'gsparams': { 'folding_threshold': 1.e-4 } }, 'bad1': { 'type': 'DES_Shapelet', 'image_pos': galsim.PositionD(5670, 789) }, # This would normally be set by the config processing. Set it manually here. 'image_pos': image_pos, } galsim.config.ProcessInput(config) psf1a = galsim.config.BuildGSObject(config, 'psf1')[0] fitpsf = galsim.des.DES_Shapelet(fitpsf_file, dir=data_dir) psf1b = fitpsf.getPSF(image_pos) gsobject_compare(psf1a, psf1b) psf2a = galsim.config.BuildGSObject(config, 'psf2')[0] psfex0 = galsim.des.DES_PSFEx(psfex_file, dir=data_dir) psf2b = psfex0.getPSF(image_pos) gsobject_compare(psf2a, psf2b) psf3a = galsim.config.BuildGSObject(config, 'psf3')[0] psfex1 = galsim.des.DES_PSFEx(psfex_file, wcs_file, dir=data_dir) psf3b = psfex1.getPSF(image_pos) gsobject_compare(psf3a, psf3b) gsparams = galsim.GSParams(folding_threshold=1.e-4) psf4a = galsim.config.BuildGSObject(config, 'psf4')[0] psf4b = fitpsf.getPSF(galsim.PositionD(567, 789), gsparams=gsparams).withFlux(179) gsobject_compare(psf4a, psf4b) # Insert a wcs for thes last one. config['wcs'] = galsim.FitsWCS(os.path.join(data_dir, wcs_file)) config = galsim.config.CleanConfig(config) galsim.config.ProcessInput(config) psfex2 = galsim.des.DES_PSFEx(psfex_file, dir=data_dir, wcs=config['wcs']) psf5a = galsim.config.BuildGSObject(config, 'psf5')[0] psf5b = psfex2.getPSF(galsim.PositionD(789, 567), gsparams=gsparams).withFlux(388) gsobject_compare(psf5a, psf5b) del config['image_pos'] galsim.config.RemoveCurrent(config) with assert_raises(galsim.GalSimConfigError): galsim.config.BuildGSObject(config, 'psf1')[0] with assert_raises(galsim.GalSimConfigError): galsim.config.BuildGSObject(config, 'psf2')[0] with assert_raises(galsim.config.gsobject.SkipThisObject): galsim.config.BuildGSObject(config, 'bad1')[0]
def test_gsparams(): """Test withGSParams with some non-default gsparams """ obj1 = galsim.Exponential(half_light_radius=1.7) obj2 = galsim.Pixel(scale=0.2) gsp = galsim.GSParams(folding_threshold=1.e-4, maxk_threshold=1.e-4, maximum_fft_size=1.e4) gsp2 = galsim.GSParams(folding_threshold=1.e-2, maxk_threshold=1.e-2) # Convolve conv = galsim.Convolve(obj1, obj2) conv1 = conv.withGSParams(gsp) assert conv.gsparams == galsim.GSParams() assert conv1.gsparams == gsp assert conv1.obj_list[0].gsparams == gsp assert conv1.obj_list[1].gsparams == gsp conv2 = galsim.Convolve(obj1.withGSParams(gsp), obj2.withGSParams(gsp)) conv3 = galsim.Convolve( galsim.Exponential(half_light_radius=1.7, gsparams=gsp), galsim.Pixel(scale=0.2)) conv4 = galsim.Convolve(obj1, obj2, gsparams=gsp) assert conv != conv1 assert conv1 == conv2 assert conv1 == conv3 assert conv1 == conv4 print('stepk = ', conv.stepk, conv1.stepk) assert conv1.stepk < conv.stepk print('maxk = ', conv.maxk, conv1.maxk) assert conv1.maxk > conv.maxk conv5 = galsim.Convolve(obj1, obj2, gsparams=gsp, propagate_gsparams=False) assert conv5 != conv4 assert conv5.gsparams == gsp assert conv5.obj_list[0].gsparams == galsim.GSParams() assert conv5.obj_list[1].gsparams == galsim.GSParams() conv6 = conv5.withGSParams(gsp2) assert conv6 != conv5 assert conv6.gsparams == gsp2 assert conv6.obj_list[0].gsparams == galsim.GSParams() assert conv6.obj_list[1].gsparams == galsim.GSParams() # AutoConvolve conv = galsim.AutoConvolve(obj1) conv1 = conv.withGSParams(gsp) assert conv.gsparams == galsim.GSParams() assert conv1.gsparams == gsp assert conv1.orig_obj.gsparams == gsp conv2 = galsim.AutoConvolve(obj1.withGSParams(gsp)) conv3 = galsim.AutoConvolve(obj1, gsparams=gsp) assert conv != conv1 assert conv1 == conv2 assert conv1 == conv3 print('stepk = ', conv.stepk, conv1.stepk) assert conv1.stepk < conv.stepk print('maxk = ', conv.maxk, conv1.maxk) assert conv1.maxk > conv.maxk conv4 = galsim.AutoConvolve(obj1, gsparams=gsp, propagate_gsparams=False) assert conv4 != conv3 assert conv4.gsparams == gsp assert conv4.orig_obj.gsparams == galsim.GSParams() conv5 = conv4.withGSParams(gsp2) assert conv5 != conv4 assert conv5.gsparams == gsp2 assert conv5.orig_obj.gsparams == galsim.GSParams() # AutoCorrelate conv = galsim.AutoCorrelate(obj1) conv1 = conv.withGSParams(gsp) assert conv.gsparams == galsim.GSParams() assert conv1.gsparams == gsp assert conv1.orig_obj.gsparams == gsp conv2 = galsim.AutoCorrelate(obj1.withGSParams(gsp)) conv3 = galsim.AutoCorrelate(obj1, gsparams=gsp) assert conv != conv1 assert conv1 == conv2 assert conv1 == conv3 print('stepk = ', conv.stepk, conv1.stepk) assert conv1.stepk < conv.stepk print('maxk = ', conv.maxk, conv1.maxk) assert conv1.maxk > conv.maxk conv4 = galsim.AutoCorrelate(obj1, gsparams=gsp, propagate_gsparams=False) assert conv4 != conv3 assert conv4.gsparams == gsp assert conv4.orig_obj.gsparams == galsim.GSParams() conv5 = conv4.withGSParams(gsp2) assert conv5 != conv4 assert conv5.gsparams == gsp2 assert conv5.orig_obj.gsparams == galsim.GSParams() # Deconvolve conv = galsim.Convolve(obj1, galsim.Deconvolve(obj2)) conv1 = conv.withGSParams(gsp) assert conv.gsparams == galsim.GSParams() assert conv1.gsparams == gsp assert conv1.obj_list[0].gsparams == gsp assert conv1.obj_list[1].gsparams == gsp assert conv1.obj_list[1].orig_obj.gsparams == gsp conv2 = galsim.Convolve(obj1, galsim.Deconvolve(obj2.withGSParams(gsp))) conv3 = galsim.Convolve(obj1.withGSParams(gsp), galsim.Deconvolve(obj2)) conv4 = galsim.Convolve(obj1, galsim.Deconvolve(obj2, gsparams=gsp)) assert conv != conv1 assert conv1 == conv2 assert conv1 == conv3 assert conv1 == conv4 print('stepk = ', conv.stepk, conv1.stepk) assert conv1.stepk < conv.stepk print('maxk = ', conv.maxk, conv1.maxk) assert conv1.maxk > conv.maxk conv5 = galsim.Convolve( obj1, galsim.Deconvolve(obj2, gsparams=gsp, propagate_gsparams=False)) assert conv5 != conv4 assert conv5.gsparams == gsp assert conv5.obj_list[0].gsparams == gsp assert conv5.obj_list[1].gsparams == gsp assert conv5.obj_list[1].orig_obj.gsparams == galsim.GSParams() conv6 = conv5.withGSParams(gsp2) assert conv6 != conv5 assert conv6.gsparams == gsp2 assert conv6.obj_list[0].gsparams == gsp2 assert conv6.obj_list[1].gsparams == gsp2 assert conv6.obj_list[1].orig_obj.gsparams == galsim.GSParams() # FourierSqrt conv = galsim.Convolve(obj1, galsim.FourierSqrt(obj2)) conv1 = conv.withGSParams(gsp) assert conv.gsparams == galsim.GSParams() assert conv1.gsparams == gsp assert conv1.obj_list[0].gsparams == gsp assert conv1.obj_list[1].gsparams == gsp assert conv1.obj_list[1].orig_obj.gsparams == gsp conv2 = galsim.Convolve(obj1, galsim.FourierSqrt(obj2.withGSParams(gsp))) conv3 = galsim.Convolve(obj1.withGSParams(gsp), galsim.FourierSqrt(obj2)) conv4 = galsim.Convolve(obj1, galsim.FourierSqrt(obj2, gsparams=gsp)) assert conv != conv1 assert conv1 == conv2 assert conv1 == conv3 assert conv1 == conv4 print('stepk = ', conv.stepk, conv1.stepk) assert conv1.stepk < conv.stepk print('maxk = ', conv.maxk, conv1.maxk) assert conv1.maxk > conv.maxk conv5 = galsim.Convolve( obj1, galsim.FourierSqrt(obj2, gsparams=gsp, propagate_gsparams=False)) assert conv5 != conv4 assert conv5.gsparams == gsp assert conv5.obj_list[0].gsparams == gsp assert conv5.obj_list[1].gsparams == gsp assert conv5.obj_list[1].orig_obj.gsparams == galsim.GSParams() conv6 = conv5.withGSParams(gsp2) assert conv6 != conv5 assert conv6.gsparams == gsp2 assert conv6.obj_list[0].gsparams == gsp2 assert conv6.obj_list[1].gsparams == gsp2 assert conv6.obj_list[1].orig_obj.gsparams == galsim.GSParams()
def main(argv): """ Make a fits image cube where each frame has two images of the same galaxy drawn with regular FFT convolution and with photon shooting. We do this for 5 different PSFs and 5 different galaxies, each with 4 different (random) fluxes, sizes, and shapes. """ logging.basicConfig(format="%(message)s", level=logging.INFO, stream=sys.stdout) logger = logging.getLogger("demo7") # To turn off logging: #logger.propagate = False # To turn on the debugging messages: #logger.setLevel(logging.DEBUG) # Define some parameters we'll use below. # Make output directory if not already present. if not os.path.isdir('output'): os.mkdir('output') file_name = os.path.join('output', 'cube_phot.fits.gz') random_seed = 553728 sky_level = 1.e4 # ADU / arcsec^2 pixel_scale = 0.28 # arcsec nx = 64 ny = 64 gal_flux_min = 1.e4 # Range for galaxy flux gal_flux_max = 1.e5 gal_hlr_min = 0.3 # arcsec gal_hlr_max = 1.3 # arcsec gal_e_min = 0. # Range for ellipticity gal_e_max = 0.8 psf_fwhm = 0.65 # arcsec # This script is set up as a comparison between using FFTs for doing the convolutions and # shooting photons. The two methods have trade-offs in speed and accuracy which vary # with the kind of profile being drawn and the S/N of the object, among other factors. # In addition, for each method, there are a number of parameters GalSim uses that control # aspects of the calculation that further affect the speed and accuracy. # # We encapsulate these parameters with an object called GSParams. The default values # are intended to be accurate enough for normal precision shear tests, without sacrificing # too much speed. # # Any PSF or galaxy object can be given a gsparams argument on construction that can # have different values to make the calculation more or less accurate (typically trading # off for speed or memory). # # In this script, we adjust some of the values slightly, just to show you how it works. # You could play around with these values and see what effect they have on the drawn images. # Usually, it requires a pretty drastic change in these parameters for you to be able to # notice the difference by eye. But subtle effects that may impact the shapes of galaxies # can happen well before then. # Type help(galsim.GSParams) for the complete list of parameters and more detailed # documentation, including the default values for each parameter. gsparams = galsim.GSParams( folding_threshold= 1.e-2, # maximum fractional flux that may be folded around edge of FFT maxk_threshold= 2.e-3, # k-values less than this may be excluded off edge of FFT xvalue_accuracy= 1.e-4, # approximations in real space aim to be this accurate kvalue_accuracy= 1.e-4, # approximations in fourier space aim to be this accurate shoot_accuracy= 1.e-4, # approximations in photon shooting aim to be this accurate minimum_fft_size=64) # minimum size of ffts logger.info('Starting demo script 7') # Make the PSF profiles: psf1 = galsim.Gaussian(fwhm=psf_fwhm, gsparams=gsparams) psf2 = galsim.Moffat(fwhm=psf_fwhm, beta=2.4, gsparams=gsparams) psf3_inner = galsim.Gaussian(fwhm=psf_fwhm, flux=0.8, gsparams=gsparams) psf3_outer = galsim.Gaussian(fwhm=2 * psf_fwhm, flux=0.2, gsparams=gsparams) psf3 = psf3_inner + psf3_outer atmos = galsim.Gaussian(fwhm=psf_fwhm, gsparams=gsparams) # The OpticalPSF and set of Zernike values chosen below correspond to a reasonably well aligned, # smallish ~0.3m / 12 inch diameter telescope with a central obscuration of ~0.12m or 5 inches # diameter, being used in optical wavebands. # In the Noll convention, the value of the Zernike coefficient also gives the RMS optical path # difference across a circular pupil. An RMS difference of ~0.5 or larger indicates that parts # of the wavefront are in fully destructive interference, and so we might expect aberrations to # become strong when Zernike aberrations summed in quadrature approach 0.5 wave. # The aberrations chosen in this case correspond to operating close to a 0.25 wave RMS optical # path difference. Unlike in demo3, we specify the aberrations by making a list that we pass # in using the 'aberrations' kwarg. The order of aberrations starting from index 4 is defocus, # astig1, astig2, coma1, coma2, trefoil1, trefoil2, spher as in the Noll convention. # We ignore the first 4 values so that the index number corresponds to the Zernike index # in the Noll convention. This will be particularly convenient once we start allowing # coefficients beyond spherical (index 11). c.f. The Wikipedia page about the Noll indices: # # http://en.wikipedia.org/wiki/Zernike_polynomials#Zernike_polynomials aberrations = [0.0] * 12 # Set the initial size. aberrations[4] = 0.06 # Noll index 4 = Defocus aberrations[5:7] = [0.12, -0.08] # Noll index 5,6 = Astigmatism aberrations[7:9] = [0.07, 0.04] # Noll index 7,8 = Coma aberrations[11] = -0.13 # Noll index 11 = Spherical # You could also define these all at once if that is more convenient: #aberrations = [0.0, 0.0, 0.0, 0.0, 0.06, 0.12, -0.08, 0.07, 0.04, 0.0, 0.0, -0.13] optics = galsim.OpticalPSF(lam_over_diam=0.6 * psf_fwhm, obscuration=0.4, aberrations=aberrations, gsparams=gsparams) psf4 = galsim.Convolve([atmos, optics ]) # Convolve inherits the gsparams from the first # item in the list. (Or you can supply a gsparams # argument explicitly if you want to override this.) atmos = galsim.Kolmogorov(fwhm=psf_fwhm, gsparams=gsparams) optics = galsim.Airy(lam_over_diam=0.3 * psf_fwhm, gsparams=gsparams) psf5 = galsim.Convolve([atmos, optics]) psfs = [psf1, psf2, psf3, psf4, psf5] psf_names = [ "Gaussian", "Moffat", "Double Gaussian", "OpticalPSF", "Kolmogorov * Airy" ] psf_times = [0, 0, 0, 0, 0] psf_fft_times = [0, 0, 0, 0, 0] psf_phot_times = [0, 0, 0, 0, 0] # Make the galaxy profiles: gal1 = galsim.Gaussian(half_light_radius=1, gsparams=gsparams) gal2 = galsim.Exponential(half_light_radius=1, gsparams=gsparams) gal3 = galsim.DeVaucouleurs(half_light_radius=1, gsparams=gsparams) gal4 = galsim.Sersic(half_light_radius=1, n=2.5, gsparams=gsparams) # A Sersic profile may be truncated if desired. # The units for this are expected to be arcsec (or specifically -- whatever units # you are using for all the size values as defined by the pixel_scale). bulge = galsim.Sersic(half_light_radius=0.7, n=3.2, trunc=8.5, gsparams=gsparams) disk = galsim.Sersic(half_light_radius=1.2, n=1.5, gsparams=gsparams) gal5 = 0.4 * bulge + 0.6 * disk # Net half-light radius is only approximate for this one. gals = [gal1, gal2, gal3, gal4, gal5] gal_names = [ "Gaussian", "Exponential", "Devaucouleurs", "n=2.5 Sersic", "Bulge + Disk" ] gal_times = [0, 0, 0, 0, 0] gal_fft_times = [0, 0, 0, 0, 0] gal_phot_times = [0, 0, 0, 0, 0] # Other times to keep track of: setup_times = 0 fft_times = 0 phot_times = 0 noise_times = 0 # Loop over combinations of psf, gal, and make 4 random choices for flux, size, shape. all_images = [] k = 0 for ipsf in range(len(psfs)): psf = psfs[ipsf] psf_name = psf_names[ipsf] logger.info('psf %d: %s', ipsf + 1, psf) # Note that this implicitly calls str(psf). We've made an effort to give all GalSim # objects an informative but relatively succinct str representation. Some details may # be missing, but it should look essentially like how you would create the object. logger.debug('repr = %r', psf) # The repr() version are a bit more pedantic in form and should be completely informative, # to the point where two objects that are not identical should never have equal repr # strings. As such the repr strings may in some cases be somewhat unwieldy. For instance, # since we set non-default gsparams in these, the repr includes that information, but # it is omitted from the str for brevity. for igal in range(len(gals)): gal = gals[igal] gal_name = gal_names[igal] logger.info(' galaxy %d: %s', igal + 1, gal) logger.debug(' repr = %r', gal) for i in range(4): logger.debug(' Start work on image %d', i) t1 = time.time() # Initialize the random number generator we will be using. rng = galsim.UniformDeviate(random_seed + k + 1) # Generate random variates: flux = rng() * (gal_flux_max - gal_flux_min) + gal_flux_min # Use a new variable name, since we'll want to keep the original unmodified. this_gal = gal.withFlux(flux) hlr = rng() * (gal_hlr_max - gal_hlr_min) + gal_hlr_min this_gal = this_gal.dilate(hlr) beta_ellip = rng() * 2 * math.pi * galsim.radians ellip = rng() * (gal_e_max - gal_e_min) + gal_e_min gal_shape = galsim.Shear(e=ellip, beta=beta_ellip) this_gal = this_gal.shear(gal_shape) # Build the final object by convolving the galaxy and PSF. final = galsim.Convolve([this_gal, psf]) # Create the large, double width output image # Rather than provide a scale= argument to the drawImage commands, we can also # set the pixel scale in the image constructor. # Note: You can also change it after the construction with im.scale=pixel_scale image = galsim.ImageF(2 * nx + 2, ny, scale=pixel_scale) # Assign the following two Image "views", fft_image and phot_image. # Using the syntax below, these are views into the larger image. # Changes/additions to the sub-images referenced by the views are automatically # reflected in the original image. fft_image = image[galsim.BoundsI(1, nx, 1, ny)] phot_image = image[galsim.BoundsI(nx + 3, 2 * nx + 2, 1, ny)] logger.debug( ' Read in training sample galaxy and PSF from file') t2 = time.time() # Draw the profile # This default rendering method (method='auto') usually defaults to FFT, since # that is normally the most efficient method. However, we can also set method # to 'fft' explicitly to force it to always use FFTs for the convolution # by the pixel response. (In this case, it doesn't have any effect, since # the 'auto' method would have always chosen 'fft' anyway, so this is just # for illustrative purposes.) final.drawImage(fft_image, method='fft') logger.debug( ' Drew fft image. Total drawn flux = %f. .flux = %f', fft_image.array.sum(), final.getFlux()) t3 = time.time() # Add Poisson noise sky_level_pixel = sky_level * pixel_scale**2 fft_image.addNoise( galsim.PoissonNoise(rng, sky_level=sky_level_pixel)) t4 = time.time() # The next two lines are just to get the output from this demo script # to match the output from the parsing of demo7.yaml. rng = galsim.UniformDeviate(random_seed + k + 1) rng() rng() rng() rng() # Repeat for photon shooting image. # The max_extra_noise parameter indicates how much extra noise per pixel we are # willing to tolerate. The sky noise will be adding a variance of sky_level_pixel, # so we allow up to 1% of that extra. final.drawImage(phot_image, method='phot', max_extra_noise=sky_level_pixel / 100, rng=rng) t5 = time.time() # For photon shooting, galaxy already has Poisson noise, so we want to make # sure not to add that noise again! Thus, we just add sky noise, which # is Poisson with the mean = sky_level_pixel pd = galsim.PoissonDeviate(rng, mean=sky_level_pixel) # DeviateNoise just adds the action of the given deviate to every pixel. phot_image.addNoise(galsim.DeviateNoise(pd)) # For PoissonDeviate, the mean is not zero, so for a background-subtracted # image, we need to subtract the mean back off when we are done. phot_image -= sky_level_pixel logger.debug( ' Added Poisson noise. Image fluxes are now %f and %f', fft_image.array.sum(), phot_image.array.sum()) t6 = time.time() # Store that into the list of all images all_images += [image] k = k + 1 logger.info( ' %d: flux = %.2e, hlr = %.2f, ellip = (%.2f,%.2f)', k, flux, hlr, gal_shape.getE1(), gal_shape.getE2()) logger.debug(' Times: %f, %f, %f, %f, %f', t2 - t1, t3 - t2, t4 - t3, t5 - t4, t6 - t5) psf_times[ipsf] += t6 - t1 psf_fft_times[ipsf] += t3 - t2 psf_phot_times[ipsf] += t5 - t4 gal_times[igal] += t6 - t1 gal_fft_times[igal] += t3 - t2 gal_phot_times[igal] += t5 - t4 setup_times += t2 - t1 fft_times += t3 - t2 phot_times += t5 - t4 noise_times += t4 - t3 + t6 - t5 logger.info('Done making images of galaxies') logger.info('') logger.info('Some timing statistics:') logger.info(' Total time for setup steps = %f', setup_times) logger.info(' Total time for regular fft drawing = %f', fft_times) logger.info(' Total time for photon shooting = %f', phot_times) logger.info(' Total time for adding noise = %f', noise_times) logger.info('') logger.info('Breakdown by PSF type:') for ipsf in range(len(psfs)): logger.info(' %s: Total time = %f (fft: %f, phot: %f)', psf_names[ipsf], psf_times[ipsf], psf_fft_times[ipsf], psf_phot_times[ipsf]) logger.info('') logger.info('Breakdown by Galaxy type:') for igal in range(len(gals)): logger.info(' %s: Total time = %f (fft: %f, phot: %f)', gal_names[igal], gal_times[igal], gal_fft_times[igal], gal_phot_times[igal]) logger.info('') # Now write the image to disk. # With any write command, you can optionally compress the file using several compression # schemes: # 'gzip' uses gzip on the full output file. # 'bzip2' uses bzip2 on the full output file. # 'rice' uses rice compression on the image, leaving the fits headers readable. # 'gzip_tile' uses gzip in tiles on the output image, leaving the fits headers readable. # 'hcompress' uses hcompress on the image, but it is only valid for 2-d data, so it # doesn't work for writeCube. # 'plio' uses plio on the image, but it is only valid for positive integer data. # Furthermore, the first three have standard filename extensions associated with them, # so if you don't specify a compression, but the filename ends with '.gz', '.bz2' or '.fz', # the corresponding compression will be selected automatically. # In other words, the `compression='gzip'` specification is actually optional here: galsim.fits.writeCube(all_images, file_name, compression='gzip') logger.info('Wrote fft image to fits data cube %r', file_name)
def test_convolve(): """Test the convolution of a Moffat and a Box profile against a known result. """ dx = 0.2 # Using an exact Maple calculation for the comparison. Only accurate to 4 decimal places. savedImg = galsim.fits.read(os.path.join(imgdir, "moffat_pixel.fits")) myImg = galsim.ImageF(savedImg.bounds, scale=dx) myImg.setCenter(0, 0) # Code was formerly: # psf = galsim.Moffat(beta=1.5, truncationFWHM=4, flux=1, half_light_radius=1) # # ...but this is no longer quite so simple since we changed the handling of trunc to be in # physical units. However, the same profile can be constructed using # fwhm=1.0927449310213702, # as calculated by interval bisection in devutils/external/calculate_moffat_radii.py fwhm_backwards_compatible = 1.0927449310213702 psf = galsim.Moffat(beta=1.5, fwhm=fwhm_backwards_compatible, trunc=4 * fwhm_backwards_compatible, flux=1) pixel = galsim.Pixel(scale=dx, flux=1.) # Note: Since both of these have hard edges, GalSim wants to do this with real_space=True. # Here we are intentionally tesing the Fourier convolution, so we want to suppress the # warning that GalSim emits. with assert_warns(galsim.GalSimWarning): # We'll do the real space convolution below conv = galsim.Convolve([psf, pixel], real_space=False) conv.drawImage(myImg, scale=dx, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 4, err_msg="Moffat convolved with Pixel disagrees with expected result" ) assert psf.gsparams is galsim.GSParams.default assert pixel.gsparams is galsim.GSParams.default assert conv.gsparams is galsim.GSParams.default # Other ways to do the convolution: conv = galsim.Convolve(psf, pixel, real_space=False) conv.drawImage(myImg, scale=dx, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 4, err_msg= "Using GSObject Convolve(psf,pixel) disagrees with expected result" ) assert conv.gsparams is galsim.GSParams.default # Check with default_params conv = galsim.Convolve([psf, pixel], real_space=False, gsparams=default_params) conv.drawImage(myImg, scale=dx, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 4, err_msg= "Using GSObject Convolve([psf,pixel]) with default_params disagrees with" "expected result") # In this case, it's not the same object, but it should be == assert conv.gsparams is not galsim.GSParams.default assert conv.gsparams == galsim.GSParams.default assert conv.gsparams is default_params # Also the components shouldn't have changed. assert conv.obj_list[0] is psf assert conv.obj_list[1] is pixel conv = galsim.Convolve([psf, pixel], real_space=False, gsparams=galsim.GSParams()) conv.drawImage(myImg, scale=dx, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 4, err_msg= "Using GSObject Convolve([psf,pixel]) with GSParams() disagrees with" "expected result") assert conv.gsparams is not galsim.GSParams.default assert conv.gsparams == galsim.GSParams.default cen = galsim.PositionD(0, 0) np.testing.assert_equal(conv.centroid, cen) np.testing.assert_almost_equal(conv.flux, psf.flux * pixel.flux) # Not almost_equal. Convolutions don't give a very good estimate. # They are almost always too high, which is actually ok for how we use max_sb for phot shooting. np.testing.assert_array_less(conv.xValue(cen), conv.max_sb) check_basic(conv, "Moffat * Pixel") # Test photon shooting. with assert_warns(galsim.GalSimWarning): do_shoot(conv, myImg, "Moffat * Pixel") # Convolution of just one argument should be equivalent to that argument. single = galsim.Convolve(psf) gsobject_compare(single, psf) check_basic(single, "`convolution' of single Moffat") do_pickle(single) do_shoot(single, myImg, "single Convolution") single = galsim.Convolve([psf]) gsobject_compare(single, psf) check_basic(single, "`convolution' of single Moffat") do_pickle(single) single = galsim.Convolution(psf) gsobject_compare(single, psf) check_basic(single, "`convolution' of single Moffat") do_pickle(single) single = galsim.Convolution([psf]) gsobject_compare(single, psf) check_basic(single, "`convolution' of single Moffat") do_pickle(single) # Should raise an exception for invalid arguments assert_raises(TypeError, galsim.Convolve) assert_raises(TypeError, galsim.Convolve, myImg) assert_raises(TypeError, galsim.Convolve, [myImg]) assert_raises(TypeError, galsim.Convolve, [psf, myImg]) assert_raises(TypeError, galsim.Convolve, [psf, psf, myImg]) assert_raises(TypeError, galsim.Convolve, [psf, psf], realspace=False) assert_raises(TypeError, galsim.Convolution) assert_raises(TypeError, galsim.Convolution, myImg) assert_raises(TypeError, galsim.Convolution, [myImg]) assert_raises(TypeError, galsim.Convolution, [psf, myImg]) assert_raises(TypeError, galsim.Convolution, [psf, psf, myImg]) assert_raises(TypeError, galsim.Convolution, [psf, psf], realspace=False) with assert_warns(galsim.GalSimWarning): triple = galsim.Convolve(psf, psf, pixel) assert_raises(galsim.GalSimError, triple.xValue, galsim.PositionD(0, 0)) assert_raises(galsim.GalSimError, triple.drawReal, myImg) deconv = galsim.Convolve(psf, galsim.Deconvolve(pixel)) assert_raises(galsim.GalSimError, deconv.xValue, galsim.PositionD(0, 0)) assert_raises(galsim.GalSimError, deconv.drawReal, myImg) assert_raises(galsim.GalSimError, deconv.drawPhot, myImg, n_photons=10)
def test_knots_defaults(): """ Create a random walk galaxy and test that the getters work for default inputs """ # try constructing with mostly defaults npoints=100 hlr = 8.0 rng = galsim.BaseDeviate(1234) rw=galsim.RandomKnots(npoints, half_light_radius=hlr, rng=rng) assert rw.npoints==npoints,"expected npoints==%d, got %d" % (npoints, rw.npoints) assert rw.input_half_light_radius==hlr,\ "expected hlr==%g, got %g" % (hlr, rw.input_half_light_radius) nobj=len(rw.points) assert nobj == npoints,"expected %d objects, got %d" % (npoints, nobj) pts=rw.points assert pts.shape == (npoints,2),"expected (%d,2) shape for points, got %s" % (npoints, pts.shape) np.testing.assert_almost_equal(rw.centroid.x, np.mean(pts[:,0])) np.testing.assert_almost_equal(rw.centroid.y, np.mean(pts[:,1])) gsp = galsim.GSParams(xvalue_accuracy=1.e-8, kvalue_accuracy=1.e-8) rng2 = galsim.BaseDeviate(1234) rw2 = galsim.RandomKnots(npoints, half_light_radius=hlr, rng=rng2, gsparams=gsp) assert rw2 != rw assert rw2 == rw.withGSParams(gsp) assert rw2 == rw.withGSParams(xvalue_accuracy=1.e-8, kvalue_accuracy=1.e-8) # Check that they produce identical images. psf = galsim.Gaussian(sigma=0.8) conv1 = galsim.Convolve(rw.withGSParams(gsp), psf) conv2 = galsim.Convolve(rw2, psf) im1 = conv1.drawImage() im2 = conv2.drawImage() assert im1 == im2 # Check that image is not sensitive to use of rng by other objects. rng3 = galsim.BaseDeviate(1234) rw3=galsim.RandomKnots(npoints, half_light_radius=hlr, rng=rng3) rng3.discard(523) conv1 = galsim.Convolve(rw, psf) conv3 = galsim.Convolve(rw3, psf) im1 = conv1.drawImage() im3 = conv2.drawImage() assert im1 == im3 # Run some basic tests of correctness check_basic(conv1, "RandomKnots") im = galsim.ImageD(64,64, scale=0.5) do_shoot(conv1, im, "RandomKnots") do_kvalue(conv1, im, "RandomKnots") do_pickle(rw) do_pickle(conv1) do_pickle(conv1, lambda x: x.drawImage(scale=1)) # Check negative flux rw3 = rw.withFlux(-2.3) assert rw3 == galsim.RandomKnots(npoints, half_light_radius=hlr, rng=galsim.BaseDeviate(1234), flux=-2.3) conv = galsim.Convolve(rw3, psf) check_basic(conv, "RandomKnots with negative flux")
def test_realspace_convolve(): """Test the real-space convolution of a Moffat and a Box profile against a known result. """ dx = 0.2 # Note: Using an image created from Maple "exact" calculations. saved_img = galsim.fits.read(os.path.join(imgdir, "moffat_pixel.fits")) img = galsim.ImageF(saved_img.bounds, scale=dx) img.setCenter(0, 0) # Code was formerly: # psf = galsim.Moffat(beta=1.5, truncationFWHM=4, flux=1, half_light_radius=1) # # ...but this is no longer quite so simple since we changed the handling of trunc to be in # physical units. However, the same profile can be constructed using # fwhm=1.0927449310213702, # as calculated by interval bisection in devutils/external/calculate_moffat_radii.py fwhm_backwards_compatible = 1.0927449310213702 psf = galsim.Moffat(beta=1.5, half_light_radius=1, trunc=4 * fwhm_backwards_compatible, flux=1) #psf = galsim.Moffat(beta=1.5, fwhm=fwhm_backwards_compatible, #trunc=4*fwhm_backwards_compatible, flux=1) pixel = galsim.Pixel(scale=dx, flux=1.) conv = galsim.Convolve([psf, pixel], real_space=True) conv.drawImage(img, scale=dx, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( img.array, saved_img.array, 5, err_msg= "Using GSObject Convolve([psf,pixel]) disagrees with expected result") # Check with default_params conv = galsim.Convolve([psf, pixel], real_space=True, gsparams=default_params) conv.drawImage(img, scale=dx, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( img.array, saved_img.array, 5, err_msg= "Using GSObject Convolve([psf,pixel]) with default_params disagrees with " "expected result") conv = galsim.Convolve([psf, pixel], real_space=True, gsparams=galsim.GSParams()) conv.drawImage(img, scale=dx, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( img.array, saved_img.array, 5, err_msg= "Using GSObject Convolve([psf,pixel]) with GSParams() disagrees with " "expected result") # Other ways to do the convolution: conv = galsim.Convolve(psf, pixel, real_space=True) conv.drawImage(img, scale=dx, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( img.array, saved_img.array, 5, err_msg= "Using GSObject Convolve(psf,pixel) disagrees with expected result") # The real-space convolution algorithm is not (trivially) independent of the order of # the two things being convolved. So check the opposite order. conv = galsim.Convolve([pixel, psf], real_space=True) conv.drawImage(img, scale=dx, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( img.array, saved_img.array, 5, err_msg= "Using GSObject Convolve([pixel,psf]) disagrees with expected result") check_basic(conv, "Truncated Moffat*Box", approx_maxsb=True) # Test kvalues do_kvalue(conv, img, "Truncated Moffat*Box") # Check picklability do_pickle(conv, lambda x: x.drawImage(method='sb')) do_pickle(conv) # Check some warnings that should be raised # More than 2 with only hard edges gives a warning either way. (Different warnings though.) assert_warns(galsim.GalSimWarning, galsim.Convolve, [psf, psf, pixel]) assert_warns(galsim.GalSimWarning, galsim.Convolve, [psf, psf, pixel], real_space=False) assert_warns(galsim.GalSimWarning, galsim.Convolve, [psf, psf, pixel], real_space=True) # 2 with hard edges gives a warning if we ask it not to use real_space assert_warns(galsim.GalSimWarning, galsim.Convolve, [psf, pixel], real_space=False) # >2 of any kind give a warning if we ask it to use real_space g = galsim.Gaussian(sigma=2) assert_warns(galsim.GalSimWarning, galsim.Convolve, [g, g, g], real_space=True) # non-analytic profiles cannot do real_space d = galsim.Deconvolve(galsim.Gaussian(sigma=2)) assert_warns(galsim.GalSimWarning, galsim.Convolve, [g, d], real_space=True) assert_raises(TypeError, galsim.Convolve, [g, d], real_space='true') # Repeat some of the above for AutoConvolve and AutoCorrelate conv = galsim.AutoConvolve(psf, real_space=True) check_basic(conv, "AutoConvolve Truncated Moffat", approx_maxsb=True) do_kvalue(conv, img, "AutoConvolve Truncated Moffat") do_pickle(conv) conv = galsim.AutoCorrelate(psf, real_space=True) check_basic(conv, "AutoCorrelate Truncated Moffat", approx_maxsb=True) do_kvalue(conv, img, "AutoCorrelate Truncated Moffat") do_pickle(conv) assert_warns(galsim.GalSimWarning, galsim.AutoConvolve, psf, real_space=False) assert_warns(galsim.GalSimWarning, galsim.AutoConvolve, d, real_space=True) assert_warns(galsim.GalSimWarning, galsim.AutoCorrelate, psf, real_space=False) assert_warns(galsim.GalSimWarning, galsim.AutoCorrelate, d, real_space=True) assert_raises(TypeError, galsim.AutoConvolve, d, real_space='true') assert_raises(TypeError, galsim.AutoCorrelate, d, real_space='true')
def run_tests(random_seed, outfile, config=None, gsparams=None, wmult=None, logger=None, fail_value=-666.): """Run a full set of tests, writing pickled tuple output to outfile. """ import sys import cPickle import numpy as np import galsim import galaxy_sample # Load up the comparison_utilities module from the parent directory sys.path.append('..') import comparison_utilities if config is None: use_config = False if gsparams is None: import warnings warnings.warn("No gsparams provided to run_tests?") if wmult is None: raise ValueError("wmult must be set if config=None.") else: use_config = True if gsparams is not None: import warnings warnings.warn( "gsparams is provided as a kwarg but the config['image']['gsparams'] will take "+ "precedence.") if wmult is not None: import warnings warnings.warn( "wmult is provided as a kwarg but the config['image']['wmult'] will take "+ "precedence.") # Get galaxy sample n_cosmos, hlr_cosmos, gabs_cosmos = galaxy_sample.get() # Only take the first NOBS objects n_cosmos = n_cosmos[0: NOBS] hlr_cosmos = hlr_cosmos[0: NOBS] gabs_cosmos = gabs_cosmos[0: NOBS] ntest = len(SERSIC_N_TEST) # Setup a UniformDeviate ud = galsim.UniformDeviate(random_seed) # Open the output file and write a header: fout = open(outfile, 'wb') fout.write( '# g1obs_draw g2obs_draw sigma_draw delta_g1obs delta_g2obs delta_sigma '+ 'err_g1obs err_g2obs err_sigma\n') # Start looping through the sample objects and collect the results for i, hlr, gabs in zip(range(NOBS), hlr_cosmos, gabs_cosmos): print "Testing galaxy #"+str(i+1)+"/"+str(NOBS)+\ " with (hlr, |g|) = "+str(hlr)+", "+str(gabs) random_theta = 2. * np.pi * ud() g1 = gabs * np.cos(2. * random_theta) g2 = gabs * np.sin(2. * random_theta) for j, sersic_n in zip(range(ntest), SERSIC_N_TEST): print "Exploring Sersic n = "+str(sersic_n) if use_config: # Increment the random seed so that each test gets a unique one config['image']['random_seed'] = random_seed + i * NOBS * ntest + j * ntest + 1 config['gal'] = { "type" : "Sersic" , "n" : sersic_n , "half_light_radius" : hlr , "ellip" : { "type" : "G1G2" , "g1" : g1 , "g2" : g2 } } config['psf'] = {"type" : "Airy" , "lam_over_diam" : PSF_LAM_OVER_DIAM } try: results = comparison_utilities.compare_dft_vs_photon_config( config, abs_tol_ellip=TOL_ELLIP, abs_tol_size=TOL_SIZE, logger=logger) test_ran = True except RuntimeError as err: test_ran = False pass # Uncomment lines below to ouput a check image #import copy #checkimage = galsim.config.BuildImage(copy.deepcopy(config))[0] #im = first element #checkimage.write('junk_'+str(i + 1)+'_'+str(j + 1)+'.fits') else: test_gsparams = galsim.GSParams(maximum_fft_size=MAX_FFT_SIZE) galaxy = galsim.Sersic(sersic_n, half_light_radius=hlr, gsparams=test_gsparams) galaxy.applyShear(g1=g1, g2=g2) psf = galsim.Airy(lam_over_diam=PSF_LAM_OVER_DIAM, gsparams=test_gsparams) try: results = comparison_utilities.compare_dft_vs_photon_object( galaxy, psf_object=psf, rng=ud, pixel_scale=PIXEL_SCALE, size=IMAGE_SIZE, abs_tol_ellip=TOL_ELLIP, abs_tol_size=TOL_SIZE, n_photons_per_trial=NPHOTONS, wmult=wmult) test_ran = True except RuntimeError, err: test_ran = False pass if not test_ran: import warnings warnings.warn( 'RuntimeError encountered for galaxy '+str(i + 1)+'/'+str(NOBS)+' with '+ 'Sersic n = '+str(sersic_n)+': '+str(err)) fout.write( '%e %e %e %e %e %e %e %e %e %e %e %e %e\n' % ( fail_value, fail_value, fail_value, fail_value, fail_value, fail_value, fail_value, fail_value, fail_value, fail_value, fail_value, fail_value, fail_value) ) fout.flush() else: fout.write( '%e %e %e %e %e %e %e %e %e %e %e %e %e\n' % ( results.g1obs_draw, results.g2obs_draw, results.sigma_draw, results.delta_g1obs, results.delta_g2obs, results.delta_sigma, results.err_g1obs, results.err_g2obs, results.err_sigma, sersic_n, hlr, g1, g2 ) ) fout.flush()
def test_realspace_distorted_convolve(): """ The same as above, but both the Moffat and the Box are sheared, rotated and shifted to stress test the code that deals with this for real-space convolutions that wouldn't be tested otherwise. """ dx = 0.2 saved_img = galsim.fits.read( os.path.join(imgdir, "moffat_pixel_distorted.fits")) img = galsim.ImageF(saved_img.bounds, scale=dx) img.setCenter(0, 0) fwhm_backwards_compatible = 1.0927449310213702 psf = galsim.Moffat(beta=1.5, half_light_radius=1, trunc=4 * fwhm_backwards_compatible, flux=1) #psf = galsim.Moffat(beta=1.5, fwhm=fwhm_backwards_compatible, #trunc=4*fwhm_backwards_compatible, flux=1) psf = psf.shear(g1=0.11, g2=0.17).rotate(13 * galsim.degrees) pixel = galsim.Pixel(scale=dx, flux=1.) pixel = pixel.shear(g1=0.2, g2=0.0).rotate(80 * galsim.degrees).shift(0.13, 0.27) # NB: real-space is chosen automatically conv = galsim.Convolve([psf, pixel]) conv.drawImage(img, scale=dx, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( img.array, saved_img.array, 5, err_msg= "Using Convolve([psf,pixel]) (distorted) disagrees with expected result" ) # Check with default_params conv = galsim.Convolve([psf, pixel], gsparams=default_params) conv.drawImage(img, scale=dx, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( img.array, saved_img.array, 5, err_msg= "Using Convolve([psf,pixel]) (distorted) with default_params disagrees with " "expected result") conv = galsim.Convolve([psf, pixel], gsparams=galsim.GSParams()) conv.drawImage(img, scale=dx, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( img.array, saved_img.array, 5, err_msg= "Using Convolve([psf,pixel]) (distorted) with GSParams() disagrees with " "expected result") # Other ways to do the convolution: conv = galsim.Convolve(psf, pixel) conv.drawImage(img, scale=dx, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( img.array, saved_img.array, 5, err_msg= "Using Convolve(psf,pixel) (distorted) disagrees with expected result") # The real-space convolution algorithm is not (trivially) independent of the order of # the two things being convolved. So check the opposite order. conv = galsim.Convolve([pixel, psf]) conv.drawImage(img, scale=dx, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( img.array, saved_img.array, 5, err_msg= "Using Convolve([pixel,psf]) (distorted) disagrees with expected result" )
def test_box(): """Test the generation of a specific box profile against a known result. """ savedImg = galsim.fits.read(os.path.join(imgdir, "box_1.fits")) myImg = galsim.ImageF(savedImg.bounds, scale=0.2) myImg.setCenter(0,0) test_flux = 1.8 pixel = galsim.Pixel(scale=1, flux=1) pixel.drawImage(myImg, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 5, err_msg="Using GSObject Pixel disagrees with expected result") np.testing.assert_array_equal( pixel.scale, 1, err_msg="Pixel scale returned wrong value") # Check with default_params pixel = galsim.Pixel(scale=1, flux=1, gsparams=default_params) pixel.drawImage(myImg, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 5, err_msg="Using GSObject Pixel with default_params disagrees with expected result") pixel = galsim.Pixel(scale=1, flux=1, gsparams=galsim.GSParams()) pixel.drawImage(myImg, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 5, err_msg="Using GSObject Pixel with GSParams() disagrees with expected result") # Use non-unity values. pixel = galsim.Pixel(flux=1.7, scale=2.3) gsp = galsim.GSParams(xvalue_accuracy=1.e-8, kvalue_accuracy=1.e-8) pixel2 = galsim.Pixel(flux=1.7, scale=2.3, gsparams=gsp) assert pixel2 != pixel assert pixel2 == pixel.withGSParams(gsp) # Test photon shooting. do_shoot(pixel,myImg,"Pixel") # Check picklability do_pickle(pixel, lambda x: x.drawImage(method='no_pixel')) do_pickle(pixel) do_pickle(galsim.Pixel(1)) # Check that non-square Box profiles work correctly scale = 0.2939 # Use a strange scale here to make sure that the centers of the pixels # never fall on the box edge, otherwise it gets a bit weird to know what # the correct SB value is for that pixel. im = galsim.ImageF(16,16, scale=scale) gsp = galsim.GSParams(maximum_fft_size = 30000) for (width,height) in [ (3,2), (1.7, 2.7), (2.2222, 3.1415) ]: box = galsim.Box(width=width, height=height, flux=test_flux, gsparams=gsp) check_basic(box, "Box with width,height = %f,%f"%(width,height)) do_shoot(box,im,"Box with width,height = %f,%f"%(width,height)) if __name__ == '__main__': # These are slow because they require a pretty huge fft. # So only do them if running as main. do_kvalue(box,im,"Box with width,height = %f,%f"%(width,height)) cen = galsim.PositionD(0, 0) np.testing.assert_equal(box.centroid, cen) np.testing.assert_almost_equal(box.kValue(cen), (1+0j) * test_flux) np.testing.assert_almost_equal(box.flux, test_flux) np.testing.assert_almost_equal(box.xValue(cen), box.max_sb) np.testing.assert_almost_equal(box.xValue(width/2.-0.001, height/2.-0.001), box.max_sb) np.testing.assert_almost_equal(box.xValue(width/2.-0.001, height/2.+0.001), 0.) np.testing.assert_almost_equal(box.xValue(width/2.+0.001, height/2.-0.001), 0.) np.testing.assert_almost_equal(box.xValue(width/2.+0.001, height/2.+0.001), 0.) np.testing.assert_array_equal( box.width, width, err_msg="Box width returned wrong value") np.testing.assert_array_equal( box.height, height, err_msg="Box height returned wrong value") gsp2 = galsim.GSParams(xvalue_accuracy=1.e-8, kvalue_accuracy=1.e-8) box2 = galsim.Box(width=width, height=height, flux=test_flux, gsparams=gsp2) assert box2 != box assert box2 == box.withGSParams(gsp2) # Check picklability do_pickle(box, lambda x: x.drawImage(method='no_pixel')) do_pickle(box) do_pickle(galsim.Box(1,1)) # Check sheared boxes the same way box = galsim.Box(width=3, height=2, flux=test_flux, gsparams=gsp) box = box.shear(galsim.Shear(g1=0.2, g2=-0.3)) check_basic(box, "Sheared Box", approx_maxsb=True) do_shoot(box,im, "Sheared Box") if __name__ == '__main__': do_kvalue(box,im, "Sheared Box") do_pickle(box, lambda x: x.drawImage(method='no_pixel')) do_pickle(box) cen = galsim.PositionD(0, 0) np.testing.assert_equal(box.centroid, cen) np.testing.assert_almost_equal(box.kValue(cen), (1+0j) * test_flux) np.testing.assert_almost_equal(box.flux, test_flux) np.testing.assert_almost_equal(box.xValue(cen), box.max_sb) # This is also a profile that may be convolved using real space convolution, so test that. if __name__ == '__main__': conv = galsim.Convolve(box, galsim.Pixel(scale=scale), real_space=True) check_basic(conv, "Sheared Box convolved with pixel in real space", approx_maxsb=True, scale=0.2) do_kvalue(conv,im, "Sheared Box convolved with pixel in real space") do_pickle(conv, lambda x: x.xValue(0.123,-0.456)) do_pickle(conv)
def test_realspace_shearconvolve(): """Test the real-space convolution of a sheared Gaussian and a Box profile against a known result. """ e1 = 0.04 e2 = 0.0 myShear = galsim.Shear(e1=e1, e2=e2) dx = 0.2 saved_img = galsim.fits.read( os.path.join(imgdir, "gauss_smallshear_convolve_box.fits")) img = galsim.ImageF(saved_img.bounds, scale=dx) img.setCenter(0, 0) psf = galsim.Gaussian(flux=1, sigma=1) psf = psf.shear(e1=e1, e2=e2) pixel = galsim.Pixel(scale=dx, flux=1.) conv = galsim.Convolve([psf, pixel], real_space=True) conv.drawImage(img, scale=dx, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( img.array, saved_img.array, 5, err_msg= "Using GSObject Convolve([psf,pixel]) disagrees with expected result") # Check with default_params conv = galsim.Convolve([psf, pixel], real_space=True, gsparams=default_params) conv.drawImage(img, scale=dx, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( img.array, saved_img.array, 5, err_msg= "Using GSObject Convolve([psf,pixel]) with default_params disagrees with " "expected result") conv = galsim.Convolve([psf, pixel], real_space=True, gsparams=galsim.GSParams()) conv.drawImage(img, scale=dx, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( img.array, saved_img.array, 5, err_msg= "Using GSObject Convolve([psf,pixel]) with GSParams() disagrees with " "expected result") # Other ways to do the convolution: conv = galsim.Convolve(psf, pixel, real_space=True) conv.drawImage(img, scale=dx, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( img.array, saved_img.array, 5, err_msg= "Using GSObject Convolve(psf,pixel) disagrees with expected result") # The real-space convolution algorithm is not (trivially) independent of the order of # the two things being convolved. So check the opposite order. conv = galsim.Convolve([pixel, psf], real_space=True) conv.drawImage(img, scale=dx, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( img.array, saved_img.array, 5, err_msg= "Using GSObject Convolve([pixel,psf]) disagrees with expected result")
def _BuildCOSMOSGalaxy(config, base, ignore, gsparams, logger): """@brief Build a COSMOS galaxy using the cosmos_catalog input item. """ cosmos_cat = galsim.config.GetInputObj('cosmos_catalog', config, base, 'COSMOSGalaxy') ignore = ignore + ['num'] # Special: if galaxies are selected based on index, and index is Sequence or Random, and max # isn't set, set it to nobjects-1. if 'index' in config: galsim.config.SetDefaultIndex(config, cosmos_cat.getNObjects()) kwargs, safe = galsim.config.GetAllParams( config, base, req=galsim.COSMOSCatalog.makeGalaxy._req_params, opt=galsim.COSMOSCatalog.makeGalaxy._opt_params, single=galsim.COSMOSCatalog.makeGalaxy._single_params, ignore=ignore) if gsparams: kwargs['gsparams'] = galsim.GSParams(**gsparams) # Deal with defaults for gal_type, if it wasn't specified: # If COSMOSCatalog was constructed with 'use_real'=True, then default is 'real'. Otherwise, the # default is 'parametric'. This code is in makeGalaxy, but since config has to use # _makeSingleGalaxy, we have to include this here too. if 'gal_type' not in kwargs: if cosmos_cat.use_real: kwargs['gal_type'] = 'real' else: kwargs['gal_type'] = 'parametric' rng = None if 'index' not in kwargs: rng = galsim.config.GetRNG(config, base, logger, 'COSMOSGalaxy') kwargs['index'], n_rng_calls = cosmos_cat.selectRandomIndex( 1, rng=rng, _n_rng_calls=True) # Make sure this process gives consistent results regardless of the number of processes # being used. if not isinstance(cosmos_cat, galsim.COSMOSCatalog) and rng is not None: # Then cosmos_cat is really a proxy, which means the rng was pickled, so we need to # discard the same number of random calls from the one in the config dict. rng.discard(int(n_rng_calls)) # Even though gal_type is optional, it will have been set in the code above. So we can at this # point assume that kwargs['gal_type'] exists. if kwargs['gal_type'] == 'real': if rng is None: rng = galsim.config.GetRNG(config, base, logger, 'COSMOSGalaxy') kwargs['rng'] = rng # NB. Even though index is officially optional, it will always be present, either because it was # set by a call to selectRandomIndex, explicitly by the user, or due to the call to # SetDefaultIndex. index = kwargs['index'] if index >= cosmos_cat.getNObjects(): raise IndexError( "%s index has gone past the number of entries in the catalog" % index) logger.debug('obj %d: COSMOSGalaxy kwargs = %s', base.get('obj_num', 0), kwargs) kwargs['cosmos_catalog'] = cosmos_cat # Use a staticmethod of COSMOSCatalog to avoid pickling the result of makeGalaxy() # The RealGalaxy in particular has a large serialization, so it is more efficient to # make it in this process, which is what happens here. gal = galsim.COSMOSCatalog._makeSingleGalaxy(**kwargs) return gal, safe
def test_autoconvolve(): """Test that auto-convolution works the same as convolution with itself. """ dx = 0.4 myImg1 = galsim.ImageF(80, 80, scale=dx) myImg1.setCenter(0, 0) myImg2 = galsim.ImageF(80, 80, scale=dx) myImg2.setCenter(0, 0) psf = galsim.Moffat(beta=3.8, fwhm=1.3, flux=5) conv = galsim.Convolve([psf, psf]) conv.drawImage(myImg1, method='no_pixel') conv2 = galsim.AutoConvolve(psf) conv2.drawImage(myImg2, method='no_pixel') printval(myImg1, myImg2) np.testing.assert_array_almost_equal( myImg1.array, myImg2.array, 4, err_msg="Moffat convolved with self disagrees with AutoConvolve result" ) # Check with default_params conv = galsim.AutoConvolve(psf, gsparams=default_params) conv.drawImage(myImg1, method='no_pixel') np.testing.assert_array_almost_equal( myImg1.array, myImg2.array, 4, err_msg= "Using AutoConvolve with default_params disagrees with expected result" ) conv = galsim.AutoConvolve(psf, gsparams=galsim.GSParams()) conv.drawImage(myImg1, method='no_pixel') np.testing.assert_array_almost_equal( myImg1.array, myImg2.array, 4, err_msg= "Using AutoConvolve with GSParams() disagrees with expected result") check_basic(conv, "AutoConvolve(Moffat)") cen = galsim.PositionD(0, 0) np.testing.assert_equal(conv2.centroid, cen) np.testing.assert_almost_equal(conv2.flux, psf.flux**2) np.testing.assert_array_less(conv2.xValue(cen), conv2.max_sb) # Check picklability do_pickle(conv2, lambda x: x.drawImage(method='no_pixel')) do_pickle(conv2) # Test photon shooting. do_shoot(conv2, myImg2, "AutoConvolve(Moffat)") # For a symmetric profile, AutoCorrelate is the same thing: conv2 = galsim.AutoCorrelate(psf) conv2.drawImage(myImg2, method='no_pixel') printval(myImg1, myImg2) np.testing.assert_array_almost_equal( myImg1.array, myImg2.array, 4, err_msg="Moffat convolved with self disagrees with AutoCorrelate result" ) # And check AutoCorrelate with gsparams: conv2 = galsim.AutoCorrelate(psf, gsparams=default_params) conv2.drawImage(myImg1, method='no_pixel') np.testing.assert_array_almost_equal( myImg1.array, myImg2.array, 4, err_msg= "Using AutoCorrelate with default_params disagrees with expected result" ) conv2 = galsim.AutoCorrelate(psf, gsparams=galsim.GSParams()) conv2.drawImage(myImg1, method='no_pixel') np.testing.assert_array_almost_equal( myImg1.array, myImg2.array, 4, err_msg= "Using AutoCorrelate with GSParams() disagrees with expected result") cen = galsim.PositionD(0, 0) np.testing.assert_equal(conv2.centroid, cen) np.testing.assert_almost_equal(conv2.flux, psf.flux**2) np.testing.assert_array_less(conv2.xValue(cen), conv2.max_sb) # Also check AutoConvolve with an asymmetric profile. # (AutoCorrelate with this profile is done below...) obj1 = galsim.Gaussian(sigma=3., flux=4).shift(-0.2, -0.4) obj2 = galsim.Gaussian(sigma=6., flux=1.3).shift(0.3, 0.3) add = galsim.Add(obj1, obj2) conv = galsim.Convolve([add, add]) conv.drawImage(myImg1, method='no_pixel') autoconv = galsim.AutoConvolve(add) autoconv.drawImage(myImg2, method='no_pixel') printval(myImg1, myImg2) np.testing.assert_array_almost_equal( myImg1.array, myImg2.array, 4, err_msg= "Asymmetric sum of Gaussians convolved with self disagrees with " + "AutoConvolve result") cen = 2. * add.centroid np.testing.assert_equal(autoconv.centroid, cen) np.testing.assert_almost_equal(autoconv.flux, add.flux**2) np.testing.assert_array_less(autoconv.xValue(cen), autoconv.max_sb) check_basic(autoconv, "AutoConvolve(asym)") # Should raise an exception for invalid arguments assert_raises(TypeError, galsim.AutoConvolve) assert_raises(TypeError, galsim.AutoConvolve, myImg1) assert_raises(TypeError, galsim.AutoConvolve, [psf]) assert_raises(TypeError, galsim.AutoConvolve, psf, psf) assert_raises(TypeError, galsim.AutoConvolve, psf, realspace=False) assert_raises(TypeError, galsim.AutoConvolution) assert_raises(TypeError, galsim.AutoConvolution, myImg1) assert_raises(TypeError, galsim.AutoConvolution, [psf]) assert_raises(TypeError, galsim.AutoConvolution, psf, psf) assert_raises(TypeError, galsim.AutoConvolution, psf, realspace=False)
def __init__(self, lam_over_diam, defocus=0., astig1=0., astig2=0., coma1=0., coma2=0., trefoil1=0., trefoil2=0., spher=0., circular_pupil=True, obscuration=0., interpolant=None, oversampling=1.5, pad_factor=1.5, flux=1., gsparams=None): # Currently we load optics, noise etc in galsim/__init__.py, but this might change (???) import galsim.optics # Choose dx for lookup table using Nyquist for optical aperture and the specified # oversampling factor dx_lookup = .5 * lam_over_diam / oversampling # We need alias_threshold here, so don't wait to make this a default GSParams instance # if the user didn't specify anything else. if not gsparams: gsparams = galsim.GSParams() # Use a similar prescription as SBAiry to set Airy stepK and thus reference unpadded image # size in physical units stepk_airy = min( gsparams.alias_threshold * .5 * np.pi**3 * (1. - obscuration) / lam_over_diam, np.pi / 5. / lam_over_diam) # Boost Airy image size by a user-specifed pad_factor to allow for larger, aberrated PSFs, # also make npix always *odd* so that opticalPSF lookup table array is correctly centred: npix = 1 + 2 * (np.ceil(pad_factor * (np.pi / stepk_airy) / dx_lookup)).astype(int) # Make the psf image using this dx and array shape optimage = galsim.optics.psf_image(lam_over_diam=lam_over_diam, dx=dx_lookup, array_shape=(npix, npix), defocus=defocus, astig1=astig1, astig2=astig2, coma1=coma1, coma2=coma2, trefoil1=trefoil1, trefoil2=trefoil2, spher=spher, circular_pupil=circular_pupil, obscuration=obscuration, flux=flux) # If interpolant not specified on input, use a Quintic interpolant if interpolant is None: quintic = galsim.Quintic(tol=1e-4) self.interpolant = galsim.InterpolantXY(quintic) else: self.interpolant = galsim.utilities.convert_interpolant_to_2d( interpolant) # Initialize the SBProfile GSObject.__init__( self, galsim.SBInterpolatedImage(optimage, xInterp=self.interpolant, dx=dx_lookup, gsparams=gsparams)) # The above procedure ends up with a larger image than we really need, which # means that the default stepK value will be smaller than we need. # Thus, we call the function calculateStepK() to refine the value. self.SBProfile.calculateStepK() self.SBProfile.calculateMaxK()
def getStampBounds(self, gsObject, flux, image_pos, keep_sb_level, large_object_sb_level, Nmax=1400, pixel_scale=0.2): """ Get the postage stamp bounds for drawing an object within the stamp to include the specified minimum surface brightness. Use the folding_threshold criterion for point source objects. For extended objects, use the getGoodPhotImageSize function, where if the initial stamp is too large (> Nmax**2 ~ 1GB of RSS memory for a 72 vertex/pixel sensor model), use the relaxed surface brightness level for large objects. Parameters ---------- gsObject: GalSimCelestialObject This contains the information needed to construct a galsim.GSObject convolved with the desired PSF. flux: float The flux of the object in e-. keep_sb_level: float The minimum surface brightness (photons/pixel) out to which to extend the postage stamp, e.g., a value of sqrt(sky_bg_per_pixel)/3 would be 1/3 the Poisson noise per pixel from the sky background. large_object_sb_level: float Surface brightness level to use for large/bright objects that would otherwise yield stamps with more than Nmax**2 pixels. Nmax: int [1400] The largest stamp size to consider at the nominal keep_sb_level. 1400**2*72*8/1024**3 = 1GB. pixel_scale: float [0.2] The CCD pixel scale in arcsec. Returns ------- galsim.BoundsI: The postage stamp bounds. """ if flux < 10: # For really faint things, don't try too hard. Just use 32x32. image_size = 32 elif gsObject.galSimType.lower() == "pointsource": # For bright stars, set the folding threshold for the # stamp size calculation. Use a # Kolmogorov_and_Gaussian_PSF since it is faster to # evaluate than an AtmosphericPSF. folding_threshold = self.sky_bg_per_pixel/flux if folding_threshold >= self._ft_default: gsparams = None else: gsparams = galsim.GSParams(folding_threshold=folding_threshold) psf = Kolmogorov_and_Gaussian_PSF(airmass=self._airmass, rawSeeing=self._rawSeeing, band=self._band, gsparams=gsparams) obj = self.drawPointSource(gsObject, psf=psf) image_size = obj.getGoodImageSize(pixel_scale) else: # For extended objects, recreate the object to draw, but # convolved with the faster DoubleGaussian PSF. obj = self.createCenteredObject(gsObject, psf=self._double_gaussian_psf) obj = obj.withFlux(flux) # Start with GalSim's estimate of a good box size. image_size = obj.getGoodImageSize(pixel_scale) # For bright things, defined as having an average of at least 10 photons per # pixel on average, try to be careful about not truncating the surface brightness # at the edge of the box. if flux > 10 * image_size**2: image_size = getGoodPhotImageSize(obj, keep_sb_level, pixel_scale=pixel_scale) # If the above size comes out really huge, scale back to what you get for # a somewhat brighter surface brightness limit. if image_size > Nmax: image_size = getGoodPhotImageSize(obj, large_object_sb_level, pixel_scale=pixel_scale) image_size = max(image_size, Nmax) # Create the bounds object centered on the desired location. xmin = int(math.floor(image_pos.x) - image_size/2) xmax = int(math.ceil(image_pos.x) + image_size/2) ymin = int(math.floor(image_pos.y) - image_size/2) ymax = int(math.ceil(image_pos.y) + image_size/2) return galsim.BoundsI(xmin, xmax, ymin, ymax)
def test_OpticalPSF_pupil_plane(): """Test the ability to generate a PSF using an image of the pupil plane. """ # Test case: lam/diam=0.12, obscuration=0.18, 4 struts of the default width and with rotation # from the vertical of -15 degrees. There are two versions of these tests at different # oversampling levels. # # To (re-)generate the pupil plane images for this test, simply delete # tests/Optics_comparison_images/sample_pupil_rolled.fits and # tests/Optics_comparison_images/sample_pupil_rolled_oversample.fits.gz, # and then rerun this function. Note that these images are also used in test_ne(), so there # may be some racing if this script is tested in parallel before the fits files are regenerated. # First test: should get excellent agreement between that particular OpticalPSF with specified # options and one from loading the pupil plane image. Note that this won't work if you change # the optical PSF parameters, unless you also regenerate the test image. lam_over_diam = 0.12 obscuration = 0.18 nstruts = 4 strut_angle = -15. * galsim.degrees scale = 0.055 ref_psf = galsim.OpticalPSF(lam_over_diam, obscuration=obscuration, nstruts=nstruts, oversampling=pp_oversampling, strut_angle=strut_angle, pad_factor=pp_pad_factor) if os.path.isfile(os.path.join(imgdir, pp_file)): im = galsim.fits.read(os.path.join(imgdir, pp_file)) else: import warnings warnings.warn( "Could not find file {0}, so generating it from scratch. This should only " "happen if you intentionally deleted the file in order to regenerate it!" .format(pp_file)) im = galsim.Image(ref_psf._psf.aper.illuminated.astype(float)) im.scale = ref_psf._psf.aper.pupil_plane_scale print('pupil_plane image has scale = ', pp_scale) im.write(os.path.join(imgdir, pp_file)) pp_scale = im.scale print('pupil_plane image has scale = ', pp_scale) # For most of the tests, we remove this scale, since for achromatic tests, you don't really # need it, and it is invalid to give lam_over_diam (rather than lam, diam separately) when # there is a specific scale for the pupil plane image. But see the last test below where # we do use lam, diam separately with the input image. im.scale = None # This implies that the lam_over_diam value test_psf = galsim.OpticalPSF(lam_over_diam, obscuration=obscuration, oversampling=pp_oversampling, pupil_plane_im=im, pad_factor=pp_pad_factor) im_ref_psf = ref_psf.drawImage(scale=scale) im_test_psf = galsim.ImageD(im_ref_psf.array.shape[0], im_ref_psf.array.shape[1]) im_test_psf = test_psf.drawImage(image=im_test_psf, scale=scale) if pp_test_type == 'image': np.testing.assert_array_almost_equal( im_test_psf.array, im_ref_psf.array, decimal=pp_decimal, err_msg= "Inconsistent OpticalPSF image for basic model after loading pupil plane." ) else: test_moments = im_test_psf.FindAdaptiveMom() ref_moments = im_ref_psf.FindAdaptiveMom() np.testing.assert_almost_equal( test_moments.moments_sigma, ref_moments.moments_sigma, decimal=pp_decimal, err_msg= "Inconsistent OpticalPSF image for basic model after loading pupil plane." ) if do_slow_tests: do_pickle( test_psf, lambda x: x.drawImage(nx=20, ny=20, scale=0.07, method='no_pixel')) do_pickle(test_psf) # It is supposed to be able to figure this out even if we *don't* tell it the pad factor. So # make sure that it still works even if we don't tell it that value. test_psf = galsim.OpticalPSF(lam_over_diam, obscuration=obscuration, pupil_plane_im=im, oversampling=pp_oversampling) im_test_psf = galsim.ImageD(im_ref_psf.array.shape[0], im_ref_psf.array.shape[1]) im_test_psf = test_psf.drawImage(image=im_test_psf, scale=scale) if pp_test_type == 'image': np.testing.assert_array_almost_equal( im_test_psf.array, im_ref_psf.array, decimal=pp_decimal, err_msg= "Inconsistent OpticalPSF image for basic model after loading pupil plane without " "specifying parameters.") else: test_moments = im_test_psf.FindAdaptiveMom() ref_moments = im_ref_psf.FindAdaptiveMom() np.testing.assert_almost_equal( test_moments.moments_sigma, ref_moments.moments_sigma, decimal=pp_decimal, err_msg= "Inconsistent OpticalPSF image for basic model after loading pupil plane without " "specifying parameters.") # Next test (less trivial): Rotate the struts by +27 degrees, and check that agreement is # good. This is making sure that the linear interpolation that is done when rotating does not # result in significant loss of accuracy. rot_angle = 27. * galsim.degrees ref_psf = galsim.OpticalPSF(lam_over_diam, obscuration=obscuration, nstruts=nstruts, strut_angle=strut_angle + rot_angle, oversampling=pp_oversampling, pad_factor=pp_pad_factor) test_psf = galsim.OpticalPSF(lam_over_diam, obscuration=obscuration, pupil_plane_im=im, pupil_angle=rot_angle, oversampling=pp_oversampling, pad_factor=pp_pad_factor) im_ref_psf = ref_psf.drawImage(scale=scale) im_test_psf = galsim.ImageD(im_ref_psf.array.shape[0], im_ref_psf.array.shape[1]) im_test_psf = test_psf.drawImage(image=im_test_psf, scale=scale) # We are slightly less stringent here since it should not be exact. if pp_test_type == 'image': np.testing.assert_array_almost_equal( im_test_psf.array, im_ref_psf.array, decimal=pp_decimal - 1, err_msg= "Inconsistent OpticalPSF image for rotated model after loading pupil plane." ) else: test_moments = im_test_psf.FindAdaptiveMom() ref_moments = im_ref_psf.FindAdaptiveMom() np.testing.assert_almost_equal( test_moments.moments_sigma, ref_moments.moments_sigma, decimal=pp_decimal - 1, err_msg= "Inconsistent OpticalPSF image for rotated model after loading pupil plane." ) # Now include aberrations. Here we are testing the ability to figure out the pupil plane extent # and sampling appropriately. Those get fed into the routine for making the aberrations. defocus = -0.03 coma1 = 0.03 spher = -0.02 ref_psf = galsim.OpticalPSF(lam_over_diam, obscuration=obscuration, nstruts=nstruts, strut_angle=strut_angle, defocus=defocus, coma1=coma1, spher=spher, oversampling=pp_oversampling, pad_factor=pp_pad_factor) test_psf = galsim.OpticalPSF(lam_over_diam, obscuration=obscuration, pupil_plane_im=im, defocus=defocus, coma1=coma1, spher=spher, oversampling=pp_oversampling, pad_factor=pp_pad_factor) im_ref_psf = ref_psf.drawImage(scale=scale) im_test_psf = galsim.ImageD(im_ref_psf.array.shape[0], im_ref_psf.array.shape[1]) im_test_psf = test_psf.drawImage(image=im_test_psf, scale=scale) if pp_test_type == 'image': np.testing.assert_array_almost_equal( im_test_psf.array, im_ref_psf.array, decimal=pp_decimal, err_msg= "Inconsistent OpticalPSF image for aberrated model after loading pupil plane." ) else: test_moments = im_test_psf.FindAdaptiveMom() ref_moments = im_ref_psf.FindAdaptiveMom() np.testing.assert_almost_equal( test_moments.moments_sigma, ref_moments.moments_sigma, decimal=pp_decimal, err_msg= "Inconsistent OpticalPSF image for aberrated model after loading pupil plane." ) # Test for preservation of symmetries: the result should be the same if the pupil plane is # rotated by integer multiples of 2pi/(nstruts). ref_psf = galsim.OpticalPSF(lam_over_diam, obscuration=obscuration, nstruts=nstruts, strut_angle=strut_angle, oversampling=pp_oversampling, pad_factor=pp_pad_factor) im_ref_psf = ref_psf.drawImage(scale=scale) for ind in range(1, nstruts): rot_angle = ind * 2. * np.pi / nstruts test_psf = galsim.OpticalPSF(lam_over_diam, obscuration=obscuration, pupil_plane_im=im, pupil_angle=rot_angle * galsim.radians, oversampling=pp_oversampling, pad_factor=pp_pad_factor) im_test_psf = galsim.ImageD(im_ref_psf.array.shape[0], im_ref_psf.array.shape[1]) im_test_psf = test_psf.drawImage(image=im_test_psf, scale=scale) if pp_test_type == 'image': np.testing.assert_array_almost_equal( im_test_psf.array, im_ref_psf.array, decimal=pp_decimal, err_msg= "Inconsistent OpticalPSF image after rotating pupil plane by invariant " "angle.") else: test_moments = im_test_psf.FindAdaptiveMom() ref_moments = im_test_psf.FindAdaptiveMom() np.testing.assert_almost_equal( test_moments.moments_sigma, ref_moments.moments_sigma, decimal=pp_decimal, err_msg= "Inconsistent OpticalPSF image after rotating pupil plane by invariant " "angle.") # Test that if we rotate pupil plane with no aberrations, that's equivalent to rotating the PSF # itself. Use rotation angle of 90 degrees so numerical issues due to the interpolation should # be minimal. rot_angle = 90. * galsim.degrees psf_1 = galsim.OpticalPSF(lam_over_diam, obscuration=obscuration, pupil_plane_im=im, oversampling=pp_oversampling, pad_factor=pp_pad_factor) rot_psf_1 = psf_1.rotate(rot_angle) psf_2 = galsim.OpticalPSF(lam_over_diam, obscuration=obscuration, pupil_plane_im=im, pupil_angle=rot_angle, oversampling=pp_oversampling, pad_factor=pp_pad_factor) im_1 = psf_1.drawImage(scale=scale) im_2 = galsim.ImageD(im_1.array.shape[0], im_1.array.shape[1]) im_2 = psf_2.drawImage(image=im_2, scale=scale) if pp_test_type == 'image': np.testing.assert_array_almost_equal( im_1.array, im_2.array, decimal=pp_decimal, err_msg= "Inconsistent OpticalPSF image after rotating pupil plane vs. rotating PSF." ) else: test_moments = im_1.FindAdaptiveMom() ref_moments = im_2.FindAdaptiveMom() np.testing.assert_almost_equal( test_moments.moments_sigma, ref_moments.moments_sigma, decimal=pp_decimal, err_msg= "Inconsistent OpticalPSF image after rotating pupil plane vs. rotating PSF." ) # Supply the pupil plane at higher resolution, and make sure that the routine figures out the # sampling and gets the right image scale etc. gsp = galsim.GSParams(maximum_fft_size=8192) rescale_fac = 0.77 ref_psf = galsim.OpticalPSF(lam_over_diam, obscuration=obscuration, nstruts=nstruts, strut_angle=strut_angle, oversampling=pp_oversampling, pad_factor=pp_pad_factor / rescale_fac, gsparams=gsp) # Make higher resolution pupil plane image via interpolation int_im = galsim.InterpolatedImage(galsim.Image(im, scale=1.0, dtype=np.float32), calculate_maxk=False, calculate_stepk=False, x_interpolant='linear') new_im = int_im.drawImage(scale=rescale_fac, method='no_pixel') new_im.scale = None # Let OpticalPSF figure out the scale automatically. test_psf = galsim.OpticalPSF(lam_over_diam, obscuration=obscuration, pupil_plane_im=new_im, oversampling=pp_oversampling, gsparams=gsp) im_ref_psf = ref_psf.drawImage(scale=scale) im_test_psf = galsim.ImageD(im_ref_psf.array.shape[0], im_ref_psf.array.shape[1]) im_test_psf = test_psf.drawImage(image=im_test_psf, scale=scale) test_moments = im_test_psf.FindAdaptiveMom() ref_moments = im_ref_psf.FindAdaptiveMom() if pp_test_type == 'image': np.testing.assert_almost_equal( test_moments.moments_sigma / ref_moments.moments_sigma - 1., 0, decimal=2, err_msg= "Inconsistent OpticalPSF image for basic model after loading high-res pupil plane." ) else: np.testing.assert_almost_equal( test_moments.moments_sigma / ref_moments.moments_sigma - 1., 0, decimal=1, err_msg= "Inconsistent OpticalPSF image for basic model after loading high-res pupil plane." ) # Now supply the pupil plane at the original resolution, but remove some of the padding. We # want it to properly recognize that it needs more padding, and include it. remove_pad = -23 sub_im = im[im.bounds.withBorder(remove_pad)] test_psf = galsim.OpticalPSF(lam_over_diam, obscuration=obscuration, pupil_plane_im=sub_im, oversampling=pp_oversampling, pad_factor=pp_pad_factor) im_test_psf = galsim.ImageD(im_ref_psf.array.shape[0], im_ref_psf.array.shape[1]) im_test_psf = test_psf.drawImage(image=im_test_psf, scale=scale) test_moments = im_test_psf.FindAdaptiveMom() ref_moments = im_ref_psf.FindAdaptiveMom() np.testing.assert_almost_equal( test_moments.moments_sigma / ref_moments.moments_sigma - 1., 0, decimal=pp_decimal - 3, err_msg= "Inconsistent OpticalPSF image for basic model after loading less padded pupil plane." ) # Now supply the pupil plane at the original resolution, with extra padding. new_pad = 76 big_im = galsim.Image(im.bounds.withBorder(new_pad)) big_im[im.bounds] = im test_psf = galsim.OpticalPSF(lam_over_diam, obscuration=obscuration, pupil_plane_im=big_im, oversampling=pp_oversampling, pad_factor=pp_pad_factor, gsparams=gsp) im_test_psf = galsim.ImageD(im_ref_psf.array.shape[0], im_ref_psf.array.shape[1]) im_test_psf = test_psf.drawImage(image=im_test_psf, scale=scale) test_moments = im_test_psf.FindAdaptiveMom() ref_moments = im_ref_psf.FindAdaptiveMom() np.testing.assert_almost_equal( test_moments.moments_sigma, ref_moments.moments_sigma, decimal=pp_decimal - 2, err_msg="Inconsistent OpticalPSF image size for basic model " "after loading more padded pupil plane.") # Check for same answer if we use image, array, or filename for reading in array. test_psf = galsim.OpticalPSF(lam_over_diam, obscuration=obscuration, pupil_plane_im=im, oversampling=pp_oversampling, pad_factor=pp_pad_factor) im_test_psf = test_psf.drawImage(scale=scale) test_psf_2 = galsim.OpticalPSF(lam_over_diam, obscuration=obscuration, pupil_plane_im=im.array, oversampling=pp_oversampling, pad_factor=pp_pad_factor) im_test_psf_2 = test_psf_2.drawImage(scale=scale) np.testing.assert_almost_equal( im_test_psf.array, im_test_psf_2.array, decimal=pp_decimal, err_msg="Inconsistent OpticalPSF image from Image vs. array.") # The following had used lam_over_diam, but that is now invalid because the fits file # has a specific pixel scale. So we need to provide lam and diam separately so that the # units are consistent. diam = 500.e-9 / lam_over_diam * galsim.radians / galsim.arcsec test_psf_3 = galsim.OpticalPSF(lam=500, diam=diam, obscuration=obscuration, oversampling=pp_oversampling, pupil_plane_im=os.path.join( imgdir, pp_file), pad_factor=pp_pad_factor) im_test_psf_3 = test_psf_3.drawImage(scale=scale) np.testing.assert_almost_equal( im_test_psf.array, im_test_psf_3.array, decimal=pp_decimal, err_msg="Inconsistent OpticalPSF image from Image vs. file read-in.")
def test_realspace_convolve(): """Test the real-space convolution of a Moffat and a Box SBProfile against a known result. """ import time t1 = time.time() # Code was formerly: # mySBP = galsim.SBMoffat(beta=1.5, truncationFWHM=4, flux=1, half_light_radius=1) # # ...but this is no longer quite so simple since we changed the handling of trunc to be in # physical units. However, the same profile can be constructed using # fwhm=1.0927449310213702, # as calculated by interval bisection in devutils/external/calculate_moffat_radii.py fwhm_backwards_compatible = 1.0927449310213702 #psf = galsim.SBMoffat(beta=1.5, fwhm=fwhm_backwards_compatible, #trunc=4*fwhm_backwards_compatible, flux=1) psf = galsim.SBMoffat(beta=1.5, half_light_radius=1, trunc=4 * fwhm_backwards_compatible, flux=1) pixel = galsim.SBBox(xw=0.2, yw=0.2, flux=1.) conv = galsim.SBConvolve([psf, pixel], real_space=True) # Note: Using an image created from Maple "exact" calculations. saved_img = galsim.fits.read(os.path.join(imgdir, "moffat_pixel.fits")) img = galsim.ImageF(saved_img.bounds, scale=0.2) conv.draw(img.view()) printval(img, saved_img) arg = abs(saved_img.array - img.array).argmax() np.testing.assert_array_almost_equal( img.array, saved_img.array, 5, err_msg= "Moffat convolved with Box SBProfile disagrees with expected result") # Repeat with the GSObject version of this: psf = galsim.Moffat(beta=1.5, half_light_radius=1, trunc=4 * fwhm_backwards_compatible, flux=1) #psf = galsim.Moffat(beta=1.5, fwhm=fwhm_backwards_compatible, #trunc=4*fwhm_backwards_compatible, flux=1) pixel = galsim.Pixel(xw=0.2, yw=0.2, flux=1.) conv = galsim.Convolve([psf, pixel], real_space=True) conv.draw(img, dx=0.2, normalization="surface brightness", use_true_center=False) np.testing.assert_array_almost_equal( img.array, saved_img.array, 5, err_msg= "Using GSObject Convolve([psf,pixel]) disagrees with expected result") # Check with default_params conv = galsim.Convolve([psf, pixel], real_space=True, gsparams=default_params) conv.draw(img, dx=0.2, normalization="surface brightness", use_true_center=False) np.testing.assert_array_almost_equal( img.array, saved_img.array, 5, err_msg= "Using GSObject Convolve([psf,pixel]) with default_params disagrees with " "expected result") conv = galsim.Convolve([psf, pixel], real_space=True, gsparams=galsim.GSParams()) conv.draw(img, dx=0.2, normalization="surface brightness", use_true_center=False) np.testing.assert_array_almost_equal( img.array, saved_img.array, 5, err_msg= "Using GSObject Convolve([psf,pixel]) with GSParams() disagrees with " "expected result") # Other ways to do the convolution: conv = galsim.Convolve(psf, pixel, real_space=True) conv.draw(img, dx=0.2, normalization="surface brightness", use_true_center=False) np.testing.assert_array_almost_equal( img.array, saved_img.array, 5, err_msg= "Using GSObject Convolve(psf,pixel) disagrees with expected result") # The real-space convolution algorithm is not (trivially) independent of the order of # the two things being convolved. So check the opposite order. conv = galsim.Convolve([pixel, psf], real_space=True) conv.draw(img, dx=0.2, normalization="surface brightness", use_true_center=False) np.testing.assert_array_almost_equal( img.array, saved_img.array, 5, err_msg= "Using GSObject Convolve([pixel,psf]) disagrees with expected result") # Test kvalues do_kvalue(conv, "Truncated Moffat convolved with Box") t2 = time.time() print 'time for %s = %.2f' % (funcname(), t2 - t1)