def test_autocorrelate(): """Test that auto-correlation works the same as convolution with the mirror image of itself. (See the Signal processing Section of http://en.wikipedia.org/wiki/Autocorrelation) """ import time t1 = time.time() # Use a function that is NOT two-fold rotationally symmetric, e.g. two different flux Gaussians myGauss1 = galsim.SBGaussian(sigma=3., flux=4) myGauss1.applyShift(-0.2, -0.4) myGauss2 = (galsim.SBGaussian(sigma=6., flux=1.3)) myGauss2.applyShift(0.3, 0.3) mySBP1 = galsim.SBAdd([myGauss1, myGauss2]) mySBP2 = galsim.SBAdd([myGauss1, myGauss2]) # Here we rotate by 180 degrees to create mirror image mySBP2.applyRotation(180. * galsim.degrees) myConv = galsim.SBConvolve([mySBP1, mySBP2]) myImg1 = galsim.ImageF(80, 80, scale=0.7) myConv.draw(myImg1.view()) myAutoCorr = galsim.SBAutoCorrelate(mySBP1) myImg2 = galsim.ImageF(80, 80, scale=0.7) myAutoCorr.draw(myImg2.view()) printval(myImg1, myImg2) np.testing.assert_array_almost_equal( myImg1.array, myImg2.array, 4, err_msg= "Asymmetric sum of Gaussians convolved with mirror of self disagrees with " + "SBAutoCorrelate result") # Repeat with the GSObject version of this: 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) add1 = galsim.Add(obj1, obj2) add2 = (galsim.Add(obj1, obj2)).createRotated(180. * galsim.degrees) conv = galsim.Convolve([add1, add2]) conv.draw(myImg1) corr = galsim.AutoCorrelate(add1) 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 mirror of self disagrees with " + "AutoCorrelate result") # Test photon shooting. do_shoot(corr, myImg2, "AutoCorrelate") t2 = time.time() print 'time for %s = %.2f' % (funcname(), t2 - t1)
def __init__(self, real_galaxy_catalog, index=None, id=None, random=False, rng=None, x_interpolant=None, k_interpolant=None, flux=None, pad_factor=0, noise_pad=False, pad_image=None, use_cache=True, gsparams=None): import pyfits import numpy as np # Code block below will be for galaxy selection; not all are currently implemented. Each # option must return an index within the real_galaxy_catalog. if index is not None: if id is not None or random is True: raise AttributeError( 'Too many methods for selecting a galaxy!') use_index = index elif id is not None: if random is True: raise AttributeError( 'Too many methods for selecting a galaxy!') use_index = real_galaxy_catalog._get_index_for_id(id) elif random is True: if rng is None: uniform_deviate = galsim.UniformDeviate() elif isinstance(rng, galsim.BaseDeviate): uniform_deviate = galsim.UniformDeviate(rng) else: raise TypeError( "The rng provided to RealGalaxy constructor is not a BaseDeviate" ) use_index = int(real_galaxy_catalog.nobjects * uniform_deviate()) else: raise AttributeError('No method specified for selecting a galaxy!') # read in the galaxy, PSF images; for now, rely on pyfits to make I/O errors. Should # consider exporting this code into fits.py in some function that takes a filename and HDU, # and returns an ImageView gal_image = real_galaxy_catalog.getGal(use_index) PSF_image = real_galaxy_catalog.getPSF(use_index) # choose proper interpolant if x_interpolant is None: lan5 = galsim.Lanczos(5, conserve_flux=True, tol=1.e-4) self.x_interpolant = galsim.InterpolantXY(lan5) else: self.x_interpolant = galsim.utilities.convert_interpolant_to_2d( x_interpolant) if k_interpolant is None: self.k_interpolant = galsim.InterpolantXY( galsim.Quintic(tol=1.e-4)) else: self.k_interpolant = galsim.utilities.convert_interpolant_to_2d( k_interpolant) # read in data about galaxy from FITS binary table; store as normal attributes of RealGalaxy # save any other relevant information as instance attributes self.catalog_file = real_galaxy_catalog.file_name self.index = use_index self.pixel_scale = float(real_galaxy_catalog.pixel_scale[use_index]) # handle padding by an image specify_size = False padded_size = gal_image.getPaddedSize(pad_factor) if pad_image is not None: specify_size = True if isinstance(pad_image, str): pad_image = galsim.fits.read(pad_image) if (not isinstance(pad_image, galsim.BaseImageF) and not isinstance(pad_image, galsim.BaseImageD)): raise ValueError( "Supplied pad_image is not one of the allowed types!") # If an image was supplied directly or from a file, check its size: # Cannot use if too small. # Use to define the final image size otherwise. deltax = ((1 + pad_image.getXMax() - pad_image.getXMin()) - (1 + gal_image.getXMax() - gal_image.getXMin())) deltay = ((1 + pad_image.getYMax() - pad_image.getYMin()) - (1 + gal_image.getYMax() - gal_image.getYMin())) if deltax < 0 or deltay < 0: raise RuntimeError("Image supplied for padding is too small!") if pad_factor != 1. and pad_factor != 0.: import warnings msg = "Warning: ignoring specified pad_factor because user also specified\n" msg += " an image to use directly for the padding." warnings.warn(msg) else: if isinstance(gal_image, galsim.BaseImageF): pad_image = galsim.ImageF(padded_size, padded_size) if isinstance(gal_image, galsim.BaseImageD): pad_image = galsim.ImageD(padded_size, padded_size) # Set up the GaussianDeviate if not provided one, or check that the user-provided one # is of a valid type. Note if random was selected, we can use that uniform_deviate safely. if random is True: gaussian_deviate = galsim.GaussianDeviate(uniform_deviate) else: if rng is None: gaussian_deviate = galsim.GaussianDeviate() elif isinstance(rng, galsim.BaseDeviate): # Even if it's already a GaussianDeviate, we still want to make a new Gaussian # deviate that would generate the same sequence, because later we change the sigma # and we don't want to change it for the original one that was passed in. So don't # distinguish between GaussianDeviate and the other BaseDeviates here. gaussian_deviate = galsim.GaussianDeviate(rng) else: raise TypeError( "rng provided to RealGalaxy constructor is not a BaseDeviate" ) # handle noise-padding options try: noise_pad = galsim.config.value._GetBoolValue(noise_pad, '') except: pass if noise_pad: self.pad_variance = float(real_galaxy_catalog.variance[use_index]) # Check, is it "True" or something else? If True, we use Gaussian uncorrelated noise # using the stored variance in the catalog. Otherwise, if it's a CorrelatedNoise we use # it directly; if it's an Image of some sort we use it to make a CorrelatedNoise; if # it's a string, we read in the image from file and make a CorrelatedNoise. if type(noise_pad) is not bool: if isinstance(noise_pad, galsim.correlatednoise._BaseCorrelatedNoise): cn = noise_pad.copy() if rng: # Let user supplied RNG take precedence over that in user CN cn.setRNG(gaussian_deviate) # This small patch may have different overall variance, so rescale while # preserving the correlation structure by default cn.setVariance(self.pad_variance) elif (isinstance(noise_pad, galsim.BaseImageF) or isinstance(noise_pad, galsim.BaseImageD)): cn = galsim.CorrelatedNoise(gaussian_deviate, noise_pad) elif use_cache and noise_pad in RealGalaxy._cache_noise_pad: cn = RealGalaxy._cache_noise_pad[noise_pad] # Make sure that we are using the desired RNG by resetting that in this cached # CorrelatedNoise instance if rng: cn.setRNG(gaussian_deviate) # This small patch may have different overall variance, so rescale while # preserving the correlation structure cn.setVariance(self.pad_variance) elif isinstance(noise_pad, str): tmp_img = galsim.fits.read(noise_pad) cn = galsim.CorrelatedNoise(gaussian_deviate, tmp_img) if use_cache: RealGalaxy._cache_noise_pad[noise_pad] = cn # This small patch may have different overall variance, so rescale while # preserving the correlation structure cn.setVariance(self.pad_variance) else: raise RuntimeError( "noise_pad must be either a bool, CorrelatedNoise, Image, " + "or a filename for reading in an Image") # Set the GaussianDeviate sigma gaussian_deviate.setSigma(np.sqrt(self.pad_variance)) # populate padding image with noise field if type(noise_pad) is bool: pad_image.addNoise(galsim.DeviateNoise(gaussian_deviate)) else: pad_image.addNoise(cn) else: self.pad_variance = 0. # Now we have to check: was the padding determined using pad_factor? Or by passing in an # image for padding? Treat these cases differently: # (1) If the former, then we can simply have the C++ handle the padding process. # (2) If the latter, then we have to do the padding ourselves, and pass the resulting image # to the C++ with pad_factor explicitly set to 1. if specify_size is False: # Make the SBInterpolatedImage out of the image. self.original_image = galsim.SBInterpolatedImage( gal_image, xInterp=self.x_interpolant, kInterp=self.k_interpolant, dx=self.pixel_scale, pad_factor=pad_factor, pad_image=pad_image, gsparams=gsparams) else: # Leave the original image as-is. Instead, we shift around the image to be used for # padding. Find out how much x and y margin there should be on lower end: x_marg = int(np.round(0.5 * deltax)) y_marg = int(np.round(0.5 * deltay)) # Now reset the pad_image to contain the original image in an even way pad_image = pad_image.view() pad_image.setScale(self.pixel_scale) pad_image.setOrigin(gal_image.getXMin() - x_marg, gal_image.getYMin() - y_marg) # Set the central values of pad_image to be equal to the input image pad_image[gal_image.bounds] = gal_image self.original_image = galsim.SBInterpolatedImage( pad_image, xInterp=self.x_interpolant, kInterp=self.k_interpolant, dx=self.pixel_scale, pad_factor=1., gsparams=gsparams) # also make the original PSF image, with far less fanfare: we don't need to pad with # anything interesting. self.original_PSF = galsim.SBInterpolatedImage( PSF_image, xInterp=self.x_interpolant, kInterp=self.k_interpolant, dx=self.pixel_scale, gsparams=gsparams) # recalculate Fourier-space attributes rather than using overly-conservative defaults self.original_image.calculateStepK() self.original_image.calculateMaxK() self.original_PSF.calculateStepK() self.original_PSF.calculateMaxK() if flux != None: self.original_image.setFlux(flux) self.original_image.__class__ = galsim.SBTransform # correctly reflect SBProfile change self.original_PSF.setFlux(1.0) self.original_PSF.__class__ = galsim.SBTransform # correctly reflect SBProfile change # Calculate the PSF "deconvolution" kernel psf_inv = galsim.SBDeconvolve(self.original_PSF, gsparams=gsparams) # Initialize the SBProfile attribute GSObject.__init__( self, galsim.SBConvolve([self.original_image, psf_inv], gsparams=gsparams))
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 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_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_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)
def test_shearconvolve(): """Test the convolution of a sheared Gaussian and a Box SBProfile against a known result. """ import time t1 = time.time() e1 = 0.04 e2 = 0.0 myShear = galsim.Shear(e1=e1, e2=e2) # test at SBProfile level using applyShear mySBP = galsim.SBGaussian(flux=1, sigma=1) mySBP.applyShear(myShear._shear) mySBP2 = galsim.SBBox(xw=0.2, yw=0.2, flux=1.) myConv = galsim.SBConvolve([mySBP, mySBP2]) savedImg = galsim.fits.read( os.path.join(imgdir, "gauss_smallshear_convolve_box.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, 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) psf2 = psf.createSheared(e1=e1, e2=e2) psf.applyShear(e1=e1, e2=e2) pixel = galsim.Pixel(xw=0.2, yw=0.2, flux=1.) conv = galsim.Convolve([psf, pixel]) conv.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 Convolve([psf,pixel]) disagrees with expected result") conv2 = galsim.Convolve([psf2, pixel]) conv2.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 Convolve([psf,pixel]) disagrees with expected result") # Check with default_params conv = galsim.Convolve([psf, pixel], 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, 5, err_msg= "Using GSObject Convolve([psf,pixel]) with default_params disagrees with " "expected result") conv = galsim.Convolve([psf, pixel], 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, 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) conv.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 Convolve(psf,pixel) disagrees with expected result") # Test photon shooting. do_shoot(conv, myImg, "sheared Gaussian * Pixel") t2 = time.time() print 'time for %s = %.2f' % (funcname(), t2 - t1)
def __init__(self, *args, **kwargs): # First check for number of arguments != 0 if len(args) == 0: # No arguments. Could initialize with an empty list but draw then segfaults. Raise an # exception instead. raise ValueError("Convolve must be initialized with at least one GSObject.") elif len(args) == 1: if isinstance(args[0], GSObject): SBList = [args[0].SBProfile] elif isinstance(args[0], list): SBList=[] for obj in args[0]: if isinstance(obj, GSObject): SBList.append(obj.SBProfile) else: raise TypeError("Input list must contain only GSObjects.") else: raise TypeError("Single input argument must be a GSObject or list of them.") elif len(args) >= 2: # >= 2 arguments. Convert to a list of SBProfiles SBList = [] for obj in args: if isinstance(obj, GSObject): SBList.append(obj.SBProfile) else: raise TypeError("Input args must contain only GSObjects.") # Having built the list of SBProfiles or thrown exceptions if necessary, see now whether # to perform real space convolution... # Check kwargs # real_space can be True or False (default if omitted is None), which specifies whether to # do the convolution as an integral in real space rather than as a product in fourier # space. If the parameter is omitted (or explicitly given as None I guess), then # we will usually do the fourier method. However, if there are 2 components _and_ both of # them have hard edges, then we use real-space convolution. real_space = kwargs.pop("real_space", None) gsparams = kwargs.pop("gsparams", None) # Make sure there is nothing left in the dict. if kwargs: raise TypeError( "Convolve constructor got unexpected keyword argument(s): %s"%kwargs.keys()) # If 1 argument, check if it is a list: if len(args) == 1 and isinstance(args[0], list): args = args[0] hard_edge = True for obj in args: if not obj.hasHardEdges(): hard_edge = False if real_space is None: # Figure out if it makes more sense to use real-space convolution. if len(args) == 2: real_space = hard_edge elif len(args) == 1: real_space = obj.isAnalyticX() else: real_space = False # Warn if doing DFT convolution for objects with hard edges. if not real_space and hard_edge: import warnings if len(args) == 2: msg = """ Doing convolution of 2 objects, both with hard edges. This might be more accurate and/or faster using real_space=True""" else: msg = """ Doing convolution where all objects have hard edges. There might be some inaccuracies due to ringing in k-space.""" warnings.warn(msg) if real_space: # Can't do real space if nobj > 2 if len(args) > 2: import warnings msg = """ Real-space convolution of more than 2 objects is not implemented. Switching to DFT method.""" warnings.warn(msg) real_space = False # Also can't do real space if any object is not analytic, so check for that. else: for obj in args: if not obj.isAnalyticX(): import warnings msg = """ A component to be convolved is not analytic in real space. Cannot use real space convolution. Switching to DFT method.""" warnings.warn(msg) real_space = False break # Then finally initialize the SBProfile using the objects' SBProfiles in SBList GSObject.__init__(self, galsim.SBConvolve(SBList, real_space=real_space, gsparams=gsparams))
desq = de1 * de1 + de2 * de2 if desq > 0.: de = np.sqrt(desq) dg = math.tanh(0.5 * math.atanh(de)) dg1 = de1 * (dg / de) dg2 = de2 * (dg / de) else: dg1 = 0.0 dg2 = 0.0 disk.applyShear(g1=dg1, g2=dg2) # Rescale fluxes and add: use the overloaded multiplication and addition operators galaxy = bt * bulge + (1.0 - bt) * disk # Convolve with PSF, and draw image convGalaxy = galsim.SBConvolve([PSF, galaxy.SBProfile]) convGalaxyImg = convGalaxy.draw(dx=pixelScale) # More noise realizations? for invsnind in range(len(invSN)): print "Beginning inverse S/N of ", invSN[invsnind] if invSN[invsnind] > 0.0: # Choose Gaussian sigma per pixel based on GREAT08-style S/N definition gaussSig = invSN[invsnind] * np.sqrt( np.sum(convGalaxyImg.array**(2.0))) # Add noise the appropriate number of times, and write each one to file for iRealization in range(nRealization[invsnind]): tmpImg = convGalaxyImg.copy() tmpImg.addNoise( galsim.GaussianDeviate(rng,