def _GenerateFromRandomGaussian(config, base, value_type): """@brief Return a random value drawn from a Gaussian distribution """ rng = galsim.config.GetRNG(config, base) req = { 'sigma' : float } opt = { 'mean' : float, 'min' : float, 'max' : float } kwargs, safe = galsim.config.GetAllParams(config, base, req=req, opt=opt) sigma = kwargs['sigma'] if 'gd' in base and base['current_gdsigma'] == sigma: # Minor subtlety here. GaussianDeviate requires two random numbers to # generate a single Gaussian deviate. But then it gets a second # deviate for free. So it's more efficient to store gd than to make # a new one each time. So check if we did that. gd = base['gd'] else: # Otherwise, just go ahead and make a new one. gd = galsim.GaussianDeviate(rng,sigma=sigma) base['gd'] = gd base['current_gdsigma'] = sigma if 'min' in kwargs or 'max' in kwargs: # Clip at min/max. # However, special cases if min == mean or max == mean # -- can use fabs to double the chances of falling in the range. mean = kwargs.get('mean',0.) min = kwargs.get('min',-float('inf')) max = kwargs.get('max',float('inf')) do_abs = False do_neg = False if (min >= mean) and (max > mean): do_abs = True lo = min - mean hi = max - mean elif (min < mean) and (max <= mean): do_abs = True do_neg = True hi = mean - min lo = mean - max else: lo = min - mean hi = max - mean # Emulate a do-while loop import math while True: val = gd() if do_abs: val = math.fabs(val) if val >= lo and val <= hi: break if do_neg: val = -val val += mean else: val = gd() if 'mean' in kwargs: val += kwargs['mean'] #print(base['obj_num'],'RandomGaussian: ',val) return val, False
def _getAtmKwargs(self): ud = galsim.UniformDeviate(self.rng) gd = galsim.GaussianDeviate(self.rng) # Use values measured from Ellerbroek 2008. altitudes = [0.0, 2.58, 5.16, 7.73, 12.89, 15.46] # Elevate the ground layer though. Otherwise, PSFs come out too correlated # across the field of view. altitudes[0] = 0.2 # Use weights from Ellerbroek too, but add some random perturbations. weights = [0.652, 0.172, 0.055, 0.025, 0.074, 0.022] weights = [np.abs(w * (1.0 + 0.1 * gd())) for w in weights] weights = np.clip(weights, 0.01, 0.8) # keep weights from straying too far. weights /= np.sum(weights) # renormalize # Draw outer scale from truncated log normal L0 = 0 while L0 < 10.0 or L0 > 100: L0 = np.exp(gd() * 0.6 + np.log(25.0)) # Given the desired targetFWHM and randomly selected L0, determine appropriate # r0_500 if self.logger: self.logger.debug("target FWHM: {}".format(self.targetFWHM)) r0_500 = AtmosphericPSF._r0_500(self.wlen_eff, L0, self.targetFWHM) if self.logger: self.logger.debug("Found r0_500, L0: {}, {}".format(r0_500, L0)) self.logger.debug("yields vonKarman FWHM: {}".format( AtmosphericPSF._vkSeeing(r0_500, self.wlen_eff, L0))) # Broadcast common outer scale across all layers L0 = [L0] * 6 # Uniformly draw layer speeds between 0 and max_speed. maxSpeed = 20.0 speeds = [ud() * maxSpeed for _ in range(6)] # Isotropically draw directions. directions = [ud() * 360.0 * galsim.degrees for _ in range(6)] if self.logger: self.logger.debug("airmass = {}".format(self.airmass)) self.logger.debug("wlen_eff = {}".format(self.wlen_eff)) self.logger.debug("r0_500 = {}".format(r0_500)) self.logger.debug("L0 = {}".format(L0)) self.logger.debug("speeds = {}".format(speeds)) self.logger.debug("directions = {}".format(directions)) self.logger.debug("altitudes = {}".format(altitudes)) self.logger.debug("weights = {}".format(weights)) return dict(r0_500=r0_500, L0=L0, speed=speeds, direction=directions, altitude=altitudes, r0_weights=weights, rng=self.rng, screen_size=self.screen_size, screen_scale=self.screen_scale)
def simulate_shear(constants, redshift, nbins, noise_sd=0.0, seed=0): """Takes cosmological parameters, generates a shear map, and adds noise. Inputs: constants: Constants, object for cosmological constants redshift: float, the redshift value for the sample nbins: int, the number of bins for the correlation function noise_sd: float, the standard deviation for IID Gaussian noise. seed: integer, seed for the RNG; if 0 it uses a randomly chosen seed. Returns: A pair of shear spectrum grids. """ grid_nx = 100 # length of grid in one dimension (degrees) theta = 10.0 # grid spacing dtheta = theta / grid_nx # wavenumbers at which to evaluate power spectra ell = np.logspace(-2.0, 4.0, num=50) nicaea_obj = constants.nicaea_object() psObs_nicaea = nicaea_obj.convergencePowerSpectrum(ell=ell, z=redshift) psObs_tabulated = galsim.LookupTable(ell, psObs_nicaea, interpolant='linear') ps_galsim = galsim.PowerSpectrum(psObs_tabulated, delta2=False, units=galsim.radians) grid_deviate = galsim.BaseDeviate(seed) g1, g2, kappa = ps_galsim.buildGrid(grid_spacing=dtheta, ngrid=grid_nx, rng=grid_deviate, units='degrees', kmin_factor=2, kmax_factor=2, get_convergence=True) g1_r, g2_r, _ = galsim.lensing_ps.theoryToObserved(g1, g2, kappa) rng = galsim.GaussianDeviate(seed=seed) g1_noise_grid = galsim.ImageD(grid_nx, grid_nx) g2_noise_grid = galsim.ImageD(grid_nx, grid_nx) g1_noise_grid.addNoise(galsim.GaussianNoise(rng=rng, sigma=noise_sd)) g2_noise_grid.addNoise(galsim.GaussianNoise(rng=rng, sigma=noise_sd)) g1_noisy = np.add(g1_r, g1_noise_grid.array) g2_noisy = np.add(g2_r, g2_noise_grid.array) min_sep = dtheta max_sep = grid_nx * np.sqrt(2) * dtheta grid_range = dtheta * np.arange(grid_nx) x, y = np.meshgrid(grid_range, grid_range) stats = run_treecorr(x, y, g1, g2, min_sep, max_sep, nbins=nbins) return g1_noisy, g2_noisy, stats
def _add_read_noise_and_bias(self, amp_name): """ Add read noise and bias. This should be done as the final step before returning the processed image. Parameters ---------- amp_name : str The amplifier name, e.g., "R22_S11_C00". """ amp_info = self.camera_info.get_amp_info(amp_name) full_arr = self.amp_images[amp_name].getArray() rng = galsim.GaussianDeviate(seed=self.rng, sigma=amp_info.getReadNoise()) rn_data = np.zeros(np.prod(full_arr.shape)) rng.generate(rn_data) full_arr += rn_data.reshape(full_arr.shape) full_arr += self.config['electronics_readout']['bias_level']
def GenLogNormal(config, base, value_type): """Generate a random number from a log-normal distribution. """ if 'rng' not in base: raise ValueError("No base['rng'] available for type = LogNormal") rng = base['rng'] req = {'mean': float, 'sigma': float} params, safe = galsim.config.GetAllParams(config, base, req=req) mean = params['mean'] sigma = params['sigma'] try: # This uses the ngmix code, downloadable from here: # https://github.com/esheldon/ngmix # Specifically, we use the LogNormal class here: # https://github.com/esheldon/ngmix/blob/master/ngmix/priors.py # The only thing we need to be careful about is the random number generator. # Erin's code uses numpy.random, not a GalSim rng. So we use the GalSim rng to # seed numpy.random. This should produce deterministic results. import ngmix lgn = ngmix.priors.LogNormal(mean, sigma) seed = rng.raw() numpy.random.seed(seed) value = lgn.sample() except ImportError: # If the user doesn't have ngmix installed, it will use this branch, which is equivalent. # The above was mostly a demonstration of how one could use an external module such as # ngmix that uses numpy.random for its random number generator. # Here is an equivalent code using GalSim's GaussianDeviate class. logmean = numpy.log(mean) - 0.5 * numpy.log(1 + sigma**2 / mean**2) logvar = numpy.log(1 + sigma**2 / mean**2) logsigma = numpy.sqrt(logvar) gd = galsim.GaussianDeviate(rng, mean=logmean, sigma=logsigma) return numpy.exp(gd()) return value, False
def draw_atmosphere_params(random_state=None, save=None): ''' draw inputs for galsim.Atmosphere simulation based on: Tokovinin 2006 OTP model, seeing from LSST site characterization, and NOAA GFS model winds Inputs ====== - random_state to seed generation (default is None) - save: where to save the dict of parameters, except if None (default) ''' pgen = pws.gen_params.ParameterGenerator() params = pgen.draw_parameters() out = {'altitude': params['h']} out['r0_weights'] = params['j'] out['speed'] = params['speed'].flatten() out['direction'] = [ i * galsim.degrees for i in params['direction'].flatten() ] # use random seed to seed a gaussian random number generator gd = galsim.GaussianDeviate(galsim.BaseDeviate(random_state)) # outer scale, use Josh's ImSim numbers (truncated log normal, median at 25m): L0 = 0 while L0 < 10.0 or L0 > 100: L0 = np.exp(gd() * .6 + np.log(25.)) out['L0'] = [L0] # set parameters of log-normal seeing distributino: # from the LSST SRD (or similar document) s = .452 mu = -.5174 # set an r0 value fwhm = np.exp(gd() * s + mu) out['r0_500'] = [r0_from_vk(fwhm, L0)] if save is not None: with open(save, 'wb') as file: pickle.dump(out, file) ## or maybe store results in a dict that I can unzip/whatever directly into Atmosphere return out
def GenLogNormal(config, base, value_type): """ Generate a random number from a log-normal distribution. """ if 'rng' not in base: raise ValueError("No base['rng'] available for type = LogNormal") rng = base['rng'] req = {'mean': float, 'sigma': float} params, safe = galsim.config.GetAllParams(config, base, req=req) mean = params['mean'] sigma = params['sigma'] logmean = numpy.log(mean) - 0.5 * numpy.log(1 + sigma**2 / mean**2) logvar = numpy.log(1 + sigma**2 / mean**2) logsigma = numpy.sqrt(logvar) gd = galsim.GaussianDeviate(rng, mean=logmean, sigma=logsigma) value = numpy.exp(gd()) return value, False
def main(argv): """ Make images similar to that done for the Great08 challenge: - Each fits file is 10 x 10 postage stamps. (The real Great08 images are 100x100, but in the interest of making the Demo script a bit quicker, we only build 100 stars and 100 galaxies.) - Each postage stamp is 40 x 40 pixels. - One image is all stars. - A second image is all galaxies. - Applied shear is the same for each galaxy. - Galaxies are oriented randomly, but in pairs to cancel shape noise. - Noise is Poisson using a nominal sky value of 1.e6. - Galaxies are Exponential profiles. """ logging.basicConfig(format="%(message)s", level=logging.INFO, stream=sys.stdout) logger = logging.getLogger("demo5") # Define some parameters we'll use below. # Normally these would be read in from some parameter file. nx_tiles = 10 # ny_tiles = 10 # stamp_xsize = 40 # stamp_ysize = 40 # random_seed = 6424512 # pixel_scale = 1.0 # arcsec / pixel sky_level = 1.e6 # ADU / arcsec^2 # Make output directory if not already present. if not os.path.isdir('output'): os.mkdir('output') psf_file_name = os.path.join('output','g08_psf.fits') psf_beta = 3 # psf_fwhm = 2.85 # arcsec (=pixels) psf_trunc = 2.*psf_fwhm # arcsec (=pixels) psf_e1 = -0.019 # psf_e2 = -0.007 # gal_file_name = os.path.join('output','g08_gal.fits') gal_signal_to_noise = 200 # Great08 "LowNoise" run gal_resolution = 0.98 # r_gal / r_psf (use r = half_light_radius) # Note: Great08 defined their resolution as r_obs / r_psf, using the convolved # size rather than the pre-convolved size. # Therefore, our r_gal/r_psf = 0.98 approximately corresponds to # their r_obs / r_psf = 1.4. gal_ellip_rms = 0.2 # using "distortion" definition of ellipticity: # e = (a^2-b^2)/(a^2+b^2), where a and b are the # semi-major and semi-minor axes, respectively. gal_ellip_max = 0.6 # Maximum value of e, to avoid getting near e=1. gal_g1 = 0.013 # Applied shear, using normal shear definition: gal_g2 = -0.008 # g = (a-b)/(a+b) shift_radius = 1.0 # arcsec (=pixels) logger.info('Starting demo script 5 using:') logger.info(' - image with %d x %d postage stamps',nx_tiles,ny_tiles) logger.info(' - postage stamps of size %d x %d pixels',stamp_xsize,stamp_ysize) logger.info(' - Moffat PSF (beta = %.1f, FWHM = %.2f, trunc = %.2f),', psf_beta,psf_fwhm,psf_trunc) logger.info(' - PSF ellip = (%.3f,%.3f)',psf_e1,psf_e2) logger.info(' - Exponential galaxies') logger.info(' - Resolution (r_gal / r_psf) = %.2f',gal_resolution) logger.info(' - Ellipticities have rms = %.1f, max = %.1f', gal_ellip_rms, gal_ellip_max) logger.info(' - Applied gravitational shear = (%.3f,%.3f)',gal_g1,gal_g2) logger.info(' - Poisson noise (sky level = %.1e).', sky_level) logger.info(' - Centroid shifts up to = %.2f pixels',shift_radius) # Define the PSF profile psf = galsim.Moffat(beta=psf_beta, fwhm=psf_fwhm, trunc=psf_trunc) # When something can be constructed from multiple sizes, e.g. Moffat, then # you can get any size out even if it wasn't the way the object was constructed. # In this case, we extract the half-light radius, even though we built it with fwhm. # We'll use this later to set the galaxy's half-light radius in terms of a resolution. psf_re = psf.getHalfLightRadius() psf = psf.shear(e1=psf_e1,e2=psf_e2) logger.debug('Made PSF profile') # Define the galaxy profile # First figure out the size we need from the resolution gal_re = psf_re * gal_resolution # Make the galaxy profile starting with flux = 1. gal = galsim.Exponential(flux=1., half_light_radius=gal_re) logger.debug('Made galaxy profile') # This profile is placed with different orientations and noise realizations # at each postage stamp in the gal image. gal_image = galsim.ImageF(stamp_xsize * nx_tiles-1 , stamp_ysize * ny_tiles-1, scale=pixel_scale) psf_image = galsim.ImageF(stamp_xsize * nx_tiles-1 , stamp_ysize * ny_tiles-1, scale=pixel_scale) shift_radius_sq = shift_radius**2 first_in_pair = True # Make pairs that are rotated by 90 degrees k = 0 for iy in range(ny_tiles): for ix in range(nx_tiles): # The normal procedure for setting random numbers in GalSim is to start a new # random number generator for each object using sequential seed values. # This sounds weird at first (especially if you were indoctrinated by Numerical # Recipes), but for the boost random number generator we use, the "random" # number sequences produced from sequential initial seeds are highly uncorrelated. # # The reason for this procedure is that when we use multiple processes to build # our images, we want to make sure that the results are deterministic regardless # of the way the objects get parcelled out to the different processes. # # Of course, this script isn't using multiple processes, so it isn't required here. # However, we do it nonetheless in order to get the same results as the config # version of this demo script (demo5.yaml). ud = galsim.UniformDeviate(random_seed+k+1) # Any kind of random number generator can take another RNG as its first # argument rather than a seed value. This makes both objects use the same # underlying generator for their pseudo-random values. gd = galsim.GaussianDeviate(ud, sigma=gal_ellip_rms) # The -1's in the next line are to provide a border of # 1 pixel between postage stamps b = galsim.BoundsI(ix*stamp_xsize+1 , (ix+1)*stamp_xsize-1, iy*stamp_ysize+1 , (iy+1)*stamp_ysize-1) sub_gal_image = gal_image[b] sub_psf_image = psf_image[b] # Great08 randomized the locations of the two galaxies in each pair, # but for simplicity, we just do them in sequential postage stamps. if first_in_pair: # Use a random orientation: beta = ud() * 2. * math.pi * galsim.radians # Determine the ellipticity to use for this galaxy. ellip = 1 while (ellip > gal_ellip_max): # Don't do `ellip = math.fabs(gd())` # Python basically implements this as a macro, so gd() is called twice! val = gd() ellip = math.fabs(val) # Make a new copy of the galaxy with an applied e1/e2-type distortion # by specifying the ellipticity and a real-space position angle ellip_gal = gal.shear(e=ellip, beta=beta) first_in_pair = False else: # Use the previous ellip_gal profile and rotate it by 90 degrees ellip_gal = ellip_gal.rotate(90 * galsim.degrees) first_in_pair = True # Apply the gravitational reduced shear by specifying g1/g2 this_gal = ellip_gal.shear(g1=gal_g1, g2=gal_g2) # Apply a random shift_radius: rsq = 2 * shift_radius_sq while (rsq > shift_radius_sq): dx = (2*ud()-1) * shift_radius dy = (2*ud()-1) * shift_radius rsq = dx**2 + dy**2 this_gal = this_gal.shift(dx,dy) # Note that the shifted psf that we create here is purely for the purpose of being able # to draw a separate, shifted psf image. We do not use it when convolving the galaxy # with the psf. this_psf = psf.shift(dx,dy) # Make the final image, convolving with the (unshifted) psf final_gal = galsim.Convolve([psf,this_gal]) # Draw the image final_gal.drawImage(sub_gal_image) # Now add an appropriate amount of noise to get our desired S/N # There are lots of definitions of S/N, but here is the one used by Great08 # We use a weighted integral of the flux: # S = sum W(x,y) I(x,y) / sum W(x,y) # N^2 = Var(S) = sum W(x,y)^2 Var(I(x,y)) / (sum W(x,y))^2 # Now we assume that Var(I(x,y)) is constant so # Var(I(x,y)) = noise_var # We also assume that we are using a matched filter for W, so W(x,y) = I(x,y). # Then a few things cancel and we find that # S/N = sqrt( sum I(x,y)^2 / noise_var ) # # The above procedure is encapsulated in the function image.addNoiseSNR which # sets the flux appropriately given the variance of the noise model. # In our case, noise_var = sky_level_pixel sky_level_pixel = sky_level * pixel_scale**2 noise = galsim.PoissonNoise(ud, sky_level=sky_level_pixel) sub_gal_image.addNoiseSNR(noise, gal_signal_to_noise) # Draw the PSF image # No noise on PSF images. Just draw it as is. this_psf.drawImage(sub_psf_image) # For first instance, measure moments if ix==0 and iy==0: psf_shape = sub_psf_image.FindAdaptiveMom() temp_e = psf_shape.observed_shape.e if temp_e > 0.0: g_to_e = psf_shape.observed_shape.g / temp_e else: g_to_e = 0.0 logger.info('Measured best-fit elliptical Gaussian for first PSF image: ') logger.info(' g1, g2, sigma = %7.4f, %7.4f, %7.4f (pixels)', g_to_e*psf_shape.observed_shape.e1, g_to_e*psf_shape.observed_shape.e2, psf_shape.moments_sigma) x = b.center().x y = b.center().y logger.info('Galaxy (%d,%d): center = (%.0f,%0.f) (e,beta) = (%.4f,%.3f)', ix,iy,x,y,ellip,beta/galsim.radians) k = k+1 logger.info('Done making images of postage stamps') # Now write the images to disk. psf_image.write(psf_file_name) logger.info('Wrote PSF file %s',psf_file_name) gal_image.write(gal_file_name) logger.info('Wrote image to %r',gal_file_name) # using %r adds quotes around filename for us
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 _GenerateFromRandomGaussian(param, param_name, base, value_type): """@brief Return a random value drawn from a Gaussian distribution """ if 'rng' not in base: raise ValueError( "No base['rng'] available for %s.type = RandomGaussian" % param_name) rng = base['rng'] req = {'sigma': float} opt = {'mean': float, 'min': float, 'max': float} kwargs, safe = GetAllParams(param, param_name, base, req=req, opt=opt) sigma = kwargs['sigma'] if 'gd' in base: # Minor subtlety here. GaussianDeviate requires two random numbers to # generate a single Gaussian deviate. But then it gets a second # deviate for free. So it's more efficient to store gd than to make # a new one each time. So check if we did that. gd = base['gd'] if base['current_gdsigma'] != sigma: gd.setSigma(sigma) base['current_gdsigma'] = sigma else: # Otherwise, just go ahead and make a new one. gd = galsim.GaussianDeviate(rng, sigma=sigma) base['gd'] = gd base['current_gdsigma'] = sigma if 'min' in kwargs or 'max' in kwargs: # Clip at min/max. # However, special cases if min == mean or max == mean # -- can use fabs to double the chances of falling in the range. mean = kwargs.get('mean', 0.) min = kwargs.get('min', -float('inf')) max = kwargs.get('max', float('inf')) do_abs = False do_neg = False if min == mean: do_abs = True max -= mean min = -max elif max == mean: do_abs = True do_neg = True min -= mean max = -min else: min -= mean max -= mean # Emulate a do-while loop #print 'sigma = ',sigma import math while True: val = gd() #print 'val = ',val if do_abs: val = math.fabs(val) if val >= min and val <= max: break if do_neg: val = -val val += mean else: val = gd() if 'mean' in kwargs: val += kwargs['mean'] #print 'RandomGaussian: ',val return val, False
def build_file(seed, file_name, mass): """A function that does all the work to build a single file. Returns the total time taken. """ t1 = time.time() full_image = galsim.ImageF(image_size, image_size) full_image.setScale(pixel_scale) # The weight image will hold the inverse variance for each pixel. weight_image = galsim.ImageF(image_size, image_size) weight_image.setScale(pixel_scale) # It is common for astrometric images to also have a bad pixel mask. We don't have any # defect simulation currently, so our bad pixel masks are currently all zeros. # But someday, we plan to add defect functionality to GalSim, at which point, we'll # be able to mark those defects on a bad pixel mask. # Note: the S in ImageS means to use "short int" for the data type. # This is a typical choice for a bad pixel image. badpix_image = galsim.ImageS(image_size, image_size) badpix_image.setScale(pixel_scale) # Setup the NFWHalo stuff: nfw = galsim.NFWHalo(mass=mass, conc=nfw_conc, redshift=nfw_z_halo, omega_m=omega_m, omega_lam=omega_lam) # Note: the last two are optional. If they are omitted, then (omega_m=0.3, omega_lam=0.7) # are actually the defaults. If you only specify one of them, the other is set so that # the total is 1. But you can define both values so that the total is not 1 if you want. # Radiation is assumed to be zero and dark energy equation of state w = -1. # If you want to include either radiation or more complicated dark energy models, # you can define your own cosmology class that defines the functions a(z), E(a), and # Da(z_source, z_lens). Then you can pass this to NFWHalo as a `cosmo` parameter. # The "true" center of the image is allowed to be halfway between two pixels, as is the # case for even-sized images. full_image.bounds.center() is an integer position, # which would be 1/2 pixel up and to the right of the true center in this case. im_center = full_image.bounds.trueCenter() for k in range(nobj): # Initialize the random number generator we will be using for this object: rng = galsim.UniformDeviate(seed+k) # Determine where this object is going to go. # We choose points randomly within a donut centered at the center of the main image # in order to avoid placing galaxies too close to the halo center where the lensing # is not weak. We use an inner radius of 10 arcsec and an outer radius of 50 arcsec, # which takes us essentially to the edge of the image. radius = 50 inner_radius = 10 max_rsq = radius**2 min_rsq = inner_radius**2 while True: # (This is essentially a do..while loop.) x = (2.*rng()-1) * radius y = (2.*rng()-1) * radius rsq = x**2 + y**2 if rsq >= min_rsq and rsq <= max_rsq: break pos = galsim.PositionD(x,y) # We also need the position in pixels to determine where to place the postage # stamp on the full image. image_pos = pos / pixel_scale + im_center # For even-sized postage stamps, the nominal center (returned by stamp.bounds.center()) # cannot be at the true center (returned by stamp.bounds.trueCenter()) of the postage # stamp, since the nominal center values have to be integers. Thus, the nominal center # is 1/2 pixel up and to the right of the true center. # If we used odd-sized postage stamps, we wouldn't need to do this. x_nominal = image_pos.x + 0.5 y_nominal = image_pos.y + 0.5 # Get the integer values of these which will be the actual nominal center of the # postage stamp image. ix_nominal = int(math.floor(x_nominal+0.5)) iy_nominal = int(math.floor(y_nominal+0.5)) # The remainder will be accounted for in a shift dx = x_nominal - ix_nominal dy = y_nominal - iy_nominal # Make the pixel: pix = galsim.Pixel(pixel_scale) # Make the PSF profile: psf = galsim.Kolmogorov(fwhm = psf_fwhm) # Determine the random values for the galaxy: flux = rng() * (gal_flux_max-gal_flux_min) + gal_flux_min hlr = rng() * (gal_hlr_max-gal_hlr_min) + gal_hlr_min gd = galsim.GaussianDeviate(rng, sigma = gal_eta_rms) eta1 = gd() # Unlike g or e, large values of eta are valid, so no need to cutoff. eta2 = gd() # Make the galaxy profile with these values: gal = galsim.Exponential(half_light_radius=hlr, flux=flux) gal.applyShear(eta1=eta1, eta2=eta2) # Now apply the appropriate lensing effects for this position from # the NFW halo mass. try: g1,g2 = nfw.getShear( pos , nfw_z_source ) shear = galsim.Shear(g1=g1,g2=g2) except: # This shouldn't happen, since we exclude the inner 10 arcsec, but it's a # good idea to use the try/except block here anyway. import warnings warnings.warn("Warning: NFWHalo shear is invalid -- probably strong lensing! " + "Using shear = 0.") shear = galsim.Shear(g1=0,g2=0) mu = nfw.getMagnification( pos , nfw_z_source ) if mu < 0: import warnings warnings.warn("Warning: mu < 0 means strong lensing! Using mu=25.") mu = 25 elif mu > 25: import warnings warnings.warn("Warning: mu > 25 means strong lensing! Using mu=25.") mu = 25 gal.applyMagnification(mu) gal.applyShear(shear) # Build the final object final = galsim.Convolve([psf, pix, gal]) # Account for the non-integral portion of the position final.applyShift(dx*pixel_scale,dy*pixel_scale) # Draw the stamp image stamp = final.draw(dx=pixel_scale) # Recenter the stamp at the desired position: stamp.setCenter(ix_nominal,iy_nominal) # Find overlapping bounds bounds = stamp.bounds & full_image.bounds full_image[bounds] += stamp[bounds] # Add Poisson noise to the full image sky_level_pixel = sky_level * pixel_scale**2 # Going to the next seed isn't really required, but it matches the behavior of the # config parser, so doing this will result in identical output files. # If you didn't care about that, you could instead construct this as a continuation # of the last RNG from the above loop rng = galsim.BaseDeviate(seed+nobj) full_image.addNoise(galsim.PoissonNoise(rng,sky_level=sky_level_pixel)) # For the weight image, we only want the noise from the sky. (If we were including # read_noise, we'd want that as well.) Including the Poisson noise from the objects # as well tends to bias fits that use this as a weight, since the model becomes # magnitude-dependent. # The variance is just sky_level_pixel. And we want the inverse of this. weight_image.fill(1./sky_level_pixel) # Write the file to disk: galsim.fits.writeMulti([full_image, badpix_image, weight_image], file_name) t2 = time.time() return t2-t1
def test_float_value(): """Test various ways to generate a float value """ import time t1 = time.time() config = { 'input': { 'catalog': [{ 'dir': 'config_input', 'file_name': 'catalog.txt' }, { 'dir': 'config_input', 'file_name': 'catalog.fits' }], 'dict': [{ 'dir': 'config_input', 'file_name': 'dict.p' }, { 'dir': 'config_input', 'file_name': 'dict.json' }, { 'dir': 'config_input', 'file_name': 'dict.yaml' }] }, 'val1': 9.9, 'val2': int(400), 'str1': '8.73', 'str2': '2.33e-9', 'str3': '6.e-9', 'cat1': { 'type': 'Catalog', 'col': 0 }, 'cat2': { 'type': 'Catalog', 'col': 1 }, 'cat3': { 'type': 'Catalog', 'num': 1, 'col': 'float1' }, 'cat4': { 'type': 'Catalog', 'num': 1, 'col': 'float2' }, 'ran1': { 'type': 'Random', 'min': 0.5, 'max': 3 }, 'ran2': { 'type': 'Random', 'min': -5, 'max': 0 }, 'gauss1': { 'type': 'RandomGaussian', 'sigma': 1 }, 'gauss2': { 'type': 'RandomGaussian', 'sigma': 3, 'mean': 4 }, 'gauss3': { 'type': 'RandomGaussian', 'sigma': 1.5, 'min': -2, 'max': 2 }, 'gauss4': { 'type': 'RandomGaussian', 'sigma': 0.5, 'min': 0, 'max': 0.8 }, 'gauss5': { 'type': 'RandomGaussian', 'sigma': 0.3, 'mean': 0.5, 'min': 0, 'max': 0.5 }, 'dist1': { 'type': 'RandomDistribution', 'function': 'config_input/distribution.txt', 'interpolant': 'linear' }, 'dist2': { 'type': 'RandomDistribution', 'function': 'config_input/distribution2.txt', 'interpolant': 'linear' }, 'dist3': { 'type': 'RandomDistribution', 'function': 'x*x', 'x_min': 0., 'x_max': 2.0 }, 'dev1': { 'type': 'RandomPoisson', 'mean': 137 }, 'dev2': { 'type': 'RandomBinomial', 'N': 17 }, 'dev3': { 'type': 'RandomBinomial', 'N': 17, 'p': 0.2 }, 'dev4': { 'type': 'RandomWeibull', 'a': 1.7, 'b': 4.3 }, 'dev5': { 'type': 'RandomGamma', 'k': 1, 'theta': 4 }, 'dev6': { 'type': 'RandomGamma', 'k': 1.9, 'theta': 4.1 }, 'dev7': { 'type': 'RandomChi2', 'n': 17 }, 'seq1': { 'type': 'Sequence' }, 'seq2': { 'type': 'Sequence', 'step': 0.1 }, 'seq3': { 'type': 'Sequence', 'first': 1.5, 'step': 0.5 }, 'seq4': { 'type': 'Sequence', 'first': 10, 'step': -2 }, 'seq5': { 'type': 'Sequence', 'first': 1, 'last': 2.1, 'repeat': 2 }, 'list1': { 'type': 'List', 'items': [73, 8.9, 3.14] }, 'list2': { 'type': 'List', 'items': [0.6, 1.8, 2.1, 3.7, 4.3, 5.5, 6.1, 7.0, 8.6, 9.3, 10.8, 11.2], 'index': { 'type': 'Sequence', 'first': 10, 'step': -3 } }, 'dict1': { 'type': 'Dict', 'key': 'f' }, 'dict2': { 'type': 'Dict', 'num': 1, 'key': 'f' }, 'dict3': { 'type': 'Dict', 'num': 2, 'key': 'f' }, 'dict4': { 'type': 'Dict', 'num': 2, 'key': 'noise.models.1.gain' }, 'sum1': { 'type': 'Sum', 'items': [72, '2.33', { 'type': 'Dict', 'key': 'f' }] } } test_yaml = True try: galsim.config.ProcessInput(config) except: # We don't require PyYAML as a dependency, so if this fails, just remove the YAML dict. del config['input']['dict'][2] galsim.config.ProcessInput(config) test_yaml = False # Test direct values val1 = galsim.config.ParseValue(config, 'val1', config, float)[0] np.testing.assert_almost_equal(val1, 9.9) val2 = galsim.config.ParseValue(config, 'val2', config, float)[0] np.testing.assert_almost_equal(val2, 400) # Test conversions from strings str1 = galsim.config.ParseValue(config, 'str1', config, float)[0] np.testing.assert_almost_equal(str1, 8.73) str2 = galsim.config.ParseValue(config, 'str2', config, float)[0] np.testing.assert_almost_equal(str2, 2.33e-9) str3 = galsim.config.ParseValue(config, 'str3', config, float)[0] np.testing.assert_almost_equal(str3, 6.0e-9) # Test values read from a Catalog cat1 = [] cat2 = [] cat3 = [] cat4 = [] config['index_key'] = 'file_num' for k in range(5): config['file_num'] = k cat1.append(galsim.config.ParseValue(config, 'cat1', config, float)[0]) cat2.append(galsim.config.ParseValue(config, 'cat2', config, float)[0]) cat3.append(galsim.config.ParseValue(config, 'cat3', config, float)[0]) cat4.append(galsim.config.ParseValue(config, 'cat4', config, float)[0]) np.testing.assert_array_almost_equal(cat1, [1.234, 2.345, 3.456, 1.234, 2.345]) np.testing.assert_array_almost_equal(cat2, [4.131, -900, 8000, 4.131, -900]) np.testing.assert_array_almost_equal(cat3, [1.234, 2.345, 3.456, 1.234, 2.345]) np.testing.assert_array_almost_equal(cat4, [4.131, -900, 8000, 4.131, -900]) # Test values generated from a uniform deviate rng = galsim.UniformDeviate(1234) config['rng'] = galsim.UniformDeviate( 1234) # A second copy starting with the same seed. for k in range(6): config[ 'obj_num'] = k # The Random type doesn't use obj_num, but this keeps it # from thinking current_val is still current. ran1 = galsim.config.ParseValue(config, 'ran1', config, float)[0] np.testing.assert_almost_equal(ran1, rng() * 2.5 + 0.5) ran2 = galsim.config.ParseValue(config, 'ran2', config, float)[0] np.testing.assert_almost_equal(ran2, rng() * 5 - 5) # Test values generated from a Gaussian deviate for k in range(6): config['obj_num'] = k gauss1 = galsim.config.ParseValue(config, 'gauss1', config, float)[0] gd = galsim.GaussianDeviate(rng, mean=0, sigma=1) np.testing.assert_almost_equal(gauss1, gd()) gauss2 = galsim.config.ParseValue(config, 'gauss2', config, float)[0] gd = galsim.GaussianDeviate(rng, mean=4, sigma=3) np.testing.assert_almost_equal(gauss2, gd()) gauss3 = galsim.config.ParseValue(config, 'gauss3', config, float)[0] gd = galsim.GaussianDeviate(rng, mean=0, sigma=1.5) gd_val = gd() while math.fabs(gd_val) > 2: gd_val = gd() np.testing.assert_almost_equal(gauss3, gd_val) gauss4 = galsim.config.ParseValue(config, 'gauss4', config, float)[0] gd = galsim.GaussianDeviate(rng, mean=0, sigma=0.5) gd_val = math.fabs(gd()) while gd_val > 0.8: gd_val = math.fabs(gd()) np.testing.assert_almost_equal(gauss4, gd_val) gauss5 = galsim.config.ParseValue(config, 'gauss5', config, float)[0] gd = galsim.GaussianDeviate(rng, mean=0.5, sigma=0.3) gd_val = gd() if gd_val > 0.5: gd_val = 1 - gd_val while gd_val < 0: gd_val = gd() if gd_val > 0.5: gd_val = 1 - gd_val np.testing.assert_almost_equal(gauss5, gd_val) # Test values generated from a distribution in a file dd = galsim.DistDeviate(rng, function='config_input/distribution.txt', interpolant='linear') for k in range(6): config['obj_num'] = k dist1 = galsim.config.ParseValue(config, 'dist1', config, float)[0] np.testing.assert_almost_equal(dist1, dd()) dd = galsim.DistDeviate(rng, function='config_input/distribution2.txt', interpolant='linear') for k in range(6): config['obj_num'] = k dist2 = galsim.config.ParseValue(config, 'dist2', config, float)[0] np.testing.assert_almost_equal(dist2, dd()) dd = galsim.DistDeviate(rng, function=lambda x: x * x, x_min=0., x_max=2.) for k in range(6): config['obj_num'] = k dist3 = galsim.config.ParseValue(config, 'dist3', config, float)[0] np.testing.assert_almost_equal(dist3, dd()) # Test values generated from various other deviates for k in range(6): config['obj_num'] = k dev = galsim.PoissonDeviate(rng, mean=137) dev1 = galsim.config.ParseValue(config, 'dev1', config, float)[0] np.testing.assert_almost_equal(dev1, dev()) dev = galsim.BinomialDeviate(rng, N=17) dev2 = galsim.config.ParseValue(config, 'dev2', config, float)[0] np.testing.assert_almost_equal(dev2, dev()) dev = galsim.BinomialDeviate(rng, N=17, p=0.2) dev3 = galsim.config.ParseValue(config, 'dev3', config, float)[0] np.testing.assert_almost_equal(dev3, dev()) dev = galsim.WeibullDeviate(rng, a=1.7, b=4.3) dev4 = galsim.config.ParseValue(config, 'dev4', config, float)[0] np.testing.assert_almost_equal(dev4, dev()) dev = galsim.GammaDeviate(rng, k=1, theta=4) dev5 = galsim.config.ParseValue(config, 'dev5', config, float)[0] np.testing.assert_almost_equal(dev5, dev()) dev = galsim.GammaDeviate(rng, k=1.9, theta=4.1) dev6 = galsim.config.ParseValue(config, 'dev6', config, float)[0] np.testing.assert_almost_equal(dev6, dev()) dev = galsim.Chi2Deviate(rng, n=17) dev7 = galsim.config.ParseValue(config, 'dev7', config, float)[0] np.testing.assert_almost_equal(dev7, dev()) # Test values generated from a Sequence seq1 = [] seq2 = [] seq3 = [] seq4 = [] seq5 = [] config['index_key'] = 'file_num' for k in range(6): config['file_num'] = k seq1.append(galsim.config.ParseValue(config, 'seq1', config, float)[0]) config['index_key'] = 'image_num' for k in range(6): config['image_num'] = k seq2.append(galsim.config.ParseValue(config, 'seq2', config, float)[0]) config['index_key'] = 'obj_num' for k in range(6): config['obj_num'] = k seq3.append(galsim.config.ParseValue(config, 'seq3', config, float)[0]) config['index_key'] = 'obj_num_in_file' config['start_obj_num'] = 10 for k in range(6): config['obj_num'] = k + 10 seq4.append(galsim.config.ParseValue(config, 'seq4', config, float)[0]) seq5.append(galsim.config.ParseValue(config, 'seq5', config, float)[0]) np.testing.assert_array_almost_equal(seq1, [0, 1, 2, 3, 4, 5]) np.testing.assert_array_almost_equal(seq2, [0, 0.1, 0.2, 0.3, 0.4, 0.5]) np.testing.assert_array_almost_equal(seq3, [1.5, 2, 2.5, 3, 3.5, 4]) np.testing.assert_array_almost_equal(seq4, [10, 8, 6, 4, 2, 0]) np.testing.assert_array_almost_equal(seq5, [1, 1, 2, 2, 1, 1]) # Test values taken from a List list1 = [] list2 = [] config['index_key'] = 'obj_num' for k in range(5): config['obj_num'] = k list1.append( galsim.config.ParseValue(config, 'list1', config, float)[0]) list2.append( galsim.config.ParseValue(config, 'list2', config, float)[0]) np.testing.assert_array_almost_equal(list1, [73, 8.9, 3.14, 73, 8.9]) np.testing.assert_array_almost_equal(list2, [10.8, 7.0, 4.3, 1.8, 10.8]) # Test values read from a Dict dict = [] dict.append(galsim.config.ParseValue(config, 'dict1', config, float)[0]) dict.append(galsim.config.ParseValue(config, 'dict2', config, float)[0]) if test_yaml: dict.append( galsim.config.ParseValue(config, 'dict3', config, float)[0]) dict.append( galsim.config.ParseValue(config, 'dict4', config, float)[0]) else: dict.append(0.1) dict.append(1.9) np.testing.assert_array_almost_equal(dict, [23.17, -17.23, 0.1, 1.9]) sum1 = galsim.config.ParseValue(config, 'sum1', config, float)[0] np.testing.assert_almost_equal(sum1, 72 + 2.33 + 23.17) t2 = time.time() print 'time for %s = %.2f' % (funcname(), t2 - t1)
def test_variable_gaussian_noise(): """Test VariableGaussian random number generator """ # Make a checkerboard image with two values for the variance gSigma1 = 17.23 gSigma2 = 28.55 var_image = galsim.ImageD(galsim.BoundsI(0, 9, 0, 9)) coords = np.ogrid[0:10, 0:10] var_image.array[(coords[0] + coords[1]) % 2 == 1] = gSigma1**2 var_image.array[(coords[0] + coords[1]) % 2 == 0] = gSigma2**2 print('var_image.array = ', var_image.array) g = galsim.GaussianDeviate(testseed, sigma=1.) vgResult = np.empty((10, 10)) g.generate(vgResult) vgResult *= np.sqrt(var_image.array) # Test filling an image vgn = galsim.VariableGaussianNoise(galsim.BaseDeviate(testseed), var_image) testimage = galsim.ImageD(10, 10) testimage.addNoise(vgn) np.testing.assert_array_almost_equal( testimage.array, vgResult, precision, err_msg= "VariableGaussianNoise applied to Images does not reproduce expected sequence" ) # Test filling an image with Fortran ordering vgn.rng.seed(testseed) testimage = galsim.ImageD(np.zeros((10, 10)).T) testimage.addNoise(vgn) np.testing.assert_array_almost_equal( testimage.array, vgResult, precision, err_msg= "Wrong VariableGaussian noise generated for Fortran-ordered Image") # Check var_image property np.testing.assert_almost_equal( vgn.var_image.array, var_image.array, precision, err_msg="VariableGaussianNoise var_image returns wrong var_image") # Check that the noise model really does produce this variance. big_var_image = galsim.ImageD(galsim.BoundsI(0, 2047, 0, 2047)) big_coords = np.ogrid[0:2048, 0:2048] mask1 = (big_coords[0] + big_coords[1]) % 2 == 0 mask2 = (big_coords[0] + big_coords[1]) % 2 == 1 big_var_image.array[mask1] = gSigma1**2 big_var_image.array[mask2] = gSigma2**2 big_vgn = galsim.VariableGaussianNoise(galsim.BaseDeviate(testseed), big_var_image) big_im = galsim.Image(2048, 2048, dtype=float) big_im.addNoise(big_vgn) var = np.var(big_im.array) print('variance = ', var) print('getVar = ', big_vgn.var_image.array.mean()) np.testing.assert_almost_equal( var, big_vgn.var_image.array.mean(), 1, err_msg= 'Realized variance for VariableGaussianNoise did not match var_image') # Check realized variance in each mask print('rms1 = ', np.std(big_im.array[mask1])) print('rms2 = ', np.std(big_im.array[mask2])) np.testing.assert_almost_equal(np.std(big_im.array[mask1]), gSigma1, decimal=1) np.testing.assert_almost_equal(np.std(big_im.array[mask2]), gSigma2, decimal=1) # Check that VariableGaussianNoise adds to the image, not overwrites the image. gal = galsim.Exponential(half_light_radius=2.3, flux=1.e4) gal.drawImage(image=big_im) big_vgn.rng.seed(testseed) big_im.addNoise(big_vgn) gal.withFlux(-1.e4).drawImage(image=big_im, add_to_image=True) var = np.var(big_im.array) np.testing.assert_almost_equal( var, big_vgn.var_image.array.mean(), 1, err_msg= 'VariableGaussianNoise wrong when already an object drawn on the image' ) # Check picklability do_pickle(vgn, lambda x: (x.rng.serialize(), x.var_image)) do_pickle(vgn, drawNoise) do_pickle(vgn) # Check copy, eq and ne vgn2 = galsim.VariableGaussianNoise(vgn.rng.duplicate(), var_image) vgn3 = vgn.copy() vgn4 = vgn.copy(rng=galsim.BaseDeviate(11)) vgn5 = galsim.VariableGaussianNoise(vgn.rng, 2. * var_image) assert vgn == vgn2 assert vgn == vgn3 assert vgn != vgn4 assert vgn != vgn5 assert vgn.rng.raw() == vgn2.rng.raw() assert vgn == vgn2 assert vgn == vgn3 vgn.rng.raw() assert vgn != vgn2 assert vgn == vgn3 assert_raises(TypeError, vgn.applyTo, 23) assert_raises(ValueError, vgn.applyTo, galsim.ImageF(3, 3)) assert_raises(galsim.GalSimError, vgn.getVariance) assert_raises(galsim.GalSimError, vgn.withVariance, 23) assert_raises(galsim.GalSimError, vgn.withScaledVariance, 23)
def test_dep_random(): """Test the deprecated methods in galsim/deprecated/random.py """ rng = galsim.BaseDeviate(123) gd = galsim.GaussianDeviate(rng, mean=0.5, sigma=1.7) np.testing.assert_almost_equal(gd.getMean(), 0.5) np.testing.assert_almost_equal(gd.getSigma(), 1.7) check_dep(gd.setMean, 0.9) np.testing.assert_almost_equal(gd.getMean(), 0.9) np.testing.assert_almost_equal(gd.getSigma(), 1.7) check_dep(gd.setSigma, 2.3) np.testing.assert_almost_equal(gd.getMean(), 0.9) np.testing.assert_almost_equal(gd.getSigma(), 2.3) bd = galsim.BinomialDeviate(rng, N=7, p=0.7) np.testing.assert_almost_equal(bd.getN(), 7) np.testing.assert_almost_equal(bd.getP(), 0.7) check_dep(bd.setN, 9) np.testing.assert_almost_equal(bd.getN(), 9) np.testing.assert_almost_equal(bd.getP(), 0.7) check_dep(bd.setP, 0.3) np.testing.assert_almost_equal(bd.getN(), 9) np.testing.assert_almost_equal(bd.getP(), 0.3) pd = galsim.PoissonDeviate(rng, mean=0.5) np.testing.assert_almost_equal(pd.getMean(), 0.5) check_dep(pd.setMean, 0.9) np.testing.assert_almost_equal(pd.getMean(), 0.9) wd = galsim.WeibullDeviate(rng, a=0.5, b=1.7) np.testing.assert_almost_equal(wd.getA(), 0.5) np.testing.assert_almost_equal(wd.getB(), 1.7) check_dep(wd.setA, 0.9) np.testing.assert_almost_equal(wd.getA(), 0.9) np.testing.assert_almost_equal(wd.getB(), 1.7) check_dep(wd.setB, 2.3) np.testing.assert_almost_equal(wd.getA(), 0.9) np.testing.assert_almost_equal(wd.getB(), 2.3) gd = galsim.GammaDeviate(rng, k=0.5, theta=1.7) np.testing.assert_almost_equal(gd.getK(), 0.5) np.testing.assert_almost_equal(gd.getTheta(), 1.7) check_dep(gd.setK, 0.9) np.testing.assert_almost_equal(gd.getK(), 0.9) np.testing.assert_almost_equal(gd.getTheta(), 1.7) check_dep(gd.setTheta, 2.3) np.testing.assert_almost_equal(gd.getK(), 0.9) np.testing.assert_almost_equal(gd.getTheta(), 2.3) cd = galsim.Chi2Deviate(rng, n=5) np.testing.assert_almost_equal(cd.getN(), 5) check_dep(cd.setN, 9) np.testing.assert_almost_equal(cd.getN(), 9)
def build_file(seed, file_name, mass, nobj): """A function that does all the work to build a single file. Returns the total time taken. """ t1 = time.time() # Build the image onto which we will draw the galaxies. full_image = galsim.ImageF(image_size, image_size) # The "true" center of the image is allowed to be halfway between two pixels, as is the # case for even-sized images. full_image.bounds.center() is an integer position, # which would be 1/2 pixel up and to the right of the true center in this case. im_center = full_image.bounds.trueCenter() # For the WCS, this time we use UVFunction, which lets you define arbitrary u(x,y) # and v(x,y) functions. We use a simple cubic radial function to create a # pincushion distortion. This is a typical kind of telescope distortion, although # we exaggerate the magnitude of the effect to make it more apparent. # The pixel size in the center of the image is 0.05, but near the corners (r=362), # the pixel size is approximately 0.075, which is much more distortion than is # normally present in typical telescopes. But it makes the effect of the variable # pixel area obvious when you look at the weight image in the output files. ufunc1 = lambda x, y: 0.05 * x * (1. + 2.e-6 * (x**2 + y**2)) vfunc1 = lambda x, y: 0.05 * y * (1. + 2.e-6 * (x**2 + y**2)) # It's not required to provide the inverse functions. However, if we don't, then # you will only be able to do toWorld operations, not the inverse toImage. # The inverse function does not have to be exact either. For example, you could provide # a function that does some kind of iterative solution to whatever accuracy you care # about. But in this case, we can do the exact inverse. # # Let w = sqrt(u**2 + v**2) and r = sqrt(x**2 + y**2). Then the solutions are: # x = (u/w) r and y = (u/w) r, and we use Cardano's method to solve for r given w: # See http://en.wikipedia.org/wiki/Cubic_function#Cardano.27s_method # # w = 0.05 r + 2.e-6 * 0.05 * r**3 # r = 100 * ( ( 5 sqrt(w**2 + 5.e3/27) + 5 w )**(1./3.) - # - ( 5 sqrt(w**2 + 5.e3/27) - 5 w )**(1./3.) ) def xfunc1(u, v): import math wsq = u * u + v * v if wsq == 0.: return 0. else: w = math.sqrt(wsq) temp = 5. * math.sqrt(wsq + 5.e3 / 27) r = 100. * ((temp + 5 * w)**(1. / 3.) - (temp - 5 * w)**(1. / 3)) return u * r / w def yfunc1(u, v): import math wsq = u * u + v * v if wsq == 0.: return 0. else: w = math.sqrt(wsq) temp = 5. * math.sqrt(wsq + 5.e3 / 27) r = 100. * ((temp + 5 * w)**(1. / 3.) - (temp - 5 * w)**(1. / 3)) return v * r / w # You could pass the above functions to UVFunction, and normally we would do that. # The only down side to doing so is that the specification of the WCS in the FITS # file is rather ugly. GalSim is able to turn the python byte code into strings, # but they are basically a really ugly mess of random-looking characters. GalSim # will be able to read it back in, but human readers will have no idea what WCS # function was used. To see what they look like, uncomment this line and comment # out the later wcs line. #wcs = galsim.UVFunction(ufunc1, vfunc1, xfunc1, yfunc1, origin=im_center) # If you provide the functions as strings, then those strings will be preserved # in the FITS header in a form that is more legible to human readers. # It also has the extra benefit of matching the output from demo9.yaml, which we # always try to do. The config file has no choice but to specify the functions # as strings. ufunc = '0.05 * x * (1. + 2.e-6 * (x**2 + y**2))' vfunc = '0.05 * y * (1. + 2.e-6 * (x**2 + y**2))' xfunc = ( '( lambda w: ( 0 if w==0 else ' + '100.*u/w*(( 5*(w**2 + 5.e3/27.)**0.5 + 5*w )**(1./3.) - ' + '( 5*(w**2 + 5.e3/27.)**0.5 - 5*w )**(1./3.))))( (u**2+v**2)**0.5 )' ) yfunc = ( '( lambda w: ( 0 if w==0 else ' + '100.*v/w*(( 5*(w**2 + 5.e3/27.)**0.5 + 5*w )**(1./3.) - ' + '( 5*(w**2 + 5.e3/27.)**0.5 - 5*w )**(1./3.))))( (u**2+v**2)**0.5 )' ) # The origin parameter defines where on the image should be considered (x,y) = (0,0) # in the WCS functions. wcs = galsim.UVFunction(ufunc, vfunc, xfunc, yfunc, origin=im_center) # Assign this wcs to full_image full_image.wcs = wcs # The weight image will hold the inverse variance for each pixel. # We can set the wcs directly on construction with the wcs parameter. weight_image = galsim.ImageF(image_size, image_size, wcs=wcs) # It is common for astrometric images to also have a bad pixel mask. We don't have any # defect simulation currently, so our bad pixel masks are currently all zeros. # But someday, we plan to add defect functionality to GalSim, at which point, we'll # be able to mark those defects on a bad pixel mask. # Note: the S in ImageS means to use "short int" for the data type. # This is a typical choice for a bad pixel image. badpix_image = galsim.ImageS(image_size, image_size, wcs=wcs) # We also draw a PSF image at the location of every galaxy. This isn't normally done, # and since some of the PSFs overlap, it's not necessarily so useful to have this kind # of image. But in this case, it's fun to look at the psf image, especially with # something like log scaling in ds9 to see how crazy an aberrated OpticalPSF with # struts can look when there is no atmospheric component to blur it out. psf_image = galsim.ImageF(image_size, image_size, wcs=wcs) # Setup the NFWHalo stuff: nfw = galsim.NFWHalo(mass=mass, conc=nfw_conc, redshift=nfw_z_halo, omega_m=omega_m, omega_lam=omega_lam) # Note: the last two are optional. If they are omitted, then (omega_m=0.3, omega_lam=0.7) # are actually the defaults. If you only specify one of them, the other is set so that # the total is 1. But you can define both values so that the total is not 1 if you want. # Radiation is assumed to be zero and dark energy equation of state w = -1. # If you want to include either radiation or more complicated dark energy models, # you can define your own cosmology class that defines the functions a(z), E(a), and # Da(z_source, z_lens). Then you can pass this to NFWHalo as a `cosmo` parameter. # Make the PSF profile outside the loop to minimize the (significant) OpticalPSF # construction overhead. psf = galsim.OpticalPSF(lam_over_diam=psf_lam_over_D, obscuration=psf_obsc, nstruts=psf_nstruts, strut_thick=psf_strut_thick, strut_angle=psf_strut_angle, defocus=psf_defocus, astig1=psf_astig1, astig2=psf_astig2, coma1=psf_coma1, coma2=psf_coma2, trefoil1=psf_trefoil1, trefoil2=psf_trefoil2) for k in range(nobj): # Initialize the random number generator we will be using for this object: rng = galsim.UniformDeviate(seed + k) # Determine where this object is going to go. # We choose points randomly within a donut centered at the center of the main image # in order to avoid placing galaxies too close to the halo center where the lensing # is not weak. We use an inner radius of 3 arcsec and an outer radius of 12 arcsec, # which takes us essentially to the edge of the image. radius = 12 inner_radius = 3 max_rsq = radius**2 min_rsq = inner_radius**2 while True: # (This is essentially a do..while loop.) x = (2. * rng() - 1) * radius y = (2. * rng() - 1) * radius rsq = x**2 + y**2 if rsq >= min_rsq and rsq <= max_rsq: break pos = galsim.PositionD(x, y) # We also need the position in pixels to determine where to place the postage # stamp on the full image. image_pos = wcs.toImage(pos) # For even-sized postage stamps, the nominal center (returned by stamp.bounds.center()) # cannot be at the true center (returned by stamp.bounds.trueCenter()) of the postage # stamp, since the nominal center values have to be integers. Thus, the nominal center # is 1/2 pixel up and to the right of the true center. # If we used odd-sized postage stamps, we wouldn't need to do this. x_nominal = image_pos.x + 0.5 y_nominal = image_pos.y + 0.5 # Get the integer values of these which will be the actual nominal center of the # postage stamp image. ix_nominal = int(math.floor(x_nominal + 0.5)) iy_nominal = int(math.floor(y_nominal + 0.5)) # The remainder will be accounted for in an offset when we draw. dx = x_nominal - ix_nominal dy = y_nominal - iy_nominal offset = galsim.PositionD(dx, dy) # Determine the random values for the galaxy: flux = rng() * (gal_flux_max - gal_flux_min) + gal_flux_min hlr = rng() * (gal_hlr_max - gal_hlr_min) + gal_hlr_min gd = galsim.GaussianDeviate(rng, sigma=gal_eta_rms) eta1 = gd( ) # Unlike g or e, large values of eta are valid, so no need to cutoff. eta2 = gd() # Make the galaxy profile with these values: gal = galsim.Exponential(half_light_radius=hlr, flux=flux) gal = gal.shear(eta1=eta1, eta2=eta2) # Now apply the appropriate lensing effects for this position from # the NFW halo mass. try: g1, g2 = nfw.getShear(pos, nfw_z_source) nfw_shear = galsim.Shear(g1=g1, g2=g2) except: # This shouldn't happen, since we exclude the inner 10 arcsec, but it's a # good idea to use the try/except block here anyway. import warnings warnings.warn( "Warning: NFWHalo shear is invalid -- probably strong lensing! " + "Using shear = 0.") nfw_shear = galsim.Shear(g1=0, g2=0) nfw_mu = nfw.getMagnification(pos, nfw_z_source) if nfw_mu < 0: import warnings warnings.warn( "Warning: mu < 0 means strong lensing! Using mu=25.") nfw_mu = 25 elif nfw_mu > 25: import warnings warnings.warn( "Warning: mu > 25 means strong lensing! Using mu=25.") nfw_mu = 25 # Calculate the total shear to apply # Since shear addition is not commutative, it is worth pointing out that # the order is in the sense that the second shear is applied first, and then # the first shear. i.e. The field shear is taken to be behind the cluster. # Kind of a cosmic shear contribution between the source and the cluster. # However, this is not quite the same thing as doing: # gal.shear(field_shear).shear(nfw_shear) # since the shear addition ignores the rotation that would occur when doing the # above lines. This is normally ok, because the rotation is not observable, but # it is worth keeping in mind. total_shear = nfw_shear + field_shear # Apply the magnification and shear to the galaxy gal = gal.magnify(nfw_mu) gal = gal.shear(total_shear) # Build the final object final = galsim.Convolve([psf, gal]) # Draw the stamp image # To draw the image at a position other than the center of the image, you can # use the offset parameter, which applies an offset in pixels relative to the # center of the image. # We also need to provide the local wcs at the current position. local_wcs = wcs.local(image_pos) stamp = final.drawImage(wcs=local_wcs, offset=offset) # Recenter the stamp at the desired position: stamp.setCenter(ix_nominal, iy_nominal) # Find overlapping bounds bounds = stamp.bounds & full_image.bounds full_image[bounds] += stamp[bounds] # Also draw the PSF psf_stamp = galsim.ImageF( stamp.bounds) # Use same bounds as galaxy stamp psf.drawImage(psf_stamp, wcs=local_wcs, offset=offset) psf_image[bounds] += psf_stamp[bounds] # Add Poisson noise to the full image # Note: The normal calculation of Poission noise isn't quite correct right now. # The pixel area is variable, which means the amount of sky flux that enters each # pixel is also variable. The wcs classes have a function `makeSkyImage` which # will fill an image with the correct amount of sky flux given the sky level # in units of ADU/arcsec^2. We use the weight image as our work space for this. wcs.makeSkyImage(weight_image, sky_level) # Add this to the current full_image (temporarily). full_image += weight_image # Add Poisson noise, given the current full_image. # Going to the next seed isn't really required, but it matches the behavior of the # config parser, so doing this will result in identical output files. # If you didn't care about that, you could instead construct this as a continuation # of the last RNG from the above loop rng = galsim.BaseDeviate(seed + nobj) full_image.addNoise(galsim.PoissonNoise(rng)) # Subtract the sky back off. full_image -= weight_image # The weight image is nominally the inverse variance of the pixel noise. However, it is # common to exclude the Poisson noise from the objects themselves and only include the # noise from the sky photons. The variance of the noise is just the sky level, which is # what is currently in the weight_image. (If we wanted to include the variance from the # objects too, then we could use the full_image before we added the PoissonNoise to it.) # So all we need to do now is to invert the values in weight_image. weight_image.invertSelf() # Write the file to disk: galsim.fits.writeMulti( [full_image, badpix_image, weight_image, psf_image], file_name) t2 = time.time() return t2 - t1
def test_gaussian_noise(): """Test Gaussian random number generator """ gSigma = 17.23 g = galsim.GaussianDeviate(testseed, sigma=gSigma) gResult = np.empty((10, 10)) g.generate(gResult) noise = galsim.DeviateNoise(g) # Test filling an image testimage = galsim.ImageD(10, 10) noise.rng.seed(testseed) testimage.addNoise(noise) np.testing.assert_array_almost_equal( testimage.array, gResult, precision, err_msg= 'Wrong Gaussian random number sequence generated when applied to image.' ) # Test filling a single-precision image noise.rng.seed(testseed) testimage = galsim.ImageF(10, 10) testimage.addNoise(noise) np.testing.assert_array_almost_equal( testimage.array, gResult, precisionF, err_msg= 'Wrong Gaussian random number sequence generated when applied to ImageF.' ) # GaussianNoise is equivalent, but no mean allowed. gn = galsim.GaussianNoise(galsim.BaseDeviate(testseed), sigma=gSigma) testimage = galsim.ImageD(10, 10) testimage.addNoise(gn) np.testing.assert_array_almost_equal( testimage.array, gResult, precision, err_msg= "GaussianNoise applied to Images does not reproduce expected sequence") # Test filling an image with Fortran ordering gn.rng.seed(testseed) testimage = galsim.ImageD(np.zeros((10, 10)).T) testimage.addNoise(gn) np.testing.assert_array_almost_equal( testimage.array, gResult, precision, err_msg="Wrong Gaussian noise generated for Fortran-ordered Image") # Check GaussianNoise variance: np.testing.assert_almost_equal( gn.getVariance(), gSigma**2, precision, err_msg="GaussianNoise getVariance returns wrong variance") np.testing.assert_almost_equal( gn.sigma, gSigma, precision, err_msg="GaussianNoise sigma returns wrong value") # Check that the noise model really does produce this variance. big_im = galsim.Image(2048, 2048, dtype=float) gn.rng.seed(testseed) big_im.addNoise(gn) var = np.var(big_im.array) print('variance = ', var) print('getVar = ', gn.getVariance()) np.testing.assert_almost_equal( var, gn.getVariance(), 1, err_msg= 'Realized variance for GaussianNoise did not match getVariance()') # Check that GaussianNoise adds to the image, not overwrites the image. gal = galsim.Exponential(half_light_radius=2.3, flux=1.e4) gal.drawImage(image=big_im) gn.rng.seed(testseed) big_im.addNoise(gn) gal.withFlux(-1.e4).drawImage(image=big_im, add_to_image=True) var = np.var(big_im.array) np.testing.assert_almost_equal( var, gn.getVariance(), 1, err_msg='GaussianNoise wrong when already an object drawn on the image' ) # Check that DeviateNoise adds to the image, not overwrites the image. gal.drawImage(image=big_im) gn.rng.seed(testseed) big_im.addNoise(gn) gal.withFlux(-1.e4).drawImage(image=big_im, add_to_image=True) var = np.var(big_im.array) np.testing.assert_almost_equal( var, gn.getVariance(), 1, err_msg='DeviateNoise wrong when already an object drawn on the image') # Check withVariance gn = gn.withVariance(9.) np.testing.assert_almost_equal( gn.getVariance(), 9, precision, err_msg="GaussianNoise withVariance results in wrong variance") np.testing.assert_almost_equal( gn.sigma, 3., precision, err_msg="GaussianNoise withVariance results in wrong sigma") # Check withScaledVariance gn = gn.withScaledVariance(4.) np.testing.assert_almost_equal( gn.getVariance(), 36., precision, err_msg="GaussianNoise withScaledVariance results in wrong variance") np.testing.assert_almost_equal( gn.sigma, 6., precision, err_msg="GaussianNoise withScaledVariance results in wrong sigma") # Check arithmetic gn = gn.withVariance(0.5) gn2 = gn * 3 np.testing.assert_almost_equal( gn2.getVariance(), 1.5, precision, err_msg="GaussianNoise gn*3 results in wrong variance") np.testing.assert_almost_equal( gn.getVariance(), 0.5, precision, err_msg="GaussianNoise gn*3 results in wrong variance for original gn") gn2 = 5 * gn np.testing.assert_almost_equal( gn2.getVariance(), 2.5, precision, err_msg="GaussianNoise 5*gn results in wrong variance") np.testing.assert_almost_equal( gn.getVariance(), 0.5, precision, err_msg="GaussianNoise 5*gn results in wrong variance for original gn") gn2 = gn / 2 np.testing.assert_almost_equal( gn2.getVariance(), 0.25, precision, err_msg="GaussianNoise gn/2 results in wrong variance") np.testing.assert_almost_equal( gn.getVariance(), 0.5, precision, err_msg="GaussianNoise 5*gn results in wrong variance for original gn") gn *= 3 np.testing.assert_almost_equal( gn.getVariance(), 1.5, precision, err_msg="GaussianNoise gn*=3 results in wrong variance") gn /= 2 np.testing.assert_almost_equal( gn.getVariance(), 0.75, precision, err_msg="GaussianNoise gn/=2 results in wrong variance") # Check starting with GaussianNoise() gn2 = galsim.GaussianNoise() gn2 = gn2.withVariance(9.) np.testing.assert_almost_equal( gn2.getVariance(), 9, precision, err_msg="GaussianNoise().withVariance results in wrong variance") np.testing.assert_almost_equal( gn2.sigma, 3., precision, err_msg="GaussianNoise().withVariance results in wrong sigma") gn2 = galsim.GaussianNoise() gn2 = gn2.withScaledVariance(4.) np.testing.assert_almost_equal( gn2.getVariance(), 4., precision, err_msg="GaussianNoise().withScaledVariance results in wrong variance") np.testing.assert_almost_equal( gn2.sigma, 2., precision, err_msg="GaussianNoise().withScaledVariance results in wrong sigma") # Check picklability do_pickle(gn, lambda x: (x.rng.serialize(), x.sigma)) do_pickle(gn, drawNoise) do_pickle(gn) # Check copy, eq and ne gn = gn.withVariance(gSigma**2) gn2 = galsim.GaussianNoise(gn.rng.duplicate(), gSigma) gn3 = gn.copy() gn4 = gn.copy(rng=galsim.BaseDeviate(11)) gn5 = galsim.GaussianNoise(gn.rng, 2. * gSigma) assert gn == gn2 assert gn == gn3 assert gn != gn4 assert gn != gn5 assert gn.rng.raw() == gn2.rng.raw() assert gn == gn2 assert gn == gn3 gn.rng.raw() assert gn != gn2 assert gn == gn3
def make_default_input(): # Set the PSF catalogue values moffat_beta = np.zeros(NOBJECTS) + MOFFAT_BETA moffat_fwhm = np.zeros(NOBJECTS) + MOFFAT_FWHM moffat_e1 = np.zeros(NOBJECTS) + MOFFAT_E1 moffat_e2 = np.zeros(NOBJECTS) + MOFFAT_E2 moffat_trunc = np.zeros(NOBJECTS) + MOFFAT_TRUNCATIONFWHM * MOFFAT_FWHM # Then set the exponential disc catalogue fixed values exponential_hlr = np.zeros(NOBJECTS) + EXPONENTIAL_HLR # Then set the dVc bulge catalogue fixed values devaucouleurs_hlr = np.zeros(NOBJECTS) + DEVAUCOULEURS_HLR # Then set up the Gaussian RNG for making the ellipticity values urng = galsim.UniformDeviate(RNG_SEED) edist = galsim.GaussianDeviate(urng, sigma=EXPONENTIAL_DEVAUCOULEURS_SIGMA_E) # Slightly hokey way of making vectors of Gaussian deviates, using images... No direct NumPy # array-filling with galsim RNGs at the moment. # # In GREAT08 these galaxy ellipticies were made in rotated pairs to reduce shape noise, but for # this illustrative default file we do not do this. ime1 = galsim.ImageD(NOBJECTS, 1) ime1.addNoise(edist) exponential_e1 = ime1.array.flatten() ime2 = galsim.ImageD(NOBJECTS, 1) ime2.addNoise(edist) exponential_e2 = ime2.array.flatten() # Make galaxies co-elliptical devaucouleurs_e1 = exponential_e1 devaucouleurs_e2 = exponential_e2 # Add a centroid shift in drawn uniform randomly from the unit circle around (0., 0.) dx = np.empty(NOBJECTS) dy = np.empty(NOBJECTS) for i in xrange(NOBJECTS): # Apply a random centroid shift: rsq = 2 * GAL_CENTROID_SHIFT_RADIUS_SQUARED while (rsq > GAL_CENTROID_SHIFT_RADIUS_SQUARED): dx[i] = (2. * urng() - 1.) * GAL_CENTROID_SHIFT_RADIUS dy[i] = (2. * urng() - 1.) * GAL_CENTROID_SHIFT_RADIUS rsq = dx[i]**2 + dy[i]**2 # Then write this to file path, modfile = os.path.split(__file__) outfile = os.path.join(path, "galsim_default_input.asc") # Make a nice header with the default fields described header = ("# psf.beta psf.fwhm psf.e1 psf.e2 psf.trunc" + " disk.hlr disk.e1 disk.e2" + " bulge.hlr bulge.e1 bulge.e2" + " gal.shift.dx gal.shift.dy \n") # Open the file and output the columns in the correct order, row-by-row output = open(outfile, "w") output.write( "# galsim_default_input.asc : illustrative default input catalog for GalSim\n" ) output.write("#\n") output.write(header) for i in xrange(NOBJECTS): outline = (" %6.2f %6.2f %7.3f %7.3f %6.2f %6.2f %14.7f %14.7f "+ "%6.2f %14.7f %14.7f %14.7f %14.7f\n") % \ (moffat_beta[i], moffat_fwhm[i], moffat_e1[i], moffat_e2[i], moffat_trunc[i], exponential_hlr[i], exponential_e1[i], exponential_e2[i], devaucouleurs_hlr[i], devaucouleurs_e1[i], devaucouleurs_e2[i], dx[i], dy[i]) output.write(outline) output.close()
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, mean=0.0, sigma=gaussSig)) outFile = outDir + ('BT%5.3f.' % bt) outFile += 'bulgeellip%5.3f.' % bell outFile += 'diskellip%5.3f.' % dell outFile += 'diskRe%5.3f.' % diskRe[dreind] outFile += 'invSNR%5.3f.' % invSN[invsnind] outFile += 'image%02d.fits' % iRealization tmpImg.write(outFile, clobber=True) print 'Wrote image to file %s' % outFile else: # Just write to file without adding noise outFile = outDir + 'BT%5.3f.' % bt outFile += 'bulgeellip%5.3f.' % bell outFile += 'diskellip%5.3f.' % dell outFile += 'diskRe%5.3f.' % diskRe[dreind]
def __init__(self, sigma, rng): self.ellip_sigma = sigma self.ud = rng self.gd = galsim.GaussianDeviate(self.ud, sigma=self.ellip_sigma)
def test_float_value(): """Test various ways to generate a float value """ import time t1 = time.time() config = { 'input' : { 'catalog' : { 'dir' : 'config_input', 'file_name' : 'catalog.txt' } }, 'val1' : 9.9, 'val2' : int(400), 'str1' : '8.73', 'str2' : '2.33e-9', 'str3' : '6.e-9', 'cat1' : { 'type' : 'InputCatalog' , 'col' : 0 }, 'cat2' : { 'type' : 'InputCatalog' , 'col' : 1 }, 'ran1' : { 'type' : 'Random', 'min' : 0.5, 'max' : 3 }, 'ran2' : { 'type' : 'Random', 'min' : -5, 'max' : 0 }, 'gauss1' : { 'type' : 'RandomGaussian', 'sigma' : 1 }, 'gauss2' : { 'type' : 'RandomGaussian', 'sigma' : 3, 'mean' : 4 }, 'gauss3' : { 'type' : 'RandomGaussian', 'sigma' : 1.5, 'min' : -2, 'max' : 2 }, 'gauss4' : { 'type' : 'RandomGaussian', 'sigma' : 0.5, 'min' : 0, 'max' : 0.8 }, 'gauss5' : { 'type' : 'RandomGaussian', 'sigma' : 0.3, 'mean' : 0.5, 'min' : 0, 'max' : 0.5 }, 'dist1' : { 'type' : 'RandomDistribution', 'function' : 'config_input/distribution.txt', 'interpolant' : 'linear' }, 'dist2' : { 'type' : 'RandomDistribution', 'function' : 'config_input/distribution2.txt', 'interpolant' : 'linear' }, 'dist3' : { 'type' : 'RandomDistribution', 'function' : 'x*x', 'x_min' : 0., 'x_max' : 2.0 }, 'seq1' : { 'type' : 'Sequence' }, 'seq2' : { 'type' : 'Sequence', 'step' : 0.1 }, 'seq3' : { 'type' : 'Sequence', 'first' : 1.5, 'step' : 0.5 }, 'seq4' : { 'type' : 'Sequence', 'first' : 10, 'step' : -2 }, 'seq5' : { 'type' : 'Sequence', 'first' : 1, 'last' : 2.1, 'repeat' : 2 }, 'list1' : { 'type' : 'List', 'items' : [ 73, 8.9, 3.14 ] }, 'list2' : { 'type' : 'List', 'items' : [ 0.6, 1.8, 2.1, 3.7, 4.3, 5.5, 6.1, 7.0, 8.6, 9.3, 10.8, 11.2 ], 'index' : { 'type' : 'Sequence', 'first' : 10, 'step' : -3 } } } galsim.config.ProcessInput(config) # Test direct values val1 = galsim.config.ParseValue(config,'val1',config, float)[0] np.testing.assert_almost_equal(val1, 9.9) val2 = galsim.config.ParseValue(config,'val2',config, float)[0] np.testing.assert_almost_equal(val2, 400) # Test conversions from strings str1 = galsim.config.ParseValue(config,'str1',config, float)[0] np.testing.assert_almost_equal(str1, 8.73) str2 = galsim.config.ParseValue(config,'str2',config, float)[0] np.testing.assert_almost_equal(str2, 2.33e-9) str3 = galsim.config.ParseValue(config,'str3',config, float)[0] np.testing.assert_almost_equal(str3, 6.0e-9) # Test values read from an InputCatalog input_cat = galsim.InputCatalog(dir='config_input', file_name='catalog.txt') cat1 = [] cat2 = [] for k in range(5): config['seq_index'] = k cat1.append(galsim.config.ParseValue(config,'cat1',config, float)[0]) cat2.append(galsim.config.ParseValue(config,'cat2',config, float)[0]) np.testing.assert_array_almost_equal(cat1, [ 1.234, 2.345, 3.456, 1.234, 2.345 ]) np.testing.assert_array_almost_equal(cat2, [ 4.131, -900, 8000, 4.131, -900 ]) # Test values generated from a uniform deviate rng = galsim.UniformDeviate(1234) config['rng'] = galsim.UniformDeviate(1234) # A second copy starting with the same seed. for k in range(6): ran1 = galsim.config.ParseValue(config,'ran1',config, float)[0] np.testing.assert_almost_equal(ran1, rng() * 2.5 + 0.5) ran2 = galsim.config.ParseValue(config,'ran2',config, float)[0] np.testing.assert_almost_equal(ran2, rng() * 5 - 5) # Test values generated from a Gaussian deviate gd = galsim.GaussianDeviate(rng) for k in range(6): gauss1 = galsim.config.ParseValue(config,'gauss1',config, float)[0] gd.setMean(0) gd.setSigma(1) np.testing.assert_almost_equal(gauss1, gd()) gauss2 = galsim.config.ParseValue(config,'gauss2',config, float)[0] gd.setMean(4) gd.setSigma(3) np.testing.assert_almost_equal(gauss2, gd()) gauss3 = galsim.config.ParseValue(config,'gauss3',config, float)[0] gd.setMean(0) gd.setSigma(1.5) gd_val = gd() while math.fabs(gd_val) > 2: gd_val = gd() np.testing.assert_almost_equal(gauss3, gd_val) gauss4 = galsim.config.ParseValue(config,'gauss4',config, float)[0] gd.setMean(0) gd.setSigma(0.5) gd_val = math.fabs(gd()) while gd_val > 0.8: gd_val = math.fabs(gd()) np.testing.assert_almost_equal(gauss4, gd_val) gauss5 = galsim.config.ParseValue(config,'gauss5',config, float)[0] gd.setMean(0.5) gd.setSigma(0.3) gd_val = gd() if gd_val > 0.5: gd_val = 1-gd_val while gd_val < 0: gd_val = gd() if gd_val > 0.5: gd_val = 1-gd_val np.testing.assert_almost_equal(gauss5, gd_val) # Test values generated from a distribution in a file dd=galsim.DistDeviate(rng,function='config_input/distribution.txt',interpolant='linear') for k in range(6): dist1 = galsim.config.ParseValue(config,'dist1',config, float)[0] np.testing.assert_almost_equal(dist1, dd()) dd=galsim.DistDeviate(rng,function='config_input/distribution2.txt',interpolant='linear') for k in range(6): dist2 = galsim.config.ParseValue(config,'dist2',config, float)[0] np.testing.assert_almost_equal(dist2, dd()) dd=galsim.DistDeviate(rng,function=lambda x: x*x,x_min=0.,x_max=2.) for k in range(6): dist3 = galsim.config.ParseValue(config,'dist3',config, float)[0] np.testing.assert_almost_equal(dist3, dd()) # Test values generated from a Sequence seq1 = [] seq2 = [] seq3 = [] seq4 = [] seq5 = [] for k in range(6): config['seq_index'] = k seq1.append(galsim.config.ParseValue(config,'seq1',config, float)[0]) seq2.append(galsim.config.ParseValue(config,'seq2',config, float)[0]) seq3.append(galsim.config.ParseValue(config,'seq3',config, float)[0]) seq4.append(galsim.config.ParseValue(config,'seq4',config, float)[0]) seq5.append(galsim.config.ParseValue(config,'seq5',config, float)[0]) np.testing.assert_array_almost_equal(seq1, [ 0, 1, 2, 3, 4, 5 ]) np.testing.assert_array_almost_equal(seq2, [ 0, 0.1, 0.2, 0.3, 0.4, 0.5 ]) np.testing.assert_array_almost_equal(seq3, [ 1.5, 2, 2.5, 3, 3.5, 4 ]) np.testing.assert_array_almost_equal(seq4, [ 10, 8, 6, 4, 2, 0 ]) np.testing.assert_array_almost_equal(seq5, [ 1, 1, 2, 2, 1, 1 ]) # Test values taken from a List list1 = [] list2 = [] for k in range(5): config['seq_index'] = k list1.append(galsim.config.ParseValue(config,'list1',config, float)[0]) list2.append(galsim.config.ParseValue(config,'list2',config, float)[0]) np.testing.assert_array_almost_equal(list1, [ 73, 8.9, 3.14, 73, 8.9 ]) np.testing.assert_array_almost_equal(list2, [ 10.8, 7.0, 4.3, 1.8, 10.8 ]) t2 = time.time() print 'time for %s = %.2f'%(funcname(),t2-t1)
gal_g1 = -0.4 + initial_n * 0.016 gal_g2 = -0.45 + initial_n * 0.018 #cat_file_name ='galsim_default_input.asc' #cat = galsim.Catalog(cat_file_name) shears1 = [] shears2 = [] numbers = [] ellipticities = [] size = [] flux = [] mag = [] sersic_indices = [] print 'hey' indices = [] gara = galsim.GaussianDeviate(mean=1., sigma=1) #random_seed, ############################gasn=galsim.GaussianDeviate(random_seed,mean=25.5,sigma=0.8) #gasn=galsim.GaussianDeviate(random_seed,mean=26,sigma=1.) #Currently draws for magnitudes. #0.5 ref_data = ascii.read( '/vol/aibn148/data1/bhernandez/PhD/PSF_HST/tmp.regions_VI3') goodgal = np.array([ref_data[i][2] for i in range(len(ref_data))]) goodregion = np.array([ref_data[i][1] for i in range(len(ref_data))]) VI = np.array([ref_data[i][5] for i in range(len(ref_data))]) #VI = VI[(goodgal>0)&(goodregion>0)] #ref_rad_tmp = [ref_data[i][4] for i in range(len(ref_data))] #ref_rad_tmp = np.array(ref_rad_tmp) #ref_rad = ref_rad_tmp[(goodgal>0.)&(goodregion>0.)&(VI<0.3)] ref_sn_tmp = [ref_data[i][3] for i in range(len(ref_data))] ref_sn_tmp = np.array(ref_sn_tmp)
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)
def __generateDeviates(self): # Generate random deviates ud = galsim.UniformDeviate(struct.unpack('i', os.urandom(4))[0]) gd = galsim.GaussianDeviate(ud, sigma=self.galData.ellipRMS) return (ud, gd)
def _random_screen(self): """Generate a random phase screen with power spectrum given by self._psi**2""" gd = galsim.GaussianDeviate(self.rng) noise = galsim.utilities.rand_arr(self._psi.shape, gd) return galsim.fft.ifft2(galsim.fft.fft2(noise)*self._psi).real
def test_uncorr_padding(): """Test for uncorrelated noise padding of InterpolatedImage.""" import time t1 = time.time() # Set up some defaults: use weird image sizes / shapes and noise variances. decimal_precise=5 decimal_coarse=2 orig_nx = 147 orig_ny = 174 noise_var = 1.73 big_nx = 519 big_ny = 482 orig_seed = 151241 # first, make a noise image orig_img = galsim.ImageF(orig_nx, orig_ny, scale=1.) gd = galsim.GaussianDeviate(orig_seed, mean=0., sigma=np.sqrt(noise_var)) orig_img.addNoise(galsim.DeviateNoise(gd)) # 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! # Note that this only works if the big image has the same even/odd-ness in the two sizes. # Otherwise the center of the original image will fall between pixels in the big image. # Then the variance will be smoothed somewhat by the interpolant. 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, noise_pad=noise_var, noise_pad_size=max(big_nx,big_ny), rng = galsim.GaussianDeviate(orig_seed)) # 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), noise_var, decimal=decimal_coarse, err_msg='Variance not correct after padding image with 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, noise_pad=noise_var, noise_pad_size=max(big_nx,big_ny), rng = galsim.GaussianDeviate(orig_seed)) 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 noise-padded image with same choice of seed') # Finally check inputs: what if we give it an input variance that is neg? A list? try: np.testing.assert_raises(ValueError,galsim.InterpolatedImage,orig_img,noise_pad=-1.) except ImportError: print 'The assert_raises tests require nose' t2 = time.time() print 'time for %s = %.2f'%(funcname(),t2-t1)
import time import numpy as np import galsim # Use a deterministic random number generator so we don't fail tests because of rare flukes # in the random numbers. rseed = 12345 smallim_size = 16 # size of image when we test correlated noise properties using small inputs largeim_size = 12 * smallim_size # ditto, but when we need a larger image if __name__ == "__main__": t1 = time.time() gd = galsim.GaussianDeviate(rseed) dx_cosmos = 0.03 # Non-unity, non-default value to be used below cn = galsim.getCOSMOSNoise( 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)
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)