def test_real_galaxy_makeFromImage(): """Test accuracy of various calculations with fake Gaussian RealGalaxy vs. ideal expectations""" # read in faked Gaussian RealGalaxy from file rgc = galsim.RealGalaxyCatalog(catalog_file, dir=image_dir) rg = galsim.RealGalaxy(rgc, index=1) gal_image = rg.gal_image psf = rg.original_psf xi = rg.noise rg_2 = galsim.RealGalaxy.makeFromImage(gal_image, psf, xi) check_basic(rg_2, "RealGalaxy", approx_maxsb=True) do_pickle( rg_2, lambda x: [ x.gal_image, x.psf_image, repr(x.noise), x.original_psf.flux, x.original_gal.flux, x.flux ]) do_pickle(rg_2, lambda x: x.drawImage(nx=20, ny=20, scale=0.7)) do_pickle(rg_2) # See if we get reasonably consistent results for rg and rg_2 psf = galsim.Kolmogorov(fwhm=0.6) obj1 = galsim.Convolve(psf, rg) obj2 = galsim.Convolve(psf, rg_2) im1 = obj1.drawImage(scale=0.2, nx=12, ny=12) im2 = obj2.drawImage(image=im1.copy()) atol = obj1.flux * 3e-5 np.testing.assert_allclose(im1.array, im2.array, rtol=0, atol=atol)
def __init__(self, airmass=1.2, rawSeeing=0.7, band='r', gsparams=None): """ Parameters ---------- airmass rawSeeing is the FWHM seeing at zenith at 500 nm in arc seconds (provided by OpSim) band is the bandpass of the observation [u,g,r,i,z,y] """ # This code was provided by David Kirkby in a private communication wlen_eff = dict(u=365.49, g=480.03, r=622.20, i=754.06, z=868.21, y=991.66)[band] # wlen_eff is from Table 2 of LSE-40 (y=y2) FWHMatm = rawSeeing * (wlen_eff / 500.)**-0.3 * airmass**0.6 # From LSST-20160 eqn (4.1) FWHMsys = numpy.sqrt(0.25**2 + 0.3**2 + 0.08**2) * airmass**0.6 # From LSST-20160 eqn (4.2) atm = galsim.Kolmogorov(fwhm=FWHMatm, gsparams=gsparams) sys = galsim.Gaussian(fwhm=FWHMsys, gsparams=gsparams) psf = galsim.Convolve((atm, sys)) self._cached_psf = psf
def make_star(hlr, g1, g2, u0, v0, flux, noise=0., du=1., fpu=0., fpv=0., nside=32, nom_u0=0., nom_v0=0., rng=None): """Make a Star instance filled with a Kolmogorov profile :param hlr: The half_light_radius of the Kolmogorov. :param g1, g2: Shear applied to profile. :param u0, v0: The sub-pixel offset to apply. :param flux: The flux of the star :param noise: RMS Gaussian noise to be added to each pixel [default: 0] :param du: pixel size in "wcs" units [default: 1.] :param fpu,fpv: position of this cutout in some larger focal plane [default: 0,0] :param nside: The size of the array [default: 32] :param nom_u0, nom_v0: The nominal u0,v0 in the StarData [default: 0,0] :param rng: If adding noise, the galsim deviate to use for the random numbers [default: None] """ k = galsim.Kolmogorov(half_light_radius=hlr, flux=flux).shear(g1=g1, g2=g2).shift(u0,v0) if noise == 0.: var = 0.1 else: var = noise star = piff.Star.makeTarget(x=nside/2+nom_u0/du, y=nside/2+nom_v0/du, u=fpu*du, v=fpv*du, scale=du, stamp_size=nside) star.image.setOrigin(0,0) k.drawImage(star.image, method='no_pixel', offset=galsim.PositionD(nom_u0/du,nom_v0/du), use_true_center=False) star.data.weight = star.image.copy() star.weight.fill(1./var/var) if noise != 0: gn = galsim.GaussianNoise(sigma=noise, rng=rng) star.image.addNoise(gn) return star
def Kolmogorov_and_Gaussian_PSF(self, airmass=1.2, rawSeeing=0.7, band='r', gsparams=None): """ This PSF class is based on David Kirkby's presentation to the DESC Survey Simulations working group on 23 March 2017. https://confluence.slac.stanford.edu/pages/viewpage.action?spaceKey=LSSTDESC&title=SSim+2017-03-23 (you will need a SLAC Confluence account to access that link) Parameters ---------- airmass rawSeeing is the FWHM seeing at zenith at 500 nm in arc seconds (provided by OpSim) band is the bandpass of the observation [u,g,r,i,z,y] """ # This code was provided by David Kirkby in a private communication wlen_eff = dict(u=365.49, g=480.03, r=622.20, i=754.06, z=868.21, y=991.66)[band] # wlen_eff is from Table 2 of LSE-40 (y=y2) FWHMatm = rawSeeing * (wlen_eff / 500.) ** -0.3 * airmass ** 0.6 # From LSST-20160 eqn (4.1) FWHMsys = np.sqrt(0.25**2 + 0.3**2 + 0.08**2) * airmass ** 0.6 # From LSST-20160 eqn (4.2) atm = galsim.Kolmogorov(fwhm=FWHMatm, gsparams=gsparams) sys = galsim.Gaussian(fwhm=FWHMsys, gsparams=gsparams) return galsim.Convolve((atm, sys))
def make_fft_psf(self, psf, logger): """Swap out any PhaseScreenPSF component with a roughly equivalent analytic approximation. """ if isinstance(psf, galsim.Transformation): return galsim.Transformation(self.make_fft_psf(psf.original, logger), psf.jac, psf.offset, psf.flux_ratio, psf.gsparams) elif isinstance(psf, galsim.Convolution): obj_list = [self.make_fft_psf(p, logger) for p in psf.obj_list] return galsim.Convolution(obj_list, gsparams=psf.gsparams) elif isinstance(psf, galsim.PhaseScreenPSF): # If psf is a PhaseScreenPSF, then make a simpler one the just convolves # a Kolmogorov profile with an OpticalPSF. r0_500 = psf.screen_list.r0_500_effective atm_psf = galsim.Kolmogorov(lam=psf.lam, r0_500=r0_500, gsparams=psf.gsparams) opt_screens = [s for s in psf.screen_list if isinstance(s, galsim.OpticalScreen)] logger.info('opt_screens = %r',opt_screens) if len(opt_screens) >= 1: # Should never be more than 1, but if there weirdly is, just use the first. opt_screen = opt_screens[0] optical_psf = galsim.OpticalPSF( lam=psf.lam, diam=opt_screen.diam, aberrations=opt_screen.aberrations, annular_zernike=opt_screen.annular_zernike, obscuration=opt_screen.obscuration, gsparams=psf.gsparams) return galsim.Convolve([atm_psf, optical_psf], gsparams=psf.gsparams) else: return atm_psf else: return psf
def test_vk_fitting_formulae(): # lam, r0_500, L0 params = [(650, 0.15, 10.0), (450, 0.12, 25.0), (900, 0.18, 100.0)] def predicted_FWHM_ratio(r0, L0): """Fitting formula for VonKarman FWHM / Kolmogorov FWHM from Martinez++2014 """ return np.sqrt(1 - 2.183 * (r0 / L0)**0.356) def predicted_HLR_ratio(r0, L0): """Fitting formula for VonKarman HLR / Kolmogorov HLR from Martinez++2014 """ return np.sqrt(1 - 1.534 * (r0 / L0)**0.347) for lam, r0_500, L0 in params: print(lam, r0_500, L0) r0 = r0_500 * (lam / 500.0)**(6. / 5) kolm = galsim.Kolmogorov(lam=lam, r0=r0) vk = galsim.VonKarman(lam=lam, r0=r0, L0=L0) vk2 = galsim.VonKarman(lam=lam, r0_500=r0_500, L0=L0) np.testing.assert_allclose(vk.r0, vk2.r0) np.testing.assert_allclose(vk.r0_500, vk2.r0_500) for prof in [vk, vk2]: HLR_ratio = prof.calculateHLR() / kolm.calculateHLR() FWHM_ratio = prof.calculateFWHM() / kolm.calculateFWHM() print(HLR_ratio) print(FWHM_ratio) np.testing.assert_allclose(HLR_ratio, predicted_HLR_ratio(r0, L0), rtol=0.015) np.testing.assert_allclose(FWHM_ratio, predicted_FWHM_ratio(r0, L0), rtol=0.015)
def _vkSeeing(r0_500, wavelength, L0): # von Karman profile FWHM from Tokovinin fitting formula kolm_seeing = galsim.Kolmogorov(r0_500=r0_500, lam=wavelength).fwhm r0 = r0_500 * (wavelength / 500)**1.2 arg = 1. - 2.183 * (r0 / L0)**0.356 factor = np.sqrt(arg) if arg > 0.0 else 0.0 return kolm_seeing * factor
def test_kolmogorov_folding_threshold(): """Test Kolmogorov with low folding_threshold. """ # This test reproduces a bug reported by Jim Chiang when Kolmogorov has a less than # default folding_threshold. Reported in Issue #952. # It turned out the problem was in OneDimensionalDeviate's findExtremum going into an # endless loop, mostly because it didn't preserve the intended invariant that x1 < x2 < x3. # In this case, x1 became the largest of the three values and ended up getting larger and # larger indefinitely, thus resulting in an endless loop. # The test is really just to construct the object in finite time, but we do a few sanity # checks afterward for good measure. fwhm = 0.55344217545630736 folding_threshold = 0.0008316873626901008 gsparams = galsim.GSParams(folding_threshold=folding_threshold) obj = galsim.Kolmogorov(fwhm=fwhm, gsparams=gsparams) print('obj = ', obj) assert obj.flux == 1.0 assert obj.fwhm == fwhm assert obj.gsparams.folding_threshold == folding_threshold check_basic(obj, 'Kolmogorov with low folding_threshold') do_pickle(obj)
def test_shearest_shape(): """Test that shear estimation is insensitive to shape of input images.""" # this test can help reveal bugs having to do with x / y indexing issues # just do test for one particular gaussian g1 = shear_values[1] g2 = shear_values[2] e1_psf = 0.05 e2_psf = -0.04 total_shear = np.sqrt(g1**2 + g2**2) conversion_factor = np.tanh(2.0 * math.atanh(total_shear)) / total_shear distortion_1 = g1 * conversion_factor distortion_2 = g2 * conversion_factor gal = galsim.Exponential(flux=1.0, half_light_radius=1.) gal = gal.shear(g1=g1, g2=g2) psf = galsim.Kolmogorov(flux=1.0, fwhm=0.7) psf = psf.shear(e1=e1_psf, e2=e2_psf) final = galsim.Convolve([gal, psf]) imsize = [128, 256] for method_index in range(len(correction_methods)): print(correction_methods[method_index]) save_e1 = -100. save_e2 = -100. for gal_x_imsize in imsize: for gal_y_imsize in imsize: for psf_x_imsize in imsize: for psf_y_imsize in imsize: final_image = galsim.ImageF(gal_x_imsize, gal_y_imsize) epsf_image = galsim.ImageF(psf_x_imsize, psf_y_imsize) final.drawImage(image=final_image, scale=pixel_scale, method='no_pixel') psf.drawImage(image=epsf_image, scale=pixel_scale, method='no_pixel') result = galsim.hsm.EstimateShear( final_image, epsf_image, shear_est=correction_methods[method_index]) e1 = result.corrected_e1 e2 = result.corrected_e2 # make sure answers don't change as we vary image size tot_e = np.sqrt(save_e1**2 + save_e2**2) if tot_e < 99.: np.testing.assert_almost_equal( e1, save_e1, err_msg="- incorrect e1", decimal=decimal_shape) np.testing.assert_almost_equal( e2, save_e2, err_msg="- incorrect e2", decimal=decimal_shape) save_e1 = e1 save_e2 = e2
def __init__(self, fastfit=False, force_model_center=True, include_pixel=True, logger=None): import galsim gsobj = galsim.Kolmogorov(half_light_radius=1.0) GSObjectModel.__init__(self, gsobj, fastfit, force_model_center, include_pixel, logger) # We'd need self.kwargs['gsobj'] if we were reconstituting via the GSObjectModel # constructor, but since config['type'] for this will be Kolmogorov, it gets reconstituted # here, where there is no `gsobj` argument. So remove `gsobj` from kwargs. del self.kwargs['gsobj']
def get_atmospheric_psf(self, wavelength, fwhm5400, gauss=False): wlen_ratio = (wavelength / (5400 * u.Angstrom)).si assert wlen_ratio == wlen_ratio.value, 'wavelength has invalid units.' fwhm = fwhm5400.to(u.arcsec).value * wlen_ratio**(-0.2) # Kolmogorov requires floats as inputs, not numpy scalars. if gauss: return galsim.Gaussian(fwhm=float(fwhm)) else: return galsim.Kolmogorov(fwhm=float(fwhm))
def test_ne(): """Test base.py GSObjects for not-equals.""" # Define some universal gsps gsp = galsim.GSParams(maxk_threshold=1.1e-3, folding_threshold=5.1e-3) # Kolmogorov. Params include lam_over_r0, fwhm, half_light_radius, lam/r0, lam/r0_500, flux # gsparams. # The following should all test unequal: gals = [galsim.Kolmogorov(lam_over_r0=1.0), galsim.Kolmogorov(lam=1.0, r0=1.1), galsim.Kolmogorov(fwhm=1.0), galsim.Kolmogorov(half_light_radius=1.0), galsim.Kolmogorov(lam=1.0, r0=1.0), galsim.Kolmogorov(lam=1.0, r0=1.0, scale_unit=galsim.arcmin), galsim.Kolmogorov(lam=1.0, r0=1.0, scale_unit='degrees'), galsim.Kolmogorov(lam=1.0, r0_500=1.0), galsim.Kolmogorov(lam=1.0, r0=1.0, flux=1.1), galsim.Kolmogorov(lam=1.0, r0=1.0, flux=1.1, gsparams=gsp)] all_obj_diff(gals)
def createPSF(self, galaxyIndex): """ Returns a GalSim model of the PSF for the specified galaxy index. """ catalog = self.getTruthCatalog() keys = catalog.columns.names params = catalog[galaxyIndex] # Create an empty list of models that will be convolved for the final PSF. models = [] # Add jitter contribution if provided. if 'opt_psf_jitter_sigma' in keys: jitterPSF = galsim.Gaussian( sigma=params['opt_psf_jitter_sigma']).shear( beta=params['opt_psf_jitter_beta'] * galsim.degrees, e=params['opt_psf_jitter_e']) models.append(jitterPSF) # Add charge diffusion contribution if provided. if 'opt_psf_charge_sigma' in keys: chargePSF = galsim.Gaussian( sigma=params['opt_psf_charge_sigma']).shear( e1=params['opt_psf_charge_e1'], e2=0.) models.append(chargePSF) # Create the optical component, which is always present. kmap = { 'opt_psf_lam_over_diam': 'lam_over_diam', 'opt_psf_obscuration': 'obscuration', 'opt_psf_n_struts': 'nstruts', 'opt_psf_strut_angle': 'strut_angle', 'opt_psf_pad_factor': 'pad_factor', 'opt_psf_defocus': 'defocus', 'opt_psf_astig1': 'astig1', 'opt_psf_astig2': 'astig2', 'opt_psf_coma1': 'coma1', 'opt_psf_coma2': 'coma2', 'opt_psf_trefoil1': 'trefoil1', 'opt_psf_trefoil2': 'trefoil2', 'opt_psf_spher': 'spher' } opticalPSFParams = {kmap[key]: params[key] for key in kmap} # Add units for the strut angle. opticalPSFParams['strut_angle'] *= galsim.degrees # Suppress warnings. opticalPSFParams['suppress_warning'] = True # Build the optical PSF from the params dictionary. models.append(galsim.OpticalPSF(**opticalPSFParams)) # Add an atmospheric component if a FWHM value is provided. if 'atmos_psf_fwhm' in keys: atmosphericPSF = galsim.Kolmogorov( fwhm=params['atmos_psf_fwhm']).shear( beta=params['atmos_psf_beta'] * galsim.degrees, e=params['atmos_psf_e']) models.append(atmosphericPSF) # Return the convolution of all PSF component models. return galsim.Convolve(models, gsparams=Observation.getGSParams())
def _generate_examples(self, size): """Yields examples.""" # Loads the galsim COSMOS catalog cat = gs.COSMOSCatalog(sample="25.2") mag_zp = 32 sky_level = 400 # ADU (~variance) psf = gs.Kolmogorov(fwhm=self.builder_config.psf_fwhm, flux=1.0) psf = psf.shear(g1=self.builder_config.psf_e1, g2=self.builder_config.psf_e2) # Prepare borders for kimage Nk = self.builder_config.kstamp_size bounds = gs._BoundsI(-Nk // 2, Nk // 2 - 1, -Nk // 2, Nk // 2 - 1) for i in range(size): # retrieving galaxy and magnitude gal = cat.makeGalaxy(i, gal_type='parametric') gal_mag = cat.param_cat['mag_auto'][cat.orig_index[i]] gal_flux = 10**(-(gal_mag - mag_zp) / 2.5) gal = gal.withFlux(gal_flux) gal = gal.shear(g1=self.builder_config.shear_g1, g2=self.builder_config.shear_g2) gal_conv = gs.Convolve(gal, psf) gal_stamp = gal_conv.drawImage( nx=self.builder_config.stamp_size, ny=self.builder_config.stamp_size, scale=self.builder_config.pixel_scale).array.astype('float32') psf_stamp = psf.drawImage( nx=self.builder_config.stamp_size, ny=self.builder_config.stamp_size, scale=self.builder_config.pixel_scale).array.astype('float32') # gal_kimage = gal.drawKImage(bounds=bounds, # scale=2.*np.pi/(self.builder_config.stamp_size*self.builder_config.pixel_scale), # recenter=False).array.astype('complex64') # psf_kimage = psf.drawKImage(bounds=bounds, # scale=2.*np.pi/(self.builder_config.stamp_size*self.builder_config.pixel_scale), # recenter=False).array.astype('complex64') yield '%d' % i, { "obs": gal_stamp, "psf": psf_stamp, # "gal_kimage": np.stack([gal_kimage.real, gal_kimage.imag]), # "psf_kimage": np.stack([psf_kimage.real, psf_kimage.imag]), "noise_std": np.array([np.sqrt(sky_level)]).astype('float32'), "mag": np.array([gal_mag]).astype('float32') }
def test_geometric_shoot(): """Test that geometric photon shooting is reasonably consistent with Fourier optics.""" jmax = 20 bd = galsim.BaseDeviate(1111111) u = galsim.UniformDeviate(bd) lam = 500.0 diam = 4.0 for i in range(4): # Do a few random tests. Takes about 1 sec. aberrations = [0]+[u()*0.1 for i in range(jmax)] opt_psf = galsim.OpticalPSF(diam=diam, lam=lam, aberrations=aberrations, geometric_shooting=True) # Use really good seeing, so that the optics contribution actually matters. psf = galsim.Convolve(opt_psf, galsim.Kolmogorov(fwhm=0.4)) im_shoot = psf.drawImage(nx=256, ny=256, scale=0.2, method='phot', n_photons=100000, rng=u) im_fft = psf.drawImage(nx=256, ny=256, scale=0.2) printval(im_fft, im_shoot) shoot_moments = galsim.hsm.FindAdaptiveMom(im_shoot) fft_moments = galsim.hsm.FindAdaptiveMom(im_fft) # 40th of a pixel centroid tolerance. np.testing.assert_allclose( shoot_moments.moments_centroid.x, fft_moments.moments_centroid.x, rtol=0, atol=0.025, err_msg="") np.testing.assert_allclose( shoot_moments.moments_centroid.y, fft_moments.moments_centroid.y, rtol=0, atol=0.025, err_msg="") # 2% size tolerance np.testing.assert_allclose( shoot_moments.moments_sigma, fft_moments.moments_sigma, rtol=0.02, atol=0, err_msg="") # Not amazing ellipticity consistency at the moment. 0.01 tolerance. print(fft_moments.observed_shape) print(shoot_moments.observed_shape) np.testing.assert_allclose( shoot_moments.observed_shape.g1, fft_moments.observed_shape.g1, rtol=0, atol=0.01, err_msg="") np.testing.assert_allclose( shoot_moments.observed_shape.g2, fft_moments.observed_shape.g2, rtol=0, atol=0.01, err_msg="") # Check the flux # The Airy part sends a lot of flux off the edge, so this test is a little loose. added_flux = im_shoot.added_flux print('psf.flux = ',psf.flux) print('added_flux = ',added_flux) print('image flux = ',im_shoot.array.sum()) assert np.isclose(added_flux, psf.flux, rtol=3.e-4) assert np.isclose(im_shoot.array.sum(), psf.flux, rtol=3.e-4)
def _stepK(self, **kwargs): """Return an appropriate stepk for this atmospheric layer. @param lam Wavelength in nanometers. @param scale_unit Sky coordinate units of output profile. [default: galsim.arcsec] @param gsparams An optional GSParams argument. See the docstring for GSParams for details. [default: None] @returns Good pupil scale size in meters. """ lam = kwargs['lam'] gsparams = kwargs.pop('gsparams', None) obj = galsim.Kolmogorov(lam=lam, r0_500=self.r0_500, gsparams=gsparams) return obj.stepk
def test_vk_eq_kolm(): lam = 500.0 r0 = 0.2 L0 = 1e10 # Need to make this surprisingly large to make vk -> kolm. flux = 3.3 kolm = galsim.Kolmogorov(lam=lam, r0=r0, flux=flux) vk = galsim.VonKarman(lam=lam, r0=r0, L0=L0, flux=flux) np.testing.assert_allclose(kolm.xValue(0,0), vk.xValue(0,0), rtol=1e-3, atol=0) kolm_img = kolm.drawImage(nx=24, ny=24, scale=0.2) vk_img = vk.drawImage(nx=24, ny=24, scale=0.2) np.testing.assert_allclose(kolm_img.array, vk_img.array, atol=flux*4e-5, rtol=0)
def test_kolmogorov_properties(): """Test some basic properties of the Kolmogorov profile. """ test_flux = 1.8 lor = 1.5 psf = galsim.Kolmogorov(lam_over_r0=lor, flux=test_flux) # Check that we are centered on (0, 0) cen = galsim.PositionD(0, 0) np.testing.assert_equal(psf.centroid, cen) # Check Fourier properties np.testing.assert_almost_equal(psf.maxk, 8.644067599028375, 9) np.testing.assert_almost_equal(psf.stepk, 0.3698212155333603, 9) np.testing.assert_almost_equal(psf.kValue(cen), test_flux + 0j) np.testing.assert_almost_equal(psf.lam_over_r0, lor) np.testing.assert_almost_equal(psf.half_light_radius, lor * 0.5548101137) np.testing.assert_almost_equal(psf.fwhm, lor * 0.9758634299) np.testing.assert_almost_equal(psf.xValue(cen), 0.6283185307179587) np.testing.assert_almost_equal(psf.kValue(cen), (1 + 0j) * test_flux) np.testing.assert_almost_equal(psf.flux, test_flux) np.testing.assert_almost_equal(psf.xValue(cen), psf.max_sb) # Check input flux vs output flux lors = [1, 0.5, 2, 5] for lor in lors: psf = galsim.Kolmogorov(lam_over_r0=lor, flux=test_flux) out_flux = psf.flux np.testing.assert_almost_equal( out_flux, test_flux, err_msg="Flux of Kolmogorov is incorrect.") # Also check the realized flux in a drawn image dx = lor / 10. img = galsim.ImageF(256, 256, scale=dx) psf.drawImage(image=img) out_flux = img.array.sum(dtype=float) np.testing.assert_almost_equal( out_flux, test_flux, 3, err_msg="Flux of Kolmogorov (image array) is incorrect.")
def test_hsmparams(): """Test the ability to set/change parameters that define how moments/shape estimation are done.""" import time t1 = time.time() # First make some profile, and make sure that we get the same answers when we specify default # hsmparams or don't specify hsmparams at all. default_hsmparams = galsim.hsm.HSMParams(nsig_rg=3.0, nsig_rg2=3.6, max_moment_nsig2=25.0, regauss_too_small=1, adapt_order=2, max_mom2_iter=400, num_iter_default=-1, bound_correct_wt=0.25, max_amoment=8000., max_ashift=15., ksb_moments_max=4, failed_moments=-1000.) bulge = galsim.DeVaucouleurs(half_light_radius = 0.3) disk = galsim.Exponential(half_light_radius = 0.5) disk.applyShear(e1=0.2, e2=-0.3) psf = galsim.Kolmogorov(fwhm = 0.6) pix = galsim.Pixel(0.18) gal = bulge + disk # equal weighting, i.e., B/T=0.5 tot_gal = galsim.Convolve(gal, psf, pix) tot_psf = galsim.Convolve(psf, pix) tot_gal_image = tot_gal.draw(dx=0.18) tot_psf_image = tot_psf.draw(dx=0.18) res = tot_gal_image.FindAdaptiveMom() res_def = tot_gal_image.FindAdaptiveMom(hsmparams = default_hsmparams) assert(equal_hsmshapedata(res, res_def)), 'Moment outputs differ when using default HSMParams' res2 = galsim.hsm.EstimateShear(tot_gal_image, tot_psf_image) res2_def = galsim.hsm.EstimateShear(tot_gal_image, tot_psf_image, hsmparams = default_hsmparams) assert(equal_hsmshapedata(res, res_def)), 'Shear outputs differ when using default HSMParams' try: # Then check failure modes: force it to fail by changing HSMParams. new_params_niter = galsim.hsm.HSMParams(max_mom2_iter = res.moments_n_iter-1) new_params_size = galsim.hsm.HSMParams(max_amoment = 0.3*res.moments_sigma**2) np.testing.assert_raises(RuntimeError, galsim.hsm.FindAdaptiveMom, tot_gal_image, hsmparams=new_params_niter) np.testing.assert_raises(RuntimeError, galsim.hsm.EstimateShear, tot_gal_image, tot_psf_image, hsmparams=new_params_size) except ImportError: print 'The assert_raises tests require nose' t2 = time.time() print 'time for %s = %.2f'%(funcname(),t2-t1)
def test_sub_neg(): """Test that a - b is the same as a + (-b).""" a = galsim.Gaussian(fwhm=1) b = galsim.Kolmogorov(fwhm=1) c = a - b d = a + (-b) assert c == d im1 = c.drawImage() im2 = d.drawImage(im1.copy()) np.testing.assert_equal(im1.array, im2.array)
def test_kolmogorov_shoot(): """Test Kolmogorov with photon shooting. Particularly the flux of the final image. """ rng = galsim.BaseDeviate(1234) obj = galsim.Kolmogorov(fwhm=1.5, flux=1.e4) im = galsim.Image(500, 500, scale=1) im.setCenter(0, 0) added_flux, photons = obj.drawPhot(im, poisson_flux=False, rng=rng) print('obj.flux = ', obj.flux) print('added_flux = ', added_flux) print('photon fluxes = ', photons.flux.min(), '..', photons.flux.max()) print('image flux = ', im.array.sum()) assert np.isclose(added_flux, obj.flux) assert np.isclose(im.array.sum(), obj.flux)
def kolmogorov2d(fwhm=1.0, xoffset=0., yoffset=0.): import galsim #gsp = galsim.GSParams(folding_threshold=1.0/512., maximum_fft_size=12288) psf = galsim.Kolmogorov(fwhm=fwhm, flux=1) #, gsparams=gsp) im = psf.drawImage(method='real_space', scale=1.0) bounds = im.getBounds() arr = im.image.array.reshape(bounds.getXMax(), bounds.getXMax()) if xoffset + yoffset > 0: arr = scipy.ndimage.interpolation.shift( arr, [xoffset, yoffset]) # spline interpolation for shift #else: # For the PSF, need to offset by -0.5 in each direction, just because. # arr = scipy.ndimage.interpolation.shift(arr, [-0.5, -0.5]) arr /= arr.sum() return arr
def constructModelImage(self, params=None, pixelScale=None, jacobian=None, shape=None): """Construct model image from parameters @param params lmfit.Parameters object or python dictionary with param values to use, or None to use self.params @param pixelScale pixel scale in arcseconds to use for model image, or None to use self.pixelScale. @param jacobian An optional 2x2 Jacobian distortion matrix to apply to the forward model. Note that this is relative to the pixelScale above. Use self.jacobian if this is None. @param shape (nx, ny) shape for model image, or None to use the shape of self.maskedImage @returns numpy array image """ if params is None: params = self.params if shape is None: shape = self.maskedImage.getImage().getArray().shape if pixelScale is None: pixelScale = self.pixelScale if jacobian is None: jacobian = self.jacobian try: v = params.valuesdict() except AttributeError: v = params optPsf = self._getOptPsf(v) if 'r0' in v: atmPsf = galsim.Kolmogorov(lam=self.wavelength, r0=v['r0']) psf = galsim.Convolve(optPsf, atmPsf) else: psf = optPsf psf = psf.shift(v['dx'], v['dy']) * v['flux'] wcs = galsim.JacobianWCS(*list(pixelScale * jacobian.ravel())) modelImg = psf.drawImage(nx=shape[0], ny=shape[1], wcs=wcs) return modelImg.array
def test_kolmogorov(): """Test various ways to build a Kolmogorov """ config = { 'gal1' : { 'type' : 'Kolmogorov' , 'lam_over_r0' : 2 }, 'gal2' : { 'type' : 'Kolmogorov' , 'fwhm' : 2, 'flux' : 100 }, 'gal3' : { 'type' : 'Kolmogorov' , 'half_light_radius' : 2, 'flux' : 1.e6, 'ellip' : { 'type' : 'QBeta' , 'q' : 0.6, 'beta' : 0.39 * galsim.radians } }, 'gal4' : { 'type' : 'Kolmogorov' , 'lam_over_r0' : 1, 'flux' : 50, 'dilate' : 3, 'ellip' : galsim.Shear(e1=0.3), 'rotate' : 12 * galsim.degrees, 'magnify' : 1.03, 'shear' : galsim.Shear(g1=0.03, g2=-0.05), 'shift' : { 'type' : 'XY', 'x' : 0.7, 'y' : -1.2 } }, 'gal5' : { 'type' : 'Kolmogorov' , 'lam_over_r0' : 1, 'flux' : 50, 'gsparams' : { 'integration_relerr' : 1.e-2, 'integration_abserr' : 1.e-4 } } } gal1a = galsim.config.BuildGSObject(config, 'gal1')[0] gal1b = galsim.Kolmogorov(lam_over_r0 = 2) gsobject_compare(gal1a, gal1b) gal2a = galsim.config.BuildGSObject(config, 'gal2')[0] gal2b = galsim.Kolmogorov(fwhm = 2, flux = 100) gsobject_compare(gal2a, gal2b) gal3a = galsim.config.BuildGSObject(config, 'gal3')[0] gal3b = galsim.Kolmogorov(half_light_radius = 2, flux = 1.e6) gal3b = gal3b.shear(q = 0.6, beta = 0.39 * galsim.radians) gsobject_compare(gal3a, gal3b) gal4a = galsim.config.BuildGSObject(config, 'gal4')[0] gal4b = galsim.Kolmogorov(lam_over_r0 = 1, flux = 50) gal4b = gal4b.dilate(3).shear(e1 = 0.3).rotate(12 * galsim.degrees) gal4b = gal4b.lens(0.03, -0.05, 1.03).shift(dx = 0.7, dy = -1.2) gsobject_compare(gal4a, gal4b) gal5a = galsim.config.BuildGSObject(config, 'gal5')[0] gsparams = galsim.GSParams(integration_relerr=1.e-2, integration_abserr=1.e-4) gal5b = galsim.Kolmogorov(lam_over_r0=1, flux=50, gsparams=gsparams) gsobject_compare(gal5a, gal5b) try: # Make sure they don't match when using the default GSParams gal5c = galsim.Kolmogorov(lam_over_r0=1, flux=50) np.testing.assert_raises(AssertionError,gsobject_compare, gal5a, gal5c) except ImportError: print('The assert_raises tests require nose')
def getProfile(self, params): """Get a version of the model as a GalSim GSObject :param params: A np array with [z4, z5, z6...z11] :returns: a galsim.GSObject instance """ prof = [] # gaussian if self.sigma is not None: gaussian = galsim.Gaussian(sigma=self.sigma) prof.append(gaussian) # atmosphere if len(self.atm_kwargs) > 0: if 'L0' in self.atm_kwargs and self.atm_kwargs['L0'] is not None: atm = galsim.VonKarman(**self.atm_kwargs) else: atm = galsim.Kolmogorov(**self.atm_kwargs) prof.append(atm) # optics if params is None or len(params) == 0: # no aberrations. Just the basic opt_kwargs optics = galsim.OpticalPSF(**self.opt_kwargs) else: aberrations = [0, 0, 0, 0] + list(params) optics = galsim.OpticalPSF(aberrations=aberrations, **self.opt_kwargs) # convolve together prof.append(optics) if len(prof) == 1: prof = prof[0] else: prof = galsim.Convolve(prof) if self.g1 is not None or self.g2 is not None: prof = prof.shear(g1=self.g1, g2=self.g2) return prof
def getProfile(self, params): """Get a version of the model as a GalSim GSObject :param params: A np array with [z4, z5, z6...z11] :returns: a galsim.GSObject instance """ import galsim prof = [] # gaussian if self.sigma is not None: gaussian = galsim.Gaussian(sigma=self.sigma) prof.append(gaussian) # atmosphere if len(self.kolmogorov_kwargs) > 0: atm = galsim.Kolmogorov(**self.kolmogorov_kwargs) prof.append(atm) # optics if params is None or len(params) == 0: # no optics here pass else: aberrations = [0, 0, 0, 0] + list(params) optics = galsim.OpticalPSF(aberrations=aberrations, **self.optical_psf_kwargs) prof.append(optics) # convolve together if len(prof) == 0: raise RuntimeError('No profile returned by model!') if len(prof) == 1: prof = prof[0] else: prof = galsim.Convolve(prof) if self.g1 is not None or self.g2 is not None: prof = prof.shear(g1=self.g1, g2=self.g2) return prof
def get_psf(Args): atmospheric_psf_fwhm = Args.zenith_psf_fwhm * Args.airmass**0.6 if Args.atmospheric_psf_beta > 0: atmospheric_psf_model = galsim.Moffat(beta=Args.atmospheric_psf_beta, fwhm=atmospheric_psf_fwhm) else: atmospheric_psf_model = galsim.Kolmogorov(fwhm=atmospheric_psf_fwhm) lambda_over_diameter = 3600 * math.degrees( 1e-10 * Args.central_wavelength / Args.mirror_diameter) area_ratio = Args.effective_area / (math.pi * (0.5 * Args.mirror_diameter)**2) obscuration_fraction = math.sqrt(1 - area_ratio) optical_psf_model = galsim.Airy(lam_over_diam=lambda_over_diameter, obscuration=obscuration_fraction) psf_model = galsim.Convolve(atmospheric_psf_model, optical_psf_model) psf_size_pixels = 2 * int( math.ceil(10 * atmospheric_psf_fwhm / Args.pixel_scale)) psf_image = galsim.Image(psf_size_pixels, psf_size_pixels, scale=Args.pixel_scale) psf_model.drawImage(image=psf_image) return psf_image.array
def sim_star(flux, psf_fwhm, stamp_length=40, random_seed=None): """Simulate a star postage stamp.""" ## Set image parameters pixel_scale = 0.2 sy = sx = stamp_length psf_fwhm = psf_fwhm dy, dx = np.random.rand(2) - 0.5 if random_seed is not None: rng = galsim.UniformDeviate(random_seed) else: rng = galsim.UniformDeviate(0) ## Generate stamp with PSF image image = galsim.ImageF(sy, sx, scale=pixel_scale) psf = galsim.Kolmogorov(fwhm=psf_fwhm, scale_unit=galsim.arcsec) psf = psf.withFlux(flux) sensor = galsim.sensor.SiliconSensor(rng=rng, diffusion_factor=1) stamp = psf.drawImage(image, rng=rng, offset=(dx, dy), sensor=sensor) return stamp
gd, '../../../examples/data/acs_I_unrot_sci_20_cf.fits', dx_cosmos=dx_cosmos) cn.setVariance(1000.) # Again chosen to be non-unity # Define a PSF with which to convolve the noise field, one WITHOUT 2-fold rotational symmetry # (see test_autocorrelate in test_SBProfile.py for more info as to why this is relevant) # Make a relatively realistic mockup of a GREAT3 target image lam_over_diam_cosmos = (814.e-9 / 2.4) * (180. / np.pi) * 3600. # ~lamda/D in arcsec lam_over_diam_ground = lam_over_diam_cosmos * 2.4 / 4. # Generic 4m at same lambda psf_cosmos = galsim.Convolve([ galsim.Airy(lam_over_diam=lam_over_diam_cosmos, obscuration=0.4), galsim.Pixel(0.05) ]) psf_ground = galsim.Convolve([ galsim.Kolmogorov(fwhm=0.8), galsim.Pixel(0.18), galsim.OpticalPSF(lam_over_diam=lam_over_diam_ground, coma2=0.4, defocus=-0.6) ]) psf_shera = galsim.Convolve([ psf_ground, (galsim.Deconvolve(psf_cosmos)).createSheared(g1=0.03, g2=-0.01) ]) # Then define the convolved cosmos correlated noise model conv_cn = cn.copy() conv_cn.convolveWith(psf_shera) # Then draw the correlation function for this correlated noise as the reference refim = galsim.ImageD(smallim_size, smallim_size) conv_cn.draw(refim, dx=0.18)
def test_kolmogorov(): """Test the generation of a specific Kolmogorov profile against a known result. """ import math dx = 0.2 test_flux = 1.8 # This savedImg was created from the SBKolmogorov implementation in # commit c8efd74d1930157b1b1ffc0bfcfb5e1bf6fe3201 # It would be nice to get an independent calculation here... #mySBP = galsim.SBKolmogorov(lam_over_r0=1.5, flux=test_flux) #savedImg = galsim.ImageF(128,128) #mySBP.drawImage(image=savedImg, dx=dx, method="sb") #savedImg.write(os.path.join(imgdir, "kolmogorov.fits")) savedImg = galsim.fits.read(os.path.join(imgdir, "kolmogorov.fits")) myImg = galsim.ImageF(savedImg.bounds, scale=dx) myImg.setCenter(0,0) kolm = galsim.Kolmogorov(lam_over_r0=1.5, flux=test_flux) kolm.drawImage(myImg, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 5, err_msg="Using GSObject Kolmogorov disagrees with expected result") # Check with default_params kolm = galsim.Kolmogorov(lam_over_r0=1.5, flux=test_flux, gsparams=default_params) kolm.drawImage(myImg, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 5, err_msg="Using GSObject Kolmogorov with default_params disagrees with expected result") kolm = galsim.Kolmogorov(lam_over_r0=1.5, flux=test_flux, gsparams=galsim.GSParams()) kolm.drawImage(myImg, method="sb", use_true_center=False) np.testing.assert_array_almost_equal( myImg.array, savedImg.array, 5, err_msg="Using GSObject Kolmogorov with GSParams() disagrees with expected result") gsp = galsim.GSParams(xvalue_accuracy=1.e-8, kvalue_accuracy=1.e-8) kolm2 = galsim.Kolmogorov(lam_over_r0=1.5, flux=test_flux, gsparams=gsp) assert kolm2 != kolm assert kolm2 == kolm.withGSParams(gsp) assert kolm2 == kolm.withGSParams(xvalue_accuracy=1.e-8, kvalue_accuracy=1.e-8) check_basic(kolm, "Kolmogorov") # Test photon shooting. do_shoot(kolm,myImg,"Kolmogorov") # Test kvalues do_kvalue(kolm,myImg, "Kolmogorov") # Check picklability do_pickle(kolm, lambda x: x.drawImage(method='no_pixel')) do_pickle(kolm) # Test initialization separately with lam and r0, in various units. Since the above profiles # have lam/r0 = 3./2. in arbitrary units, we will tell it that lam=3.e9 nm and r0=2.0 m, # and use `scale_unit` of galsim.radians. This is rather silly, but it should work. kolm = galsim.Kolmogorov(lam_over_r0=1.5, flux=test_flux) kolm2 = galsim.Kolmogorov(lam=3.e9, r0=2.0, scale_unit=galsim.radians, flux=test_flux) gsobject_compare(kolm,kolm2) # For lam/r0 = 1.5 arcsec, and r0 = 0.2, lam = (1.5/3600/180*pi) * 0.2 * 1.e9 lam = 1.5 * 0.2 / 3600. / 180. * math.pi * 1.e9 print('lam = ',lam) kolm3 = galsim.Kolmogorov(lam=lam, r0=0.2, scale_unit='arcsec', flux=test_flux) gsobject_compare(kolm,kolm3) # arcsec is the default scale_unit, so can leave this off. kolm4 = galsim.Kolmogorov(lam=lam, r0=0.2, flux=test_flux) gsobject_compare(kolm,kolm4) # Test using r0_500 instead r0_500 = 0.2 * (lam/500)**-1.2 kolm5 = galsim.Kolmogorov(lam=lam, r0_500=r0_500, flux=test_flux) gsobject_compare(kolm,kolm5) # Should raise an exception if >= 2 radius specifications are provided and/or lam and r0 are not # paired together. assert_raises(TypeError, galsim.Kolmogorov, lam_over_r0=3, fwhm=2, half_light_radius=1, lam=3, r0=1) assert_raises(TypeError, galsim.Kolmogorov, fwhm=2, half_light_radius=1, lam=3, r0=1) assert_raises(TypeError, galsim.Kolmogorov, lam_over_r0=3, half_light_radius=1, lam=3, r0=1) assert_raises(TypeError, galsim.Kolmogorov, lam_over_r0=3, fwhm=2, lam=3, r0=1) assert_raises(TypeError, galsim.Kolmogorov, lam_over_r0=3, fwhm=2, half_light_radius=1) assert_raises(TypeError, galsim.Kolmogorov, half_light_radius=1, lam=3, r0=1) assert_raises(TypeError, galsim.Kolmogorov, fwhm=2, lam=3, r0=1) assert_raises(TypeError, galsim.Kolmogorov, fwhm=2, half_light_radius=1) assert_raises(TypeError, galsim.Kolmogorov, lam_over_r0=3, lam=3, r0=1) assert_raises(TypeError, galsim.Kolmogorov, lam_over_r0=3, half_light_radius=1) assert_raises(TypeError, galsim.Kolmogorov, lam_over_r0=3, fwhm=2) assert_raises(TypeError, galsim.Kolmogorov, lam_over_r0=3, lam=3) assert_raises(TypeError, galsim.Kolmogorov, lam_over_r0=3, r0=1) assert_raises(TypeError, galsim.Kolmogorov, fwhm=2, lam=3) assert_raises(TypeError, galsim.Kolmogorov, fwhm=2, r0=1) assert_raises(TypeError, galsim.Kolmogorov, half_light_radius=1, lam=3) assert_raises(TypeError, galsim.Kolmogorov, half_light_radius=1, r0=1) assert_raises(TypeError, galsim.Kolmogorov, lam=3) assert_raises(TypeError, galsim.Kolmogorov, r0=1) assert_raises(TypeError, galsim.Kolmogorov)