def buildNoisePadImage(self, noise_pad_size, noise_pad, rng): """A helper function that builds the `pad_image` from the given `noise_pad` specification. """ # Make it with the same dtype as the image pad_image = galsim.Image(noise_pad_size, noise_pad_size, dtype=self.image.dtype) # Figure out what kind of noise to apply to the image if isinstance(noise_pad, float): noise = galsim.GaussianNoise(rng, sigma=np.sqrt(noise_pad)) elif isinstance(noise_pad, galsim.correlatednoise._BaseCorrelatedNoise): noise = noise_pad.copy(rng=rng) elif isinstance(noise_pad, galsim.Image): noise = galsim.CorrelatedNoise(noise_pad, rng) elif self.use_cache and noise_pad in InterpolatedImage._cache_noise_pad: noise = InterpolatedImage._cache_noise_pad[noise_pad] if rng: # Make sure that we are using a specified RNG by resetting that in this cached # CorrelatedNoise instance, otherwise preserve the cached RNG noise = noise.copy(rng=rng) elif isinstance(noise_pad, str): noise = galsim.CorrelatedNoise(galsim.fits.read(noise_pad), rng) if self.use_cache: InterpolatedImage._cache_noise_pad[noise_pad] = noise else: raise ValueError( "Input noise_pad must be a float/int, a CorrelatedNoise, Image, or filename " + "containing an image to use to make a CorrelatedNoise!") # Add the noise pad_image.addNoise(noise) return pad_image
def test_corr_padding_cf(): """Test for correlated noise padding of InterpolatedImage.""" import time t1 = time.time() imgfile = 'fits_files/blankimg.fits' orig_nx = 147 orig_ny = 124 orig_seed = 151241 rng = galsim.BaseDeviate(orig_seed) # Make an ImageCorrFunc cf = galsim.CorrelatedNoise(rng, galsim.fits.read(imgfile)) # first, make the base image orig_img = galsim.ImageF(orig_nx, orig_ny, scale=1.) gal = galsim.Gaussian(sigma=2.5, flux=100.) gal.drawImage(orig_img, method='no_pixel') for iter in range(n_iter): # make it into an InterpolatedImage padded with cf int_im = galsim.InterpolatedImage(orig_img, noise_pad=cf) # do it again with a particular seed int_im = galsim.InterpolatedImage(orig_img, rng = galsim.GaussianDeviate(orig_seed), noise_pad = cf) # repeat int_im = galsim.InterpolatedImage(orig_img, rng = galsim.GaussianDeviate(orig_seed), noise_pad = cf) t2 = time.time() print('time for %s = %.2f'%(funcname(),t2-t1))
def check_symm_noise(noise_image, msg): # A helper funciton to see if a noise image has 4-fold symmetric noise. im2 = noise_image.copy() # Clear out any wcs to make the test simpler im2.wcs = galsim.PixelScale(1.) noise = galsim.CorrelatedNoise(im2) cf = noise.drawImage(galsim.Image(bounds=galsim.BoundsI(-1,1,-1,1), scale=1)) # First check the variance print('variance: ',cf(0,0), noise.getVariance()) np.testing.assert_almost_equal(cf(0,0)/noise.getVariance(), 1.0, decimal=VAR_NDECIMAL, err_msg=msg + ':: noise variance is wrong.') cf_plus = np.array([ cf(1,0), cf(-1,0), cf(0,1), cf(0,-1) ]) cf_cross = np.array([ cf(1,1), cf(-1,-1), cf(-1,1), cf(1,-1) ]) print('plus pattern: ',cf_plus) print('diff relative to dc: ',(cf_plus-np.mean(cf_plus))/cf(0,0)) print('cross pattern: ',cf_cross) print('diff relative to dc: ',(cf_cross-np.mean(cf_cross))/cf(0,0)) # For now, don't make these asserts. Just print whether they will pass or fail. if True: if np.all(np.abs((cf_plus-np.mean(cf_plus))/cf(0,0)) < 0.01): print('plus test passes') else: print('*** FAIL ***') print(msg + ': plus pattern is not constant') if np.all(np.abs((cf_cross-np.mean(cf_cross))/cf(0,0)) < 0.01): print('cross test passes') else: print('*** FAIL ***') print(msg + ': cross pattern is not constant') else: np.testing.assert_almost_equal((cf_plus-np.mean(cf_plus))/cf(0,0), 0.0, decimal=2, err_msg=msg + ': plus pattern is not constant') np.testing.assert_almost_equal((cf_cross-np.mean(cf_cross))/cf(0,0), 0.0, decimal=2, err_msg=msg + ': cross pattern is not constant')
def buildNoisePadImage(self, pad_factor, noise_pad, rng): """A helper function that builds the pad_image from the given noise_pad specification. """ import numpy as np if pad_factor <= 0.: pad_factor = galsim._galsim.getDefaultPadFactor() padded_size = int(np.ceil(np.max(self.orig_image.array.shape) * pad_factor)) if isinstance(self.orig_image, galsim.BaseImageF): pad_image = galsim.ImageF(padded_size, padded_size) if isinstance(self.orig_image, galsim.BaseImageD): pad_image = galsim.ImageD(padded_size, padded_size) # Figure out what kind of noise to apply to the image if isinstance(noise_pad, float): noise = galsim.GaussianNoise(rng, sigma = np.sqrt(noise_pad)) elif isinstance(noise_pad, galsim.correlatednoise._BaseCorrelatedNoise): noise = noise_pad.copy() if rng: # Let a user supplied RNG take precedence over that in user CN noise.setRNG(rng) elif isinstance(noise_pad,galsim.BaseImageF) or isinstance(noise_pad,galsim.BaseImageD): noise = galsim.CorrelatedNoise(rng, noise_pad) elif self.use_cache and noise_pad in InterpolatedImage._cache_noise_pad: noise = InterpolatedImage._cache_noise_pad[noise_pad] if rng: # Make sure that we are using a specified RNG by resetting that in this cached # CorrelatedNoise instance, otherwise preserve the cached RNG noise.setRNG(rng) elif isinstance(noise_pad, str): noise = galsim.CorrelatedNoise(rng, galsim.fits.read(noise_pad)) if self.use_cache: InterpolatedImage._cache_noise_pad[noise_pad] = noise else: raise ValueError( "Input noise_pad must be a float/int, a CorrelatedNoise, Image, or filename "+ "containing an image to use to make a CorrelatedNoise!") pad_image.addNoise(noise) return pad_image
def check_noise(noise_image, noise, msg): # A helper function to check that the current noise in the image is properly described # by the given CorrelatedNoise object noise2 = galsim.CorrelatedNoise(noise_image) print('noise = ',noise) print('noise2 = ',noise2) np.testing.assert_almost_equal(noise.getVariance(), noise2.getVariance(), decimal=CHECKNOISE_NDECIMAL, err_msg=msg + ': variance does not match.') cf_im1 = galsim.Image(8,8, wcs=noise_image.wcs) cf_im2 = cf_im1.copy() noise.drawImage(image=cf_im1) noise2.drawImage(image=cf_im2) np.testing.assert_almost_equal(cf_im1.array, cf_im2.array, decimal=CHECKNOISE_NDECIMAL, err_msg=msg + ': image of cf does not match.')
def make_cf(args): bls = Table.read(args.blank_file, format='ascii.basic') for f, filt in enumerate(args.filter_names): print "Making Correlation function for ", filt q, = np.where(bls['FILTER'] == filt) bl = q[0] xmin, xmax = bls['XMIN'][bl], bls['XMAX'][bl] ymin, ymax = bls['YMIN'][bl], bls['YMAX'][bl] hdu = pyfits.open(bls['FILE'][bl]) bl_dat = hdu[0].data[ymin:ymax, xmin:xmax] hdu.close() rng = galsim.BaseDeviate(123456) img = galsim.Image(bl_dat) cn = galsim.CorrelatedNoise(img, rng=rng, scale=0.03) image = galsim.ImageD(80, 80, scale=0.03) cf = cn.drawImage(image) name = args.out_path + args.out_name.replace('filter', args.file_filter_name[f]) print "Savings fits file at ", name pyfits.writeto(name, cf.array, clobber=True)
print "Unpadded convolved image bounds = " + str(convimage1.bounds) convimage3_padded = galsim.ImageD( int(largeim_size * size_factor) + 32, int(largeim_size * size_factor) + 32) # Set the scales of convimage2 & 3 to be 0.18 so that addNoise() works correctly convimage2.scale = 0.18 convimage3_padded.scale = 0.18 print "Padded convolved image bounds = " + str(convimage3_padded.bounds) print "" # We draw, calculate a correlation function for the resulting field, and repeat to get an # average over nsum_test trials cimobj.draw(convimage1, dx=0.18, normalization='sb') cn_test1 = galsim.CorrelatedNoise(gd, convimage1, dx=0.18, correct_periodicity=False, subtract_mean=True, correct_sample_bias_prototype=False) testim1 = galsim.ImageD(smallim_size, smallim_size) cn_test1.draw(testim1, dx=0.18) convimage2.addNoise( conv_cn ) # Now we make a comparison by simply adding noise from conv_cn cn_test2 = galsim.CorrelatedNoise(gd, convimage2, dx=0.18, correct_periodicity=False, subtract_mean=True, correct_sample_bias_prototype=False) testim2 = galsim.ImageD(smallim_size, smallim_size)
cn2 = galsim.getCOSMOSNoise(ud, CFIMFILE_UNS, dx_cosmos=1.) testim1 = galsim.ImageD(7, 7) testim2 = galsim.ImageD(7, 7) var1 = 0. var2 = 0. noisearrays = cPickle.load(open(NOISEIMFILE, 'rb')) for noisearray, i in zip(noisearrays, range(len(noisearrays))): noise1 = galsim.ImageViewD((noisearray.copy()).astype(np.float64), scale=1.) noise2 = galsim.ImageViewD((noisearray.copy()).astype(np.float64), scale=1.) cn1.applyWhiteningTo(noise1) cn2.applyWhiteningTo(noise2) var1 += noise1.array.var() var2 += noise2.array.var() cntest1 = galsim.CorrelatedNoise(ud, noise1) cntest2 = galsim.CorrelatedNoise(ud, noise2) cntest1.draw(testim1, dx=1., add_to_image=True) cntest2.draw(testim2, dx=1., add_to_image=True) print "Done "+str(i + 1)+"/"+str(len(noisearrays)) testim1 /= len(noisearrays) testim2 /= len(noisearrays) var1 /= len(noisearrays) var2 /= len(noisearrays) print var1, var2 delx = np.arange(7) - 3. import matplotlib.pyplot as plt
A simple script used to quickly generate plots for the discussion of which interpolant should be used to describe correlation functions. See the discussion at https://github.com/GalSim-developers/GalSim/pull/452#discussion-diff-5701561 """ import numpy as np import matplotlib.pyplot as plt import galsim CFSIZE=9 UPSAMPLING = 3 rng = galsim.BaseDeviate(752424) gd = galsim.GaussianNoise(rng) noise_image = galsim.ImageD(CFSIZE, CFSIZE) noise_image.addNoise(gd) cn = galsim.CorrelatedNoise(rng, noise_image, x_interpolant=galsim.Nearest(tol=1.e-4), dx=1.) test_image = galsim.ImageD( 2 * UPSAMPLING * CFSIZE, 2 * UPSAMPLING * CFSIZE, scale=1. / float(UPSAMPLING)) cn.applyRotation(30. * galsim.degrees) cn.draw(test_image) plt.clf() plt.pcolor(test_image.array) plt.colorbar() plt.savefig('cf_nearest.png') plt.show()
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))
print "Unpadded convolved image bounds = " + str(convimage1.bounds) convimage3_padded = galsim.ImageD( int(largeim_size * size_factor) + 32, int(largeim_size * size_factor) + 32) # Set the scales of convimage2 & 3 to be 0.18 so that addNoise() works correctly convimage2.scale = 0.18 convimage3_padded.scale = 0.18 print "Padded convolved image bounds = " + str(convimage3_padded.bounds) print "" # We draw, calculate a correlation function for the resulting field, and repeat to get an # average over nsum_test trials cimobj.draw(convimage1, dx=0.18, normalization='sb') cn_test1 = galsim.CorrelatedNoise(convimage1, gd, dx=0.18, correct_periodicity=False, subtract_mean=True) testim1 = galsim.ImageD(smallim_size, smallim_size) cn_test1.draw(testim1, dx=0.18) convimage2.addNoise( conv_cn ) # Now we make a comparison by simply adding noise from conv_cn cn_test2 = galsim.CorrelatedNoise(convimage2, gd, dx=0.18, correct_periodicity=False, subtract_mean=True) testim2 = galsim.ImageD(smallim_size, smallim_size) cn_test2.draw(testim2, dx=0.18)
def test_corr_padding(): """Test for correlated noise padding of InterpolatedImage.""" import time t1 = time.time() # Set up some defaults for tests. decimal_precise=4 decimal_coarse=2 imgfile = 'fits_files/blankimg.fits' orig_nx = 187 orig_ny = 164 big_nx = 319 big_ny = 322 orig_seed = 151241 # Read in some small image of a noise field from HST. # Rescale it to have a decently large amplitude for the purpose of doing these tests. im = 1.e2*galsim.fits.read(imgfile) # Make a CorrrlatedNoise out of it. cn = galsim.CorrelatedNoise(im, galsim.BaseDeviate(orig_seed)) # first, make a noise image orig_img = galsim.ImageF(orig_nx, orig_ny, scale=1.) orig_img.addNoise(cn) # make it into an InterpolatedImage with some zero-padding # (note that default is zero-padding, by factors of several) int_im = galsim.InterpolatedImage(orig_img) # draw into a larger image big_img = galsim.ImageF(big_nx, big_ny) int_im.draw(big_img, scale=1.) # check that variance is diluted by expected amount - should be exact, so check precisely! big_var_expected = np.var(orig_img.array)*float(orig_nx*orig_ny)/(big_nx*big_ny) np.testing.assert_almost_equal(np.var(big_img.array), big_var_expected, decimal=decimal_precise, err_msg='Variance not diluted by expected amount when zero-padding') # make it into an InterpolatedImage with noise-padding int_im = galsim.InterpolatedImage(orig_img, rng = galsim.GaussianDeviate(orig_seed), noise_pad = im, noise_pad_size = max(big_nx,big_ny)) # draw into a larger image big_img = galsim.ImageF(big_nx, big_ny) int_im.draw(big_img, scale=1.) # check that variance is same as original - here, we cannot be too precise because the padded # region is not huge and the comparison will be, well, noisy. np.testing.assert_almost_equal(np.var(big_img.array), np.var(orig_img.array), decimal=decimal_coarse, err_msg='Variance not correct after padding image with correlated noise') # check that if we pass in a RNG, it is actually used to pad with the same noise field # basically, redo all of the above steps and draw into a new image, make sure it's the same as # previous. int_im = galsim.InterpolatedImage( orig_img, rng=galsim.GaussianDeviate(orig_seed), noise_pad=cn, noise_pad_size = max(big_nx,big_ny)) big_img_2 = galsim.ImageF(big_nx, big_ny) int_im.draw(big_img_2, scale=1.) np.testing.assert_array_almost_equal(big_img_2.array, big_img.array, decimal=decimal_precise, err_msg='Cannot reproduce correlated noise-padded image with same choice of seed') # Finally, check inputs: # what if we give it a screwy way of defining the image padding? try: np.testing.assert_raises(ValueError,galsim.InterpolatedImage,orig_img,noise_pad=-1.) except ImportError: print 'The assert_raises tests require nose' # also, check that whether we give it a string, image, or cn, it gives the same noise field # (given the same random seed) infile = 'fits_files/blankimg.fits' inimg = galsim.fits.read(infile) incf = galsim.CorrelatedNoise(inimg, galsim.GaussianDeviate()) # input RNG will be ignored below int_im2 = galsim.InterpolatedImage(orig_img, rng=galsim.GaussianDeviate(orig_seed), noise_pad=inimg, noise_pad_size = max(big_nx,big_ny)) int_im3 = galsim.InterpolatedImage(orig_img, rng=galsim.GaussianDeviate(orig_seed), noise_pad=incf, noise_pad_size = max(big_nx,big_ny)) big_img2 = galsim.ImageF(big_nx, big_ny) big_img3 = galsim.ImageF(big_nx, big_ny) int_im2.draw(big_img2, scale=1.) int_im3.draw(big_img3, scale=1.) np.testing.assert_equal(big_img2.array, big_img3.array, err_msg='Diff ways of specifying correlated noise give diff answers') t2 = time.time() print 'time for %s = %.2f'%(funcname(),t2-t1)
# function that is NPIX by NPIX if not os.path.isfile( CFIMFILE ): # If the CFIMFILE already exists skip straight through to the plots # Read in the pickled images noiseims = cPickle.load(open(NOISEIMFILE, 'rb')) # Loop through the images and sum the correlation functions hst_ncf = None bd = galsim.BaseDeviate(12345) # Seed is basically unimportant here for noiseim in noiseims: noiseim = noiseim.astype(np.float64) if hst_ncf is None: # Initialize the HST noise correlation function using the first image hst_ncf = galsim.CorrelatedNoise(bd, galsim.ImageViewD(noiseim), correct_periodicity=True, subtract_mean=SUBTRACT_MEAN) else: hst_ncf += galsim.CorrelatedNoise(bd, galsim.ImageViewD(noiseim), correct_periodicity=True, subtract_mean=SUBTRACT_MEAN) hst_ncf /= float(len(noiseims)) # Draw and plot an output image of the resulting correlation function cfimage = galsim.ImageD(NPIX, NPIX) hst_ncf.draw(cfimage, dx=1.) # Save this to the output filename specified in the script header cfimage.write(CFIMFILE) else: cfimage = galsim.fits.read(CFIMFILE)
failed1 = 0 failed2 = 0 failed3 = 0 failed4 = 0 failed5 = 0 failed6 = 0 failed7 = 0 TESTSTART = 25 TESTEND = 125 for dim in range(TESTSTART, TESTEND): noise_array = np.random.randn(dim, dim) noise_image = galsim.ImageViewD(noise_array) cn1 = galsim.CorrelatedNoise(rng, noise_image) cn2 = galsim.CorrelatedNoise(rng, noise_image, correct_periodicity=False) # First try with (default), then without, periodicity correction test_image1.setZero() try: cn1.applyTo(test_image1) except RuntimeError: failed1 += 1 test_image2.setZero() try: cn2.applyTo(test_image2) except RuntimeError: failed2 += 1 # Then try calculating the PS by hand, in the same manner as the CorrelatedNoise internals noiseft = np.fft.fft2(noise_array) ps = np.abs(noiseft)**2
def test_metacal_tracking(): """Test that the noise tracking works for the metacal use case involving deconvolution and reconvolution by almost the same PSF. This test is similar to the above test_uncorrelated_noise_tracking, except the modifications are based on what is done for the metacal procedure. """ import math def check_noise(noise_image, noise, msg): # A helper function to check that the current noise in the image is properly described # by the given CorrelatedNoise object noise2 = galsim.CorrelatedNoise(noise_image) print('noise = ', noise) print('noise2 = ', noise2) np.testing.assert_almost_equal(noise.getVariance(), noise2.getVariance(), decimal=CHECKNOISE_NDECIMAL, err_msg=msg + ': variance does not match.') cf_im1 = galsim.Image(8, 8, wcs=noise_image.wcs) cf_im2 = cf_im1.copy() noise.drawImage(image=cf_im1) noise2.drawImage(image=cf_im2) np.testing.assert_almost_equal(cf_im1.array, cf_im2.array, decimal=CHECKNOISE_NDECIMAL, err_msg=msg + ': image of cf does not match.') def check_symm_noise(noise_image, msg): # A helper funciton to see if a noise image has 4-fold symmetric noise. im2 = noise_image.copy() # Clear out any wcs to make the test simpler im2.wcs = galsim.PixelScale(1.) noise = galsim.CorrelatedNoise(im2) cf = noise.drawImage( galsim.Image(bounds=galsim.BoundsI(-1, 1, -1, 1), scale=1)) # First check the variance print('variance: ', cf(0, 0), noise.getVariance()) np.testing.assert_almost_equal(cf(0, 0) / noise.getVariance(), 1.0, decimal=VAR_NDECIMAL, err_msg=msg + ':: noise variance is wrong.') cf_plus = np.array([cf(1, 0), cf(-1, 0), cf(0, 1), cf(0, -1)]) cf_cross = np.array([cf(1, 1), cf(-1, -1), cf(-1, 1), cf(1, -1)]) print('plus pattern: ', cf_plus) print('diff relative to dc: ', (cf_plus - np.mean(cf_plus)) / cf(0, 0)) print('cross pattern: ', cf_cross) print('diff relative to dc: ', (cf_cross - np.mean(cf_cross)) / cf(0, 0)) # For now, don't make these asserts. Just print whether they will pass or fail. if True: if np.all(np.abs((cf_plus - np.mean(cf_plus)) / cf(0, 0)) < 0.01): print('plus test passes') else: print('*** FAIL ***') print(msg + ': plus pattern is not constant') if np.all( np.abs((cf_cross - np.mean(cf_cross)) / cf(0, 0)) < 0.01): print('cross test passes') else: print('*** FAIL ***') print(msg + ': cross pattern is not constant') else: np.testing.assert_almost_equal( (cf_plus - np.mean(cf_plus)) / cf(0, 0), 0.0, decimal=2, err_msg=msg + ': plus pattern is not constant') np.testing.assert_almost_equal( (cf_cross - np.mean(cf_cross)) / cf(0, 0), 0.0, decimal=2, err_msg=msg + ': cross pattern is not constant') seed = 1234567 # For use as a unit test, we need a specific seed #seed = 0 # During testing, it's useful to see how numbers flop around to know if # something is systematic or random. rng = galsim.BaseDeviate(seed) noise_var = 1.3 im_size = 1024 dg = 0.1 # This is bigger than metacal would use, but it makes the test easier. # Use a non-trivial wcs... #wcs = galsim.JacobianWCS(0.26, 0.04, -0.04, -0.26) # Rotation + flip. No shear. wcs = galsim.JacobianWCS(0.26, 0.03, 0.08, -0.21) # Fully complex #dudx = 0.12*0.26 #dudy = 1.10*0.26 #dvdx = -0.915*0.26 #dvdy = -0.04*0.26 #wcs = galsim.JacobianWCS(dudx, dudy, dvdx, dvdy) # Even more extreme # And an asymmetric PSF #orig_psf = galsim.Gaussian(fwhm=0.9).shear(g1=0.05, g2=0.03) # This one is small enough not to be fully Nyquist sampled, which makes things harder. orig_psf = galsim.Gaussian(fwhm=0.7).shear(g1=0.05, g2=0.03) # pixel is the pixel in world coords pixel = wcs.toWorld(galsim.Pixel(scale=1)) pixel_inv = galsim.Deconvolve(pixel) psf_image = orig_psf.drawImage(nx=im_size, ny=im_size, wcs=wcs) # Metacal only has access to the PSF as an image, so use this from here on. psf = galsim.InterpolatedImage(psf_image) psf_nopix = galsim.Convolve([psf, pixel_inv]) psf_inv = galsim.Deconvolve(psf) # Not what is done currently, but using a smoother target PSF helps make sure the # zeros in the deconvolved PSF get adequately zeroed out. def get_target_psf(psf): dk = 0.1 # The resolution in k space for the KImage small_kval = 1.e-2 # Find the k where the given psf hits this kvalue smaller_kval = 3.e-3 # Target PSF will have this kvalue at the same k kim = psf.drawKImage(scale=dk) karr_r = kim.real.array # Find the smallest r where the kval < small_kval nk = karr_r.shape[0] kx, ky = np.meshgrid(np.arange(-nk / 2, nk / 2), np.arange(-nk / 2, nk / 2)) ksq = (kx**2 + ky**2) * dk**2 ksq_max = np.min(ksq[karr_r < small_kval * psf.flux]) # We take our target PSF to be the (round) Gaussian that is even smaller at this ksq # exp(-0.5 * ksq_max * sigma_sq) = smaller_kval sigma_sq = -2. * np.log(smaller_kval) / ksq_max return galsim.Gaussian(sigma=np.sqrt(sigma_sq)) # The target PSF dilates the part without the pixel, but reconvolve by the real pixel. #psf_target_nopix = psf_nopix.dilate(1. + 2.*dg) #psf_target_nopix = orig_psf.dilate(1. + 4.*dg) psf_target_nopix = get_target_psf(psf_nopix.shear(g1=dg)) print('PSF target HLR = ', psf_target_nopix.calculateHLR()) print('PSF target FWHM = ', psf_target_nopix.calculateFWHM()) psf_target = galsim.Convolve([psf_target_nopix, pixel]) # Make an image of pure (white) Gaussian noise # Normally, there would be a galaxy in this image, but for the tests, we just have noise. obs_image = galsim.Image(im_size, im_size, init_value=0, wcs=wcs) obs_image.addNoise( galsim.GaussianNoise(rng=rng, sigma=math.sqrt(noise_var))) # The noise on this image should be describable as an UncorrelatedNoise object: noise = galsim.UncorrelatedNoise(variance=noise_var, wcs=wcs) check_noise(obs_image, noise, 'initial UncorrelatedNoise model is wrong') # Make an InterpolatedImage profile to use for manipulating this image # We can get away with no padding here, since our image is so large, but normally, you would # probably want to pad this with noise padding. ii = galsim.InterpolatedImage(obs_image, pad_factor=1) ii.noise = noise # If we draw it back, the attached noise attribute should still be correct check_noise(ii.drawImage(obs_image.copy(), method='no_pixel'), ii.noise, 'noise model is wrong for InterpolatedImage') # Here is the metacal process for which we want to understand the noise. # We'll try a few different methods. shear = galsim.Shear(g1=dg) sheared_obj = galsim.Convolve(ii, psf_inv).shear(shear) final_obj = galsim.Convolve(psf_target, sheared_obj) final_image = final_obj.drawImage(obs_image.copy(), method='no_pixel') try: check_symm_noise(final_image, 'Initial image') #didnt_fail = True # This bit doesn't work while we are not actually raising exceptions in check_symm_noise # So we expect to see **FAIL** text at this point. print( 'The above tests are expected to **FAIL**. This is not a problem.' ) didnt_fail = False except AssertionError as e: print('As expected initial image fails symmetric noise test:') print(e) didnt_fail = False if didnt_fail: assert False, 'Initial image was expected to fail symmetric noise test, but passed.' if True: print('\n\nStrategy 1:') # Strategy 1: Use the noise attribute attached to ii and use it to either whiten or # symmetrize the noise in the final image. # Note: The check_noise tests fail. I think because the convolve and deconvolve impose # a maxk = that of the psf. Which is too small for an accurate rendering of the # correlation function (here just an autocorrelation of a Pixel. # The whiten tests kind of work, but they add a lot of extra noise. Much more than # strategy 4 below. So the level of correlation remaining is pretty well below the # dc variance. Symmetrize doesn't add much noise, but the residual correlation is about # the same, which means it doesn't pass the test relative to the lower dc variance. # First, deconvolve and reconvolve by the same PSF: test_obj = galsim.Convolve([ii, psf, psf_inv]) # This fails... if False: check_noise( test_obj.drawImage(obs_image.copy(), method='no_pixel'), test_obj.noise, 'noise model is wrong after convolve/deconvolve by psf') # Now use a slightly dilated PSF for the reconvolution: test_obj = galsim.Convolve([ii, psf_target, psf_inv]) if False: check_noise( test_obj.drawImage(obs_image.copy(), method='no_pixel'), test_obj.noise, 'noise model is wrong for dilated target psf') # Finally, include the shear step. This was done above with sheared_obj, final_obj. if False: check_noise(final_image, final_obj.noise, 'noise model is wrong when including small shear') # If we whiten using this noise model, we should get back to white noise. t3 = time.time() final_image2 = final_image.copy() # Don't clobber the original final_var = final_image2.whitenNoise(final_obj.noise) t4 = time.time() print('Noise tracking method with whiten: final_var = ', final_var) print('Check: direct variance = ', np.var(final_image2.array)) check_symm_noise(final_image2, 'noise whitening does not work') print('Time for noise tracking with whiten = ', t4 - t3) # Using symmetrizeNoise should add less noise, but also work. t3 = time.time() final_image2 = final_image.copy() final_var = final_image2.symmetrizeNoise(final_obj.noise) t4 = time.time() print('Noise tracking method with symmetrize: final_var = ', final_var) print('Check: direct variance = ', np.var(final_image2.array)) check_symm_noise(final_image2, 'noise symmetrizing does not work') print('Time for noise tracking with symmetrize = ', t4 - t3) if True: print('\n\nStrategy 2:') # Strategy 2: Don't trust the noise tracking. Track a noise image through the same process # and then measure the noise from that image. Use it to either whiten or # symmetrize the noise in the final image. # Note: This method doesn't work any better. The added noise for whitening is even more # than strategy 1. And the remaining correlations are still similarly significant for the # symmetrize version. A little smaller than strategy 1, but not enough to pass our tests. # Make another noise image, since we don't actually have access to a pure noise image # for real objects. But we should be able to estimate the variance in the image. t3 = time.time() noise_image = galsim.Image(im_size, im_size, init_value=0, wcs=wcs) noise_image.addNoise( galsim.GaussianNoise(rng=rng, sigma=math.sqrt(noise_var))) noise_ii = galsim.InterpolatedImage(noise_image, pad_factor=1) sheared_noise_obj = galsim.Convolve(noise_ii, psf_inv).shear(shear) final_noise_obj = galsim.Convolve(psf_target, sheared_noise_obj) final_noise_image = final_noise_obj.drawImage(obs_image.copy(), method='no_pixel') # Use this to construct an appropriate CorrelatedNoise object noise = galsim.CorrelatedNoise(final_noise_image) t4 = time.time() final_image2 = final_image.copy() final_var = final_image2.whitenNoise(noise) t5 = time.time() check_noise( final_noise_image, noise, 'noise model is wrong when direct measuring the final noise image') print('Direct noise method with whiten: final_var = ', final_var) # Neither of these work currently, so maybe a bug in the whitening code? # Or possibly in my logic here. check_symm_noise( final_image2, 'whitening the noise using direct noise model failed') print('Time for direct noise with whitening = ', t5 - t3) t6 = time.time() final_image2 = final_image.copy() final_var = final_image2.symmetrizeNoise(noise) t7 = time.time() print('Direct noise method with symmetrize: final_var = ', final_var) check_symm_noise( final_image2, 'symmetrizing the noise using direct noise model failed') print('Time for direct noise with symmetrizing = ', t7 - t6 + t4 - t3) if False: print('\n\nStrategy 3:') # Strategy 3: Make a noise field and do the same operations as we do to the main image # except use the opposite shear value. Add this noise field to the final # image to get a symmetric noise field. # Note: This method works! But only for square pixels. However, they may be rotated # or flipped. Just not sheared. # Update: I think this method won't ever work for non-square pixels. The reason it works # for square pixels is that in that case, it is equivalent to strategy 4. t3 = time.time() # Make another noise image rev_image = galsim.Image(im_size, im_size, init_value=0, wcs=wcs) rev_image.addNoise( galsim.GaussianNoise(rng=rng, sigma=math.sqrt(noise_var))) rev_ii = galsim.InterpolatedImage(rev_image, pad_factor=1) rev_sheared_obj = galsim.Convolve(rev_ii, psf_inv).shear(-shear) rev_final_obj = galsim.Convolve(psf_target, rev_sheared_obj) rev_final_image = rev_final_obj.drawImage(obs_image.copy(), method='no_pixel') # Add the reverse-sheared noise image to the original image. final_image2 = final_image + rev_final_image t4 = time.time() # The noise variance in the end should be 2x as large as the original final_var = np.var(final_image2.array) print('Reverse shear method: final_var = ', final_var) check_symm_noise(final_image2, 'using reverse shear does not work') print('Time for reverse shear method = ', t4 - t3) if True: print('\n\nStrategy 4:') # Strategy 4: Make a noise field and do the same operations as we do to the main image, # then rotate it by 90 degress and add it to the final image. # This method works! Even for an arbitrarily sheared wcs. t3 = time.time() # Make another noise image noise_image = galsim.Image(im_size, im_size, init_value=0, wcs=wcs) noise_image.addNoise( galsim.GaussianNoise(rng=rng, sigma=math.sqrt(noise_var))) noise_ii = galsim.InterpolatedImage(noise_image, pad_factor=1) noise_sheared_obj = galsim.Convolve(noise_ii, psf_inv).shear(shear) noise_final_obj = galsim.Convolve(psf_target, noise_sheared_obj) noise_final_image = noise_final_obj.drawImage(obs_image.copy(), method='no_pixel') # Rotate the image by 90 degrees rot_noise_final_image = galsim.Image( np.ascontiguousarray(np.rot90(noise_final_image.array))) # Add the rotated noise image to the original image. final_image2 = final_image + rot_noise_final_image t4 = time.time() # The noise variance in the end should be 2x as large as the original final_var = np.var(final_image2.array) print('Rotate image method: final_var = ', final_var) check_symm_noise(final_image2, 'using rotated noise image does not work') print('Time for rotate image method = ', t4 - t3) if False: print('\n\nStrategy 5:') # Strategy 5: The same as strategy 3, except we target the effective net transformation # done by strategy 4. # I think this strategy probably can't work for non-square pixels, because the shear # happens before the convolution by the PSF. And if the wcs is non-square, then the # PSF is sheared relative to the pixels. That shear isn't being accounted for here, # so the net result isn't equivalent to rotating by 90 degrees at the end. t3 = time.time() # Make another noise image rev_image = galsim.Image(im_size, im_size, init_value=0, wcs=wcs) rev_image.addNoise( galsim.GaussianNoise(rng=rng, sigma=math.sqrt(noise_var))) rev_ii = galsim.InterpolatedImage(rev_image, pad_factor=1) # Find the effective transformation to apply in sky coordinates that matches what # you would get by applying the shear in sky coords, going to image coords and then # rotating by 90 degrees. # # If J is the jacobian of the wcs, and S1 is the applied shear, then we want to find # S2 such that J^-1 S2 = R90 J^-1 S1 jac = wcs.jacobian() J = jac.getMatrix() Jinv = jac.inverse().getMatrix() S1 = shear.getMatrix() R90 = np.array([[0, -1], [1, 0]]) S2 = J.dot(R90).dot(Jinv).dot(S1) scale, rev_shear, rev_theta, flip = galsim.JacobianWCS( *S2.flatten()).getDecomposition() # Flip should be False, and scale should be essentially 1.0. assert flip == False assert abs(scale - 1.) < 1.e-8 rev_sheared_obj = galsim.Convolve( rev_ii, psf_inv).rotate(rev_theta).shear(rev_shear) rev_final_obj = galsim.Convolve(psf_target, rev_sheared_obj) rev_final_image = rev_final_obj.drawImage(obs_image.copy(), method='no_pixel') # Add the reverse-sheared noise image to the original image. final_image2 = final_image + rev_final_image t4 = time.time() # The noise variance in the end should be 2x as large as the original final_var = np.var(final_image2.array) print('Alternate reverse shear method: final_var = ', final_var) check_symm_noise(final_image2, 'using alternate reverse shear does not work') print('Time for alternate reverse shear method = ', t4 - t3)
def __init__(self, image, x_interpolant = None, k_interpolant = None, normalization = 'flux', dx = None, flux = None, pad_factor = 0., noise_pad = 0., rng = None, pad_image = None, calculate_stepk=True, calculate_maxk=True, use_cache=True, use_true_center=True, gsparams=None): import numpy as np # first try to read the image as a file. If it's not either a string or a valid # pyfits hdu or hdulist, then an exception will be raised, which we ignore and move on. try: image = galsim.fits.read(image) except: pass # make sure image is really an image and has a float type if not isinstance(image, galsim.BaseImageF) and not isinstance(image, galsim.BaseImageD): raise ValueError("Supplied image is not an image of floats or doubles!") # it must have well-defined bounds, otherwise seg fault in SBInterpolatedImage constructor if not image.getBounds().isDefined(): raise ValueError("Supplied image does not have bounds defined!") # check what normalization was specified for the image: is it an image of surface # brightness, or flux? if not normalization.lower() in ("flux", "f", "surface brightness", "sb"): raise ValueError(("Invalid normalization requested: '%s'. Expecting one of 'flux', "+ "'f', 'surface brightness', or 'sb'.") % normalization) # set up the interpolants if none was provided by user, or check that the user-provided ones # are of a valid type if x_interpolant is None: self.x_interpolant = galsim.InterpolantXY(galsim.Quintic(tol=1e-4)) 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=1e-4)) else: self.k_interpolant = galsim.utilities.convert_interpolant_to_2d(k_interpolant) # Check for input dx, and check whether Image already has one set. At the end of this # code block, either an exception will have been raised, or the input image will have a # valid scale set. if dx is None: dx = image.scale if dx == 0: raise ValueError("No information given with Image or keywords about pixel scale!") else: if type(dx) != float: dx = float(dx) # Don't change the original image. Make a new view if we need to set the scale. image = image.view() image.setScale(dx) if dx == 0.0: raise ValueError("dx may not be 0.0") # Set up the GaussianDeviate if not provided one, or check that the user-provided one is # of a valid type. 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 InterpolatedImage constructor is not a BaseDeviate") # decide about deterministic image padding specify_size = False padded_size = image.getPaddedSize(pad_factor) if pad_image: 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+image.getXMax()-image.getXMin()) deltay = (1+pad_image.getYMax()-pad_image.getYMin())-(1+image.getYMax()-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) elif noise_pad: if isinstance(image, galsim.BaseImageF): pad_image = galsim.ImageF(padded_size, padded_size) if isinstance(image, galsim.BaseImageD): pad_image = galsim.ImageD(padded_size, padded_size) # now decide about noise padding # First, see if the input is consistent with a float. # i.e. it could be an int, or a str that converts to a number. try: noise_pad = float(noise_pad) except: pass if isinstance(noise_pad, float): if noise_pad < 0.: raise ValueError("Noise variance cannot be negative!") elif noise_pad > 0.: # Note: make sure the sigma is properly set to sqrt(noise_pad). gaussian_deviate.setSigma(np.sqrt(noise_pad)) pad_image.addNoise(galsim.DeviateNoise(gaussian_deviate)) else: if isinstance(noise_pad, galsim.correlatednoise._BaseCorrelatedNoise): cn = noise_pad.copy() if rng: # Let a user supplied RNG take precedence over that in user CN cn.setRNG(gaussian_deviate) 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 InterpolatedImage._cache_noise_pad: cn = InterpolatedImage._cache_noise_pad[noise_pad] if rng: # Make sure that we are using a specified RNG by resetting that in this cached # CorrelatedNoise instance, otherwise preserve the cached RNG cn.setRNG(gaussian_deviate) elif isinstance(noise_pad, str): cn = galsim.CorrelatedNoise(gaussian_deviate, galsim.fits.read(noise_pad)) if use_cache: InterpolatedImage._cache_noise_pad[noise_pad] = cn else: raise ValueError( "Input noise_pad must be a float/int, a CorrelatedNoise, Image, or filename "+ "containing an image to use to make a CorrelatedNoise!") pad_image.addNoise(cn) # 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. sbinterpolatedimage = galsim.SBInterpolatedImage( image, xInterp=self.x_interpolant, kInterp=self.k_interpolant, dx=dx, pad_factor=pad_factor, pad_image=pad_image, gsparams=gsparams) self.x_size = padded_size self.y_size = padded_size 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(dx) pad_image.setOrigin(image.getXMin()-x_marg, image.getYMin()-y_marg) # Set the central values of pad_image to be equal to the input image pad_image[image.bounds] = image sbinterpolatedimage = galsim.SBInterpolatedImage( pad_image, xInterp=self.x_interpolant, kInterp=self.k_interpolant, dx=dx, pad_factor=1., gsparams=gsparams) self.x_size = 1+pad_image.getXMax()-pad_image.getXMin() self.y_size = 1+pad_image.getYMax()-pad_image.getYMin() # GalSim cannot automatically know what stepK and maxK are appropriate for the # input image. So it is usually worth it to do a manual calculation here. if calculate_stepk: sbinterpolatedimage.calculateStepK() if calculate_maxk: sbinterpolatedimage.calculateMaxK() # If the user specified a flux, then set to that flux value. if flux != None: if type(flux) != flux: flux = float(flux) sbinterpolatedimage.setFlux(flux) # If the user specified a flux normalization for the input Image, then since # SBInterpolatedImage works in terms of surface brightness, have to rescale the values to # get proper normalization. elif flux is None and normalization.lower() in ['flux','f'] and dx != 1.: sbinterpolatedimage.scaleFlux(1./(dx**2)) # If the input Image normalization is 'sb' then since that is the SBInterpolated default # assumption, no rescaling is needed. # Initialize the SBProfile GSObject.__init__(self, sbinterpolatedimage) # Fix the center to be in the right place. # Note the minus sign in front of image.scale, since we want to fix the center in the # opposite sense of what the draw function does. if use_true_center: prof = self._fix_center(image, -image.scale) GSObject.__init__(self, prof.SBProfile)