def test_fourier_sqrt(): """Test that the FourierSqrt operator is the inverse of auto-convolution. """ import time t1 = time.time() dx = 0.4 myImg1 = galsim.ImageF(80, 80, scale=dx) myImg1.setCenter(0, 0) myImg2 = galsim.ImageF(80, 80, scale=dx) myImg2.setCenter(0, 0) # Test trivial case, where we could (but don't) analytically collapse the # chain of SBProfiles by recognizing that FourierSqrt is the inverse of # AutoConvolve. psf = galsim.Moffat(beta=3.8, fwhm=1.3, flux=5) psf.drawImage(myImg1, method='no_pixel') sqrt1 = galsim.FourierSqrt(psf) psf2 = galsim.AutoConvolve(sqrt1) np.testing.assert_almost_equal(psf.stepK(), psf2.stepK()) psf2.drawImage(myImg2, method='no_pixel') printval(myImg1, myImg2) np.testing.assert_array_almost_equal( myImg1.array, myImg2.array, 4, err_msg="Moffat sqrt convolved with self disagrees with original") # Test non-trivial case where we compare (in Fourier space) sqrt(a*a + b*b + 2*a*b) against (a + b) a = galsim.Moffat(beta=3.8, fwhm=1.3, flux=5) a.shift(dx=0.5, dy=-0.3) # need nonzero centroid to test centroid() b = galsim.Moffat(beta=2.5, fwhm=1.6, flux=3) check = galsim.Sum([a, b]) sqrt = galsim.FourierSqrt( galsim.Sum([ galsim.AutoConvolve(a), galsim.AutoConvolve(b), 2 * galsim.Convolve([a, b]) ])) np.testing.assert_almost_equal(check.stepK(), sqrt.stepK()) check.drawImage(myImg1, method='no_pixel') sqrt.drawImage(myImg2, method='no_pixel') np.testing.assert_almost_equal(check.centroid().x, sqrt.centroid().x) np.testing.assert_almost_equal(check.centroid().y, sqrt.centroid().y) np.testing.assert_almost_equal(check.getFlux(), sqrt.getFlux()) printval(myImg1, myImg2) np.testing.assert_array_almost_equal( myImg1.array, myImg2.array, 4, err_msg="Fourier square root of expanded square disagrees with original" ) # Check picklability do_pickle(sqrt1.SBProfile, lambda x: (repr(x.getObj()), x.getGSParams())) do_pickle(sqrt1, lambda x: x.drawImage(method='no_pixel')) do_pickle(sqrt1) do_pickle(sqrt1.SBProfile) t2 = time.time() print('time for %s = %.2f' % (funcname(), t2 - t1))
def test_sum_noise(): """Test that noise propagation works properly for compound objects. """ obj1 = galsim.Gaussian(sigma=1.7) obj2 = galsim.Gaussian(sigma=2.3) obj1.noise = galsim.UncorrelatedNoise(variance=0.3, scale=0.2) obj2.noise = galsim.UncorrelatedNoise(variance=0.5, scale=0.2) obj3 = galsim.Gaussian(sigma=2.9) # Sum adds the variance of the components sum2 = galsim.Sum([obj1,obj2]) np.testing.assert_almost_equal(sum2.noise.getVariance(), 0.8, err_msg = "Sum of two objects did not add noise varinace") sum2 = galsim.Sum([obj1,obj3]) np.testing.assert_almost_equal(sum2.noise.getVariance(), 0.3, err_msg = "Sum of two objects did not add noise varinace") sum2 = galsim.Sum([obj2,obj3]) np.testing.assert_almost_equal(sum2.noise.getVariance(), 0.5, err_msg = "Sum of two objects did not add noise varinace") sum3 = galsim.Sum([obj1,obj2,obj3]) np.testing.assert_almost_equal(sum3.noise.getVariance(), 0.8, err_msg = "Sum of three objects did not add noise varinace") sum3 = obj1 + obj2 + obj3 np.testing.assert_almost_equal(sum3.noise.getVariance(), 0.8, err_msg = "Sum of three objects did not add noise varinace") # Adding noise objects with different WCSs will raise a warning. obj4 = galsim.Gaussian(sigma=3.3) obj4.noise = galsim.UncorrelatedNoise(variance=0.3, scale=0.8) try: np.testing.assert_warns(galsim.GalSimWarning, galsim.Sum, [obj1, obj4]) except: pass
def _draw_objects(self): """ this is dumb, drawing into the full image when we don't need to """ self.imlist = [] cdisk = self['pdfs']['disk'] cbulge = self['pdfs']['bulge'] cknots = self['pdfs'].get('knots', None) for band in range(self['nband']): objects = [] for obj_parts in self.objlist: disk = obj_parts['disk'] * cdisk['color'][band] bulge = obj_parts['bulge'] * cbulge['color'][band] tparts = [disk, bulge] if cknots is not None: knots = obj_parts['knots'] * cknots['color'][band] tparts.append(knots) obj = galsim.Sum(tparts) obj = obj.shift( dx=obj_parts['cen'][0], dy=obj_parts['cen'][1], ) objects.append(obj) objects = galsim.Sum(objects) shear = self.get('shear', None) if shear is not None: objects = objects.shear( g1=shear[0], g2=shear[1], ) convolved_objects = galsim.Convolve(objects, self.psf) kw = {'scale': self['pixel_scale']} dims = self.get('dims', None) if dims is not None: kw['nx'], kw['ny'] = dims[1], dims[0] dims = np.array(self.psf_im.shape) image = convolved_objects.drawImage(**kw).array self.imlist.append(image)
def get_gal_wldeblend(*, rng, data): """Draw a galaxy from the weak lensing deblending package. Parameters ---------- rng : np.random.RandomState An RNG to use for making galaxies. data : WLDeblendData Namedtuple with data for making galaxies via the weak lesning deblending package. Returns ------- gal : galsim Object The galaxy as a galsim object. """ rind = rng.choice(data.cat.size) angle = rng.uniform() * 360 pa_angle = rng.uniform() * 360 data.cat['pa_disk'][rind] = pa_angle data.cat['pa_bulge'][rind] = pa_angle return galsim.Sum([ data.builders[band].from_catalog( data.cat[rind], 0, 0, data.surveys[band].filter_band).model.rotate( angle * galsim.degrees) for band in range(len(data.builders)) ])
def _func(x, y): if len(psfs) > 1: return galsim.Sum([ psf.getPSF(galsim.PositionD(x=x, y=y)) for psf in psfs ]).withFlux(1.0) else: return psfs[0].getPSF(galsim.PositionD(x=x, y=y))
def mockCoadd(self, variances, fwhms, psfs): weights = 1.0 / (fwhms**2 * variances) weights /= weights.sum() coadd_psf = galsim.Sum( [psf * weight for psf, weight in zip(psfs, weights)]) coadd_variance = (variances * weights * weights).sum() return coadd_variance, coadd_psf
def test_render_sources_for_image(): image_shape = (64, 64) wcs = galsim.PixelScale(0.25) draw_method = 'auto' src_inds = np.arange(5) def src_func(ind): obj = galsim.Gaussian(fwhm=ind * 0.1 + 0.9) rng = np.random.RandomState(seed=ind + 1) image_pos = galsim.PositionD( x=rng.uniform(low=20, high=40), y=rng.uniform(low=20, high=40), ) return obj, image_pos im = render_sources_for_image(image_shape=image_shape, wcs=wcs, draw_method=draw_method, src_inds=src_inds, src_func=src_func, n_jobs=1) # now render them via direct sum of objects objs = [] for ind in src_inds: obj, pos = src_func(ind) objs.append(obj.shift(dx=pos.x * 0.25, dy=pos.y * 0.25)) im_sum = galsim.Sum(objs).drawImage(wcs=wcs, nx=155, ny=155) # we set the center to (0, 0) so that the offsets from the center # match the coords of the objects im_sum.setCenter(0, 0) assert np.allclose(im_sum[im.bounds].array, im.array, rtol=0, atol=5e-7)
def test_ne(): """ Check that inequality works as expected.""" gsp = galsim.GSParams(maxk_threshold=1.1e-3, folding_threshold=5.1e-3) gal1 = galsim.Gaussian(fwhm=1) gal2 = galsim.Gaussian(fwhm=2) # Sum. Params are objs to add and potentially gsparams. gals = [ galsim.Sum(gal1), galsim.Sum(gal1, gal2), galsim.Sum(gal2, gal1), # Not! commutative. galsim.Sum(galsim.Sum(gal1, gal2), gal2), galsim.Sum(gal1, galsim.Sum(gal2, gal2)), # Not! associative. galsim.Sum(gal1, gsparams=gsp) ] all_obj_diff(gals) # Convolution. Params are objs to convolve and potentially gsparams. # The following should test unequal gals = [ galsim.Convolution(gal1), galsim.Convolution(gal1, gal2), galsim.Convolution(gal2, gal1), # Not! commutative. galsim.Convolution(gal1, gal2, real_space=True), galsim.Convolution(galsim.Convolution(gal1, gal2), gal2), galsim.Convolution(gal1, galsim.Convolution(gal2, gal2)), # Not! associative. galsim.Convolution(gal1, gsparams=gsp) ] all_obj_diff(gals) # Deconvolution. Only params here are obj to deconvolve and gsparams. gals = [ galsim.Deconvolution(gal1), galsim.Deconvolution(gal2), galsim.Deconvolution(gal1, gsparams=gsp) ] all_obj_diff(gals) # AutoConvolution. Only params here are obj to deconvolve and gsparams. gals = [ galsim.AutoConvolution(gal1), galsim.AutoConvolution(gal2), galsim.AutoConvolution(gal1, gsparams=gsp) ] all_obj_diff(gals) # AutoCorrelation. Only params here are obj to deconvolve and gsparams. gals = [ galsim.AutoCorrelation(gal1), galsim.AutoCorrelation(gal2), galsim.AutoCorrelation(gal1, gsparams=gsp) ] all_obj_diff(gals)
def test_sum_transform(): """This test addresses a bug found by Ismael Serrano, #763, wherein some attributes got messed up for a Transform(Sum(Transform())) object. The bug was that we didn't bother to make a new SBProfile for a Sum (or Convolve) of a single object. But if that was an SBTransform, then the next Transform operation combined the two Transforms, which messed up the repr. The fix is to always make an SBAdd or SBConvolve object even if the list of things to add or convolve only has one element. """ gal0 = galsim.Exponential(scale_radius=0.34, flux=105.).shear(g1=-0.56, g2=0.15) for gal1 in [galsim.Sum(gal0), galsim.Convolve(gal0)]: gal2 = gal1.dilate(1) sgal1 = eval(str(gal1)) rgal1 = eval(repr(gal1)) sgal2 = eval(str(gal2)) rgal2 = eval(repr(gal2)) print('gal1 = ', repr(gal1)) print('sgal1 = ', repr(sgal1)) print('rgal1 = ', repr(rgal1)) print('gal2 = ', repr(gal2)) print('sgal2 = ', repr(sgal2)) print('rgal2 = ', repr(rgal2)) gal1_im = gal1.drawImage(nx=64, ny=64, scale=0.2) sgal1_im = sgal1.drawImage(nx=64, ny=64, scale=0.2) rgal1_im = rgal1.drawImage(nx=64, ny=64, scale=0.2) gal2_im = gal2.drawImage(nx=64, ny=64, scale=0.2) sgal2_im = sgal2.drawImage(nx=64, ny=64, scale=0.2) rgal2_im = rgal2.drawImage(nx=64, ny=64, scale=0.2) # Check that the objects are equivalent, even if they may be written differently. np.testing.assert_almost_equal(gal1_im.array, sgal1_im.array, decimal=8) np.testing.assert_almost_equal(gal1_im.array, rgal1_im.array, decimal=8) # These two used to fail. np.testing.assert_almost_equal(gal2_im.array, sgal2_im.array, decimal=8) np.testing.assert_almost_equal(gal2_im.array, rgal2_im.array, decimal=8) do_pickle(gal0) do_pickle(gal1) do_pickle(gal2) # And this.
def mockCoadd(self, variances, fwhms, psfs): weights = 1.0 / variances weights /= weights.sum() coadd_variance = 1.0 / (1.0 / variances).sum() coadd_psf = galsim.FourierSqrt( galsim.Sum([ galsim.AutoCorrelate(psf) * weight for psf, weight in zip(psfs, weights) ])) return coadd_variance, coadd_psf
def test_gsparams(): """Test withGSParams with some non-default gsparams """ obj1 = galsim.Exponential(half_light_radius=1.7) obj2 = galsim.Pixel(scale=0.2) gsp = galsim.GSParams(folding_threshold=1.e-4, maxk_threshold=1.e-4, maximum_fft_size=1.e4) gsp2 = galsim.GSParams(folding_threshold=1.e-2, maxk_threshold=1.e-2) sum = galsim.Sum(obj1, obj2) sum1 = sum.withGSParams(gsp) assert sum.gsparams == galsim.GSParams() assert sum1.gsparams == gsp assert sum1.obj_list[0].gsparams == gsp assert sum1.obj_list[1].gsparams == gsp sum2 = galsim.Sum(obj1.withGSParams(gsp), obj2.withGSParams(gsp)) sum3 = galsim.Sum(galsim.Exponential(half_light_radius=1.7, gsparams=gsp), galsim.Pixel(scale=0.2)) sum4 = galsim.Add(obj1, obj2, gsparams=gsp) assert sum != sum1 assert sum1 == sum2 assert sum1 == sum3 assert sum1 == sum4 print('stepk = ', sum.stepk, sum1.stepk) assert sum1.stepk < sum.stepk print('maxk = ', sum.maxk, sum1.maxk) assert sum1.maxk > sum.maxk sum5 = galsim.Add(obj1, obj2, gsparams=gsp, propagate_gsparams=False) assert sum5 != sum4 assert sum5.gsparams == gsp assert sum5.obj_list[0].gsparams == galsim.GSParams() assert sum5.obj_list[1].gsparams == galsim.GSParams() sum6 = sum5.withGSParams(gsp2) assert sum6 != sum5 assert sum6.gsparams == gsp2 assert sum6.obj_list[0].gsparams == galsim.GSParams() assert sum6.obj_list[1].gsparams == galsim.GSParams()
def test_ne(): import time t1 = time.time() gsp = galsim.GSParams(maxk_threshold=1.1e-3, folding_threshold=5.1e-3) gal1 = galsim.Gaussian(fwhm=1) gal2 = galsim.Gaussian(fwhm=2) # Sum. Params are objs to add and potentially gsparams. gals = [galsim.Sum(gal1), galsim.Sum(gal1, gal2), galsim.Sum(gal2, gal1), # Not! commutative. galsim.Sum(galsim.Sum(gal1, gal2), gal2), galsim.Sum(gal1, galsim.Sum(gal2, gal2)), # Not! associative. galsim.Sum(gal1, gsparams=gsp)] all_obj_diff(gals) # Convolution. Params are objs to convolve and potentially gsparams. # The following should test unequal gals = [galsim.Convolution(gal1), galsim.Convolution(gal1, gal2), galsim.Convolution(gal2, gal1), # Not! commutative. galsim.Convolution(gal1, gal2, real_space=True), galsim.Convolution(galsim.Convolution(gal1, gal2), gal2), galsim.Convolution(gal1, galsim.Convolution(gal2, gal2)), # Not! associative. galsim.Convolution(gal1, gsparams=gsp)] all_obj_diff(gals) # Deconvolution. Only params here are obj to deconvolve and gsparams. gals = [galsim.Deconvolution(gal1), galsim.Deconvolution(gal2), galsim.Deconvolution(gal1, gsparams=gsp)] all_obj_diff(gals) # AutoConvolution. Only params here are obj to deconvolve and gsparams. gals = [galsim.AutoConvolution(gal1), galsim.AutoConvolution(gal2), galsim.AutoConvolution(gal1, gsparams=gsp)] all_obj_diff(gals) # AutoCorrelation. Only params here are obj to deconvolve and gsparams. gals = [galsim.AutoCorrelation(gal1), galsim.AutoCorrelation(gal2), galsim.AutoCorrelation(gal1, gsparams=gsp)] all_obj_diff(gals) t2 = time.time() print 'time for %s = %.2f'%(funcname(),t2-t1)
def test_ne(): """ Check that inequality works as expected.""" gsp = galsim.GSParams(maxk_threshold=1.1e-3, folding_threshold=5.1e-3) gal1 = galsim.Gaussian(fwhm=1) gal2 = galsim.Gaussian(fwhm=2) # Sum. Params are objs to add and potentially gsparams. gals = [galsim.Sum(gal1), galsim.Sum(gal1, gal2), galsim.Sum(gal2, gal1), # Not! commutative. (but is associative) galsim.Sum(galsim.Sum(gal1, gal2), gal2), galsim.Sum(gal1, gsparams=gsp), galsim.Sum(gal1, gsparams=gsp, propagate_gsparams=False)] all_obj_diff(gals)
def _set_coadded_psf(self): """ set the coadd psf wcs of final psf image is that of the *first*, since the coadd obs is a copy of that """ coadd_obs = self.coadd_obs weights = self.weights psf_wcs = coadd_obs.psf.jacobian.get_galsim_wcs() coadd_psf = galsim.Sum([psf * w for psf, w in zip(self.psfs, weights)]) coadd_psf_image = galsim.Image(self.psf_nx, self.psf_ny, wcs=psf_wcs) coadd_psf.drawImage(image=coadd_psf_image, method='no_pixel') coadd_psf_image = coadd_psf_image.array coadd_obs.psf.set_image(coadd_psf_image)
def test_gaussian_smoke(): obj = [ galsim.Gaussian(fwhm=GFWHM).shift(-12 - SCALE / 2, SCALE / 2), galsim.Gaussian(fwhm=GFWHM).shift(12 + SCALE / 2, SCALE / 2) ] pobj = [ galsim.Convolve(obj[0], galsim.Gaussian(fwhm=PSF_FAC)), galsim.Convolve(obj[1], galsim.Gaussian(fwhm=1.00)) ] def psf_model(row, col): if col >= 160 / 2: return galsim.Gaussian(fwhm=1.0).drawImage(scale=SCALE, nx=33, ny=33).array else: return galsim.Gaussian(fwhm=PSF_FAC).drawImage(scale=SCALE, nx=33, ny=33).array hpsf = PSFHomogenizer( psf_model, [160, 160], ) im_orig = galsim.Sum(pobj).drawImage(scale=SCALE, nx=160, ny=160).array imh = hpsf.homogenize_image(im_orig) def _subtract_mirrored(im, im_true): imn = np.zeros_like(im) mid = imn.shape[1] // 2 imn[:, :mid] = im[:, :mid] - im_true[:, mid:][:, ::-1] imn[:, mid:] = im[:, mid:] - im_true[:, mid:] return imn max_diff_hmg = np.max(np.abs(_subtract_mirrored(imh, imh) / imh.max())) max_diff_orig = np.max( np.abs(_subtract_mirrored(im_orig, im_orig) / im_orig.max())) assert max_diff_orig > 1e-2 assert max_diff_hmg < max_diff_orig / 10
def _set_coadded_image(self): """ do the actual coadding, with appropriate weights wcs of final image is that of the *first*, since the coadd obs is a copy of that """ coadd_obs = self.coadd_obs weights = self.weights wcs = coadd_obs.jacobian.get_galsim_wcs() coadd = galsim.Sum( [image * w for image, w in zip(self.images, weights)]) coadd_image = galsim.Image(self.nx, self.ny, wcs=wcs) coadd.drawImage( image=coadd_image, method='no_pixel', ) coadd_obs.set_image(coadd_image.array)
def _set_coadded_weight_map(self): """ coadd the noise image realizations and take var also set the .noise attribute """ coadd_obs = self.coadd_obs weights = self.weights weight_map = np.zeros((self.ny, self.nx)) wcs = coadd_obs.jacobian.get_galsim_wcs() coadd_noise = galsim.Sum( [image * w for image, w in zip(self.noise_images, weights)]) coadd_noise_image = galsim.Image(self.nx, self.ny, wcs=wcs) coadd_noise.drawImage(image=coadd_noise_image, method='no_pixel') weight_map[:, :] = 1. / np.var(coadd_noise_image.array) coadd_obs.set_weight(weight_map) coadd_obs.noise = coadd_noise_image.array
def _stack_ps_psfs(self, *, x, y, **kwargs): if not hasattr(self, '_psfs'): self._psfs = [[ PowerSpectrumPSF( rng=self.rng, im_width=self.dim, buff=self.dim/2, scale=self.scale, **kwargs) for _ in range(self.n_coadd_psf)] for _ in range(self.n_bands)] LOGGER.debug('stacking %d power spectrum psfs', self.n_coadd_psf) _psf_wcs = self._get_local_jacobian(x=x, y=y) test_psfs = [] for i in range(self.n_bands): test_psfs += [ p.getPSF(galsim.PositionD(x=x, y=y)) for p in self._psfs[i]] psf_dim = self._get_psf_box_size(test_psfs, _psf_wcs) psfs = [] psf_ims = [] for i in range(self.n_bands): psf = galsim.Sum([ p.getPSF(galsim.PositionD(x=x, y=y)) for p in self._psfs[i]]).withFlux(1) psf_im = psf.drawImage( nx=psf_dim, ny=psf_dim, wcs=_psf_wcs).array.copy() psf_im /= np.sum(psf_im) psfs.append(psf) psf_ims.append(psf_im) return psfs, psf_ims
def get_scene(self): """ get a scene with multiple objects """ c = self['scene'] dims = [int(c['size'] / self['pixel_scale'])] * 2 halfsize = c['size'] / 2.0 offset_radius = halfsize - 0.25 * halfsize objs = [] for i in range(c['nobjects']): obj = self._get_object() dx, dy = self.rng.uniform( low=-offset_radius, high=offset_radius, size=2, ) obj = obj.shift(dx=dx, dy=dy) objs.append(obj) all_obj = galsim.Sum(objs) im = self._get_image(all_obj, dims=dims) return im
def test_flip(): """Test several ways to flip a profile """ # The Shapelet profile has the advantage of being fast and not circularly symmetric, so # it is a good test of the actual code for doing the flips (in SBTransform). # But since the bug Rachel reported in #645 was actually in SBInterpolatedImage # (one calculation implicitly assumed dx > 0), it seems worthwhile to run through all the # classes to make sure we hit everything with negative steps for dx and dy. prof_list = [ galsim.Shapelet(sigma=0.17, order=2, bvec=[1.7, 0.01,0.03, 0.29, 0.33, -0.18]), ] if __name__ == "__main__": image_dir = './real_comparison_images' catalog_file = 'test_catalog.fits' rgc = galsim.RealGalaxyCatalog(catalog_file, dir=image_dir) # Some of these are slow, so only do the Shapelet test as part of the normal unit tests. prof_list += [ galsim.Airy(lam_over_diam=0.17, flux=1.7), galsim.Airy(lam_over_diam=0.17, obscuration=0.2, flux=1.7), # Box gets rendered with real-space convolution. The default accuracy isn't quite # enough to get the flip to match at 6 decimal places. galsim.Box(0.17, 0.23, flux=1.7, gsparams=galsim.GSParams(realspace_relerr=1.e-6)), # Without being convolved by anything with a reasonable k cutoff, this needs # a very large fft. galsim.DeVaucouleurs(half_light_radius=0.17, flux=1.7), # I don't really understand why this needs a lower maxk_threshold to work, but # without it, the k-space tests fail. galsim.Exponential(scale_radius=0.17, flux=1.7, gsparams=galsim.GSParams(maxk_threshold=1.e-4)), galsim.Gaussian(sigma=0.17, flux=1.7), galsim.Kolmogorov(fwhm=0.17, flux=1.7), galsim.Moffat(beta=2.5, fwhm=0.17, flux=1.7), galsim.Moffat(beta=2.5, fwhm=0.17, flux=1.7, trunc=0.82), galsim.OpticalPSF(lam_over_diam=0.17, obscuration=0.2, nstruts=6, coma1=0.2, coma2=0.5, defocus=-0.1, flux=1.7), # Like with Box, we need to increase the real-space convolution accuracy. # This time lowering both relerr and abserr. galsim.Pixel(0.23, flux=1.7, gsparams=galsim.GSParams(realspace_relerr=1.e-6, realspace_abserr=1.e-8)), # Note: RealGalaxy should not be rendered directly because of the deconvolution. # Here we convolve it by a Gaussian that is slightly larger than the original PSF. galsim.Convolve([ galsim.RealGalaxy(rgc, index=0, flux=1.7), # "Real" RealGalaxy galsim.Gaussian(sigma=0.08) ]), galsim.Convolve([ galsim.RealGalaxy(rgc, index=1, flux=1.7), # "Fake" RealGalaxy galsim.Gaussian(sigma=0.08) ]), # (cf. test_real.py) galsim.Spergel(nu=-0.19, half_light_radius=0.17, flux=1.7), galsim.Spergel(nu=0., half_light_radius=0.17, flux=1.7), galsim.Spergel(nu=0.8, half_light_radius=0.17, flux=1.7), galsim.Sersic(n=2.3, half_light_radius=0.17, flux=1.7), galsim.Sersic(n=2.3, half_light_radius=0.17, flux=1.7, trunc=0.82), # The shifts here caught a bug in how SBTransform handled the recentering. # Two of the shifts (0.125 and 0.375) lead back to 0.0 happening on an integer # index, which now works correctly. galsim.Sum([ galsim.Gaussian(sigma=0.17, flux=1.7).shift(-0.2,0.125), galsim.Exponential(scale_radius=0.23, flux=3.1).shift(0.375,0.23)]), galsim.TopHat(0.23, flux=1.7), # Box and Pixel use real-space convolution. Convolve with a Gaussian to get fft. galsim.Convolve([ galsim.Box(0.17, 0.23, flux=1.7).shift(-0.2,0.1), galsim.Gaussian(sigma=0.09) ]), galsim.Convolve([ galsim.TopHat(0.17, flux=1.7).shift(-0.275,0.125), galsim.Gaussian(sigma=0.09) ]), # Test something really crazy with several layers worth of transformations galsim.Convolve([ galsim.Sum([ galsim.Gaussian(sigma=0.17, flux=1.7).shear(g1=0.1,g2=0.2).shift(2,3), galsim.Kolmogorov(fwhm=0.33, flux=3.9).transform(0.31,0.19,-0.23,0.33) * 88., galsim.Box(0.11, 0.44, flux=4).rotate(33 * galsim.degrees) / 1.9 ]).shift(-0.3,1), galsim.AutoConvolve(galsim.TopHat(0.5).shear(g1=0.3,g2=0)).rotate(3*galsim.degrees), (galsim.AutoCorrelate(galsim.Box(0.2, 0.3)) * 11).shift(3,2).shift(2,-3) * 0.31 ]).shift(0,0).transform(0,-1,-1,0).shift(-1,1) ] s = galsim.Shear(g1=0.11, g2=-0.21) s1 = galsim.Shear(g1=0.11, g2=0.21) # Appropriate for the flips around x and y axes s2 = galsim.Shear(g1=-0.11, g2=-0.21) # Appropriate for the flip around x=y # Also use shears with just a g1 to get dx != dy, but dxy, dyx = 0. q = galsim.Shear(g1=0.11, g2=0.) q1 = galsim.Shear(g1=0.11, g2=0.) # Appropriate for the flips around x and y axes q2 = galsim.Shear(g1=-0.11, g2=0.) # Appropriate for the flip around x=y decimal=6 # Oddly, these aren't as precise as I would have expected. # Even when we only go to this many digits of accuracy, the Exponential needed # a lower than default value for maxk_threshold. im = galsim.ImageD(16,16, scale=0.05) for prof in prof_list: print('prof = ',prof) # Not all profiles are expected to have a max_sb value close to the maximum pixel value, # so mark the ones where we don't want to require this to be true. close_maxsb = True name = str(prof) if ('DeVauc' in name or 'Sersic' in name or 'Spergel' in name or 'Optical' in name or 'shift' in name): close_maxsb = False # Make sure we hit all 4 fill functions. # image_x uses fillXValue with izero, jzero # image_x1 uses fillXValue with izero, jzero, and unequal dx,dy # image_x2 uses fillXValue with dxy, dyx # image_k uses fillKValue with izero, jzero # image_k1 uses fillKValue with izero, jzero, and unequal dx,dy # image_k2 uses fillKValue with dxy, dyx image_x = prof.drawImage(image=im.copy(), method='no_pixel') image_x1 = prof.shear(q).drawImage(image=im.copy(), method='no_pixel') image_x2 = prof.shear(s).drawImage(image=im.copy(), method='no_pixel') image_k = prof.drawImage(image=im.copy()) image_k1 = prof.shear(q).drawImage(image=im.copy()) image_k2 = prof.shear(s).drawImage(image=im.copy()) if close_maxsb: np.testing.assert_allclose( image_x.array.max(), prof.max_sb*im.scale**2, rtol=0.2, err_msg="max_sb did not match maximum pixel value") np.testing.assert_allclose( image_x1.array.max(), prof.shear(q).max_sb*im.scale**2, rtol=0.2, err_msg="max_sb did not match maximum pixel value") np.testing.assert_allclose( image_x2.array.max(), prof.shear(s).max_sb*im.scale**2, rtol=0.2, err_msg="max_sb did not match maximum pixel value") # Flip around y axis (i.e. x -> -x) flip1 = prof.transform(-1, 0, 0, 1) image2_x = flip1.drawImage(image=im.copy(), method='no_pixel') np.testing.assert_array_almost_equal( image_x.array, image2_x.array[:,::-1], decimal=decimal, err_msg="Flipping image around y-axis failed x test") image2_x1 = flip1.shear(q1).drawImage(image=im.copy(), method='no_pixel') np.testing.assert_array_almost_equal( image_x1.array, image2_x1.array[:,::-1], decimal=decimal, err_msg="Flipping image around y-axis failed x1 test") image2_x2 = flip1.shear(s1).drawImage(image=im.copy(), method='no_pixel') np.testing.assert_array_almost_equal( image_x2.array, image2_x2.array[:,::-1], decimal=decimal, err_msg="Flipping image around y-axis failed x2 test") image2_k = flip1.drawImage(image=im.copy()) np.testing.assert_array_almost_equal( image_k.array, image2_k.array[:,::-1], decimal=decimal, err_msg="Flipping image around y-axis failed k test") image2_k1 = flip1.shear(q1).drawImage(image=im.copy()) np.testing.assert_array_almost_equal( image_k1.array, image2_k1.array[:,::-1], decimal=decimal, err_msg="Flipping image around y-axis failed k1 test") image2_k2 = flip1.shear(s1).drawImage(image=im.copy()) np.testing.assert_array_almost_equal( image_k2.array, image2_k2.array[:,::-1], decimal=decimal, err_msg="Flipping image around y-axis failed k2 test") if close_maxsb: np.testing.assert_allclose( image2_x.array.max(), flip1.max_sb*im.scale**2, rtol=0.2, err_msg="max_sb did not match maximum pixel value") np.testing.assert_allclose( image2_x1.array.max(), flip1.shear(q).max_sb*im.scale**2, rtol=0.2, err_msg="max_sb did not match maximum pixel value") np.testing.assert_allclose( image2_x2.array.max(), flip1.shear(s).max_sb*im.scale**2, rtol=0.2, err_msg="max_sb did not match maximum pixel value") # Flip around x axis (i.e. y -> -y) flip2 = prof.transform(1, 0, 0, -1) image2_x = flip2.drawImage(image=im.copy(), method='no_pixel') np.testing.assert_array_almost_equal( image_x.array, image2_x.array[::-1,:], decimal=decimal, err_msg="Flipping image around x-axis failed x test") image2_x1 = flip2.shear(q1).drawImage(image=im.copy(), method='no_pixel') np.testing.assert_array_almost_equal( image_x1.array, image2_x1.array[::-1,:], decimal=decimal, err_msg="Flipping image around x-axis failed x1 test") image2_x2 = flip2.shear(s1).drawImage(image=im.copy(), method='no_pixel') np.testing.assert_array_almost_equal( image_x2.array, image2_x2.array[::-1,:], decimal=decimal, err_msg="Flipping image around x-axis failed x2 test") image2_k = flip2.drawImage(image=im.copy()) np.testing.assert_array_almost_equal( image_k.array, image2_k.array[::-1,:], decimal=decimal, err_msg="Flipping image around x-axis failed k test") image2_k1 = flip2.shear(q1).drawImage(image=im.copy()) np.testing.assert_array_almost_equal( image_k1.array, image2_k1.array[::-1,:], decimal=decimal, err_msg="Flipping image around x-axis failed k1 test") image2_k2 = flip2.shear(s1).drawImage(image=im.copy()) np.testing.assert_array_almost_equal( image_k2.array, image2_k2.array[::-1,:], decimal=decimal, err_msg="Flipping image around x-axis failed k2 test") if close_maxsb: np.testing.assert_allclose( image2_x.array.max(), flip2.max_sb*im.scale**2, rtol=0.2, err_msg="max_sb did not match maximum pixel value") np.testing.assert_allclose( image2_x1.array.max(), flip2.shear(q).max_sb*im.scale**2, rtol=0.2, err_msg="max_sb did not match maximum pixel value") np.testing.assert_allclose( image2_x2.array.max(), flip2.shear(s).max_sb*im.scale**2, rtol=0.2, err_msg="max_sb did not match maximum pixel value") # Flip around x=y (i.e. y -> x, x -> y) flip3 = prof.transform(0, 1, 1, 0) image2_x = flip3.drawImage(image=im.copy(), method='no_pixel') np.testing.assert_array_almost_equal( image_x.array, np.transpose(image2_x.array), decimal=decimal, err_msg="Flipping image around x=y failed x test") image2_x1 = flip3.shear(q2).drawImage(image=im.copy(), method='no_pixel') np.testing.assert_array_almost_equal( image_x1.array, np.transpose(image2_x1.array), decimal=decimal, err_msg="Flipping image around x=y failed x1 test") image2_x2 = flip3.shear(s2).drawImage(image=im.copy(), method='no_pixel') np.testing.assert_array_almost_equal( image_x2.array, np.transpose(image2_x2.array), decimal=decimal, err_msg="Flipping image around x=y failed x2 test") image2_k = flip3.drawImage(image=im.copy()) np.testing.assert_array_almost_equal( image_k.array, np.transpose(image2_k.array), decimal=decimal, err_msg="Flipping image around x=y failed k test") image2_k1 = flip3.shear(q2).drawImage(image=im.copy()) np.testing.assert_array_almost_equal( image_k1.array, np.transpose(image2_k1.array), decimal=decimal, err_msg="Flipping image around x=y failed k1 test") image2_k2 = flip3.shear(s2).drawImage(image=im.copy()) np.testing.assert_array_almost_equal( image_k2.array, np.transpose(image2_k2.array), decimal=decimal, err_msg="Flipping image around x=y failed k2 test") if close_maxsb: np.testing.assert_allclose( image2_x.array.max(), flip3.max_sb*im.scale**2, rtol=0.2, err_msg="max_sb did not match maximum pixel value") np.testing.assert_allclose( image2_x1.array.max(), flip3.shear(q).max_sb*im.scale**2, rtol=0.2, err_msg="max_sb did not match maximum pixel value") np.testing.assert_allclose( image2_x2.array.max(), flip3.shear(s).max_sb*im.scale**2, rtol=0.2, err_msg="max_sb did not match maximum pixel value") do_pickle(prof, lambda x: x.drawImage(image=im.copy(), method='no_pixel')) do_pickle(flip1, lambda x: x.drawImage(image=im.copy(), method='no_pixel')) do_pickle(flip2, lambda x: x.drawImage(image=im.copy(), method='no_pixel')) do_pickle(flip3, lambda x: x.drawImage(image=im.copy(), method='no_pixel')) do_pickle(prof) do_pickle(flip1) do_pickle(flip2) do_pickle(flip3)
def make_sim_obs(rng, noise, shear, show=False): """ simulate an exponential object with moffat psf the hlr of the exponential is drawn from a gaussian with mean 0.4 arcseconds and sigma 0.2 Parameters ---------- rng: np.random.RandomState The random number generator noise: float Noise for the image shear: (g1, g2) The shear in each component Returns ------- ngmix.Observation """ psf_noise = 1.0e-6 nobj = rng.poisson(NOBJ_MEAN) psf_fwhm = 0.9 psf = galsim.Moffat( beta=2.5, fwhm=psf_fwhm, ).shear( g1=0.02, g2=-0.01, ) objs0 = [] for i in range(nobj): dx, dy = rng.uniform(low=-OFFSET_MAX, high=OFFSET_MAX, size=2) gal_hlr = rng.normal(loc=0.4, scale=0.2) obj0 = galsim.Exponential( half_light_radius=gal_hlr, ).shear( g1=shear[0], g2=shear[1], ).shift( dx=dx, dy=dy, ) objs0.append(obj0) objs0 = galsim.Sum(objs0) objs = galsim.Convolve(psf, objs0) psf_im = psf.drawImage(scale=SCALE).array im = objs.drawImage(nx=DIM, ny=DIM, scale=SCALE).array psf_im += rng.normal(scale=psf_noise, size=psf_im.shape) im += rng.normal(scale=noise, size=im.shape) cen = (np.array(im.shape)-1.0)/2.0 psf_cen = (np.array(psf_im.shape)-1.0)/2.0 jacobian = ngmix.DiagonalJacobian( row=cen[0] + dy/SCALE, col=cen[1] + dx/SCALE, scale=SCALE, ) psf_jacobian = ngmix.DiagonalJacobian( row=psf_cen[0], col=psf_cen[1], scale=SCALE, ) wt = im*0 + 1.0/noise**2 psf_wt = psf_im*0 + 1.0/psf_noise**2 psf_obs = ngmix.Observation( psf_im, weight=psf_wt, jacobian=psf_jacobian, ) obs = ngmix.Observation( im, weight=wt, jacobian=jacobian, psf=psf_obs, ) if show: from espy import images images.view(im) return obs
def test_fourier_sqrt(): """Test that the FourierSqrt operator is the inverse of auto-convolution. """ dx = 0.4 myImg1 = galsim.ImageF(80, 80, scale=dx) myImg1.setCenter(0, 0) myImg2 = galsim.ImageF(80, 80, scale=dx) myImg2.setCenter(0, 0) # Test trivial case, where we could (but don't) analytically collapse the # chain of profiles by recognizing that FourierSqrt is the inverse of # AutoConvolve. psf = galsim.Moffat(beta=3.8, fwhm=1.3, flux=5) psf.drawImage(myImg1, method='no_pixel') sqrt1 = galsim.FourierSqrt(psf) psf2 = galsim.AutoConvolve(sqrt1) np.testing.assert_almost_equal(psf.stepk, psf2.stepk) psf2.drawImage(myImg2, method='no_pixel') printval(myImg1, myImg2) np.testing.assert_array_almost_equal( myImg1.array, myImg2.array, 4, err_msg="Moffat sqrt convolved with self disagrees with original") check_basic(sqrt1, "FourierSqrt", do_x=False) # Test non-trivial case where we compare (in Fourier space) sqrt(a*a + b*b + 2*a*b) against (a + b) a = galsim.Moffat(beta=3.8, fwhm=1.3, flux=5) a.shift(dx=0.5, dy=-0.3) # need nonzero centroid to test b = galsim.Moffat(beta=2.5, fwhm=1.6, flux=3) check = galsim.Sum([a, b]) sqrt = galsim.FourierSqrt( galsim.Sum([ galsim.AutoConvolve(a), galsim.AutoConvolve(b), 2 * galsim.Convolve([a, b]) ])) np.testing.assert_almost_equal(check.stepk, sqrt.stepk) check.drawImage(myImg1, method='no_pixel') sqrt.drawImage(myImg2, method='no_pixel') np.testing.assert_almost_equal(check.centroid.x, sqrt.centroid.x) np.testing.assert_almost_equal(check.centroid.y, sqrt.centroid.y) np.testing.assert_almost_equal(check.flux, sqrt.flux) np.testing.assert_almost_equal(check.xValue(check.centroid), check.max_sb) print('check.max_sb = ', check.max_sb) print('sqrt.max_sb = ', sqrt.max_sb) # This isn't super accurate... np.testing.assert_allclose(check.max_sb, sqrt.max_sb, rtol=0.1) printval(myImg1, myImg2) np.testing.assert_array_almost_equal( myImg1.array, myImg2.array, 4, err_msg="Fourier square root of expanded square disagrees with original" ) # Check picklability do_pickle(sqrt1, lambda x: x.drawImage(method='no_pixel')) do_pickle(sqrt1) # Should raise an exception for invalid arguments assert_raises(TypeError, galsim.FourierSqrt) assert_raises(TypeError, galsim.FourierSqrt, myImg1) assert_raises(TypeError, galsim.FourierSqrt, [psf]) assert_raises(TypeError, galsim.FourierSqrt, psf, psf) assert_raises(TypeError, galsim.FourierSqrt, psf, real_space=False) assert_raises(TypeError, galsim.FourierSqrtProfile) assert_raises(TypeError, galsim.FourierSqrtProfile, myImg1) assert_raises(TypeError, galsim.FourierSqrtProfile, [psf]) assert_raises(TypeError, galsim.FourierSqrtProfile, psf, psf) assert_raises(TypeError, galsim.FourierSqrtProfile, psf, real_space=False) assert_raises(NotImplementedError, sqrt1.xValue, galsim.PositionD(0, 0)) assert_raises(NotImplementedError, sqrt1.drawReal, myImg1) assert_raises(NotImplementedError, sqrt1.shoot, 1)
def make_obs( *, n_grid=6, dim=235, buff=20, scale=0.2, psf_fwhm=0.9, hlr=0.5, nse=1e-7, star_dxdy=117, star_rad=1, n_stars=5, seed=10, shear=(0.02, 0.0), mcal_shear=(0.0, 0.0) ): rng = np.random.RandomState(seed=seed) n_gals = n_grid**2 tot_dim = dim + 2*buff tot_cen = (tot_dim-1)/2 gloc = (np.arange(n_grid) + 0.5) * (dim / n_grid) - dim/2 gloc *= scale dx, dy = np.meshgrid(gloc, gloc) dx = dx.ravel() + rng.uniform(low=-0.5, high=0.5, size=n_gals) * scale dy = dy.ravel() + rng.uniform(low=-0.5, high=0.5, size=n_gals) * scale ds = np.arange(n_gals) / (n_gals-1) * 0 + 1 gals = galsim.Sum([ galsim.Exponential( half_light_radius=hlr * _ds ).shift( _dx, _dy ).shear( g1=shear[0], g2=shear[1] ).shear( g1=mcal_shear[0], g2=mcal_shear[1] ) for _ds, _dx, _dy in zip(ds, dx, dy) ]) psf = galsim.Gaussian(fwhm=psf_fwhm) objs = galsim.Convolve([gals, psf]) im = objs.drawImage(nx=tot_dim, ny=tot_dim, scale=scale).array im += rng.normal(size=im.shape, scale=nse) nim = rng.normal(size=im.shape, scale=nse) psf_dim = 53 psf_cen = (psf_dim-1)/2 psf_im = psf.drawImage(nx=psf_dim, ny=psf_dim, scale=scale).array # make bmask bmask = np.zeros_like(im, dtype=np.int32) x, y = np.meshgrid(np.arange(tot_dim), np.arange(tot_dim)) sdata = [] for _ in range(n_stars): sr2 = np.power(10.0, rng.uniform(low=star_rad, high=star_rad+0.2))**2 sx = rng.uniform(low=-star_dxdy, high=star_dxdy) + tot_cen sy = rng.uniform(low=-star_dxdy, high=star_dxdy) + tot_cen dr2 = (x - sx)**2 + (y - sy)**2 msk = dr2 < sr2 bmask[msk] |= 2**0 im[msk] = 0 sdata.append((sx, sy, np.sqrt(sr2))) psf_obs = ngmix.Observation( image=psf_im, weight=np.ones_like(psf_im) / nse**2, jacobian=ngmix.DiagonalJacobian(scale=scale, row=psf_cen, col=psf_cen) ) wgt = np.ones_like(im) / nse**2 msk = bmask != 0 wgt[msk] = 0.0 mfrac = np.zeros_like(im) mfrac[msk] = 1.0 obs = ngmix.Observation( image=im, noise=nim, weight=wgt, bmask=bmask, ormask=bmask, jacobian=ngmix.DiagonalJacobian(scale=scale, row=tot_cen, col=tot_cen), psf=psf_obs ) obs.mfrac = mfrac mbobs = ngmix.MultiBandObsList() obsl = ngmix.ObsList() obsl.append(obs) mbobs.append(obsl) mbobs.meta["sdata"] = sdata return mbobs
def test_coadd_image_correct(crazy_wcs, crazy_obj): rng = np.random.RandomState(seed=42) n_coadd = 10 psf_dim = 51 coadd_dim = 53 coadd_cen = (coadd_dim + 1) / 2 se_dim = int(np.ceil(coadd_dim * np.sqrt(2))) if se_dim % 2 == 0: se_dim += 1 se_cen = (se_dim + 1) / 2 scale = 0.2 noise_std = 0.1 world_origin = galsim.CelestialCoord(0 * galsim.degrees, 0 * galsim.degrees) aff = galsim.PixelScale(scale).affine() aff = aff.withOrigin(galsim.PositionD(coadd_cen, coadd_cen), galsim.PositionD(0, 0)) coadd_wcs = galsim.TanWCS( aff, world_origin, ) def _gen_psf_func(wcs, fwhm): def _psf_func(*args, **kargs): return galsim.Gaussian(fwhm=fwhm).drawImage( nx=101, ny=101, wcs=wcs.local(world_pos=world_origin)), galsim.PositionD(0, 0) return _psf_func wgts = [] objs = [] psf_objs = [] exps = [] for _ in range(n_coadd): if crazy_obj: _fwhm = 2.9 * (1.0 + rng.normal() * 0.1) _g1 = rng.normal() * 0.3 _g2 = rng.normal() * 0.3 obj = galsim.Gaussian(fwhm=_fwhm).shear(g1=_g1, g2=_g2) else: obj = galsim.Gaussian(fwhm=2.9).shear(g1=-0.1, g2=0.3) objs.append(obj) if crazy_wcs: shear = galsim.Shear(g1=rng.normal() * 0.01, g2=rng.normal() * 0.01) aff = galsim.ShearWCS(scale, shear).affine() aff = aff.withOrigin(galsim.PositionD(se_cen, se_cen), galsim.PositionD(0, 0)) wcs = galsim.TanWCS( aff, world_origin, ) else: aff = galsim.PixelScale(scale).affine() aff = aff.withOrigin(galsim.PositionD(se_cen, se_cen), galsim.PositionD(0, 0)) wcs = galsim.TanWCS( aff, world_origin, ) _noise = noise_std * (1 + (rng.uniform() - 0.5) * 2 * 0.05) wgts.append(1.0 / _noise**2) bmsk = galsim.ImageI(np.zeros((se_dim, se_dim))) img = obj.drawImage( nx=se_dim, ny=se_dim, wcs=wcs.local(world_pos=world_origin), ) if crazy_obj: _psf_fwhm = 1.0 * (1.0 + rng.normal() * 0.1) else: _psf_fwhm = 1.0 psf = galsim.Gaussian(fwhm=_psf_fwhm) psf_objs.append(psf) exp = make_exp( gsimage=img, bmask=bmsk, noise=_noise, galsim_wcs=wcs, galsim_psf=psf, psf_dim=psf_dim, ) exps.append(exp) coadd_bbox = geom.Box2I( geom.IntervalI(min=0, max=coadd_dim - 1), geom.IntervalI(min=0, max=coadd_dim - 1), ) coadd, exp_info = make_coadd_obs( exps=exps, coadd_wcs=make_dm_wcs(coadd_wcs), coadd_bbox=coadd_bbox, psf_dims=(psf_dim, ) * 2, rng=rng, remove_poisson=False, ) coadd_img = coadd.image coadd_psf = coadd.psf.image wgts = np.array(wgts) / np.sum(wgts) true_coadd_img = galsim.Sum([ obj.withFlux(wgt) for obj, wgt in zip(objs, wgts) ]).drawImage(nx=coadd_dim, ny=coadd_dim, wcs=coadd_wcs.local(world_pos=world_origin)).array true_coadd_psf = galsim.Sum([ obj.withFlux(wgt) for obj, wgt in zip(psf_objs, wgts) ]).drawImage(nx=psf_dim, ny=psf_dim, wcs=coadd_wcs.local(world_pos=world_origin)).array if not crazy_wcs: rtol = 0 atol = 5e-7 else: rtol = 0 atol = 5e-5 coadd_img_err = np.max(np.abs(coadd_img - true_coadd_img)) coadd_psf_err = np.max(np.abs(coadd_psf - true_coadd_psf)) print("image max abs error:", coadd_img_err) print("psf max abs error:", coadd_psf_err) if not np.allclose(coadd_img, true_coadd_img, rtol=rtol, atol=atol): _plot_cmp(coadd_img, true_coadd_img, rtol, atol, crazy_obj, crazy_wcs, "img") if not np.allclose(coadd_psf, true_coadd_psf, rtol=rtol, atol=atol): _plot_cmp(coadd_psf, true_coadd_psf, rtol, atol, crazy_obj, crazy_wcs, "psf") assert np.allclose(coadd_img, true_coadd_img, rtol=rtol, atol=atol) assert np.allclose(coadd_psf, true_coadd_psf, rtol=rtol, atol=atol) assert np.all(np.isfinite(coadd.noise))
def make_sim(seed=42): scale = 0.25 flux = 10.0**(0.4 * (30 - 18)) noise = 10 ngals = 120 shape = 361 buff = 60 inner_shape = (shape - 2*buff) im_cen = (shape-1)/2 rng = np.random.RandomState(seed=seed) us = rng.uniform(low=-inner_shape/2, high=inner_shape/2, size=ngals) * scale vs = rng.uniform(low=-inner_shape/2, high=inner_shape/2, size=ngals) * scale wcs = galsim.PixelScale(scale) psf = galsim.Gaussian(fwhm=0.8) size_fac = rng.uniform(low=1.0, high=1.5, size=ngals) g1s = rng.normal(size=ngals) * 0.2 g2s = rng.normal(size=ngals) * 0.2 flux_fac = 10**rng.uniform(low=-2, high=0, size=ngals) # PSF image psf_img = psf.drawImage(nx=33, ny=33, wcs=wcs).array psf_cen = (psf_img.shape[0]-1)/2 psf_jac = ngmix.jacobian.DiagonalJacobian( row=psf_cen, col=psf_cen, scale=scale, ) target_s2n = 500.0 target_noise = np.sqrt(np.sum(psf_img ** 2)) / target_s2n psf_obs = ngmix.Observation( psf_img, weight=np.ones_like(psf_img)/target_noise**2, jacobian=psf_jac, ) # gals gals = [] for u, v, sf, g1, g2, ff in zip(us, vs, size_fac, g1s, g2s, flux_fac): gals.append(galsim.Convolve([ galsim.Exponential(half_light_radius=0.5 * sf), psf, ]).shear(g1=g1, g2=g2).withFlux(flux*ff).shift(u, v)) gals = galsim.Sum(gals) img = gals.drawImage(nx=shape, ny=shape, wcs=wcs).array img += rng.normal(size=img.shape) * noise nse = rng.normal(size=img.shape) * noise wgt = img*0 + 1.0/noise**2 msk = np.zeros(img.shape, dtype='i4') im_jac = ngmix.jacobian.DiagonalJacobian( row=im_cen, col=im_cen, scale=scale, ) obs = ngmix.Observation( img, weight=wgt, bmask=msk, ormask=msk.copy(), jacobian=im_jac, psf=psf_obs, noise=nse, ) mbobs = ngmix.MultiBandObsList() obslist = ngmix.ObsList() obslist.append(obs) mbobs.append(obslist) return mbobs
def test_coadd_psfs(crazy_wcs, crazy_psf): n_coadd = 10 rng = np.random.RandomState(seed=42) if crazy_psf: psfs = [] for _ in range(n_coadd): _fwhm = 0.9 * (1.0 + rng.normal() * 0.1) _g1 = rng.normal() * 0.3 _g2 = rng.normal() * 0.3 psfs.append(galsim.Gaussian(fwhm=_fwhm).shear(g1=_g1, g2=_g2)) else: psfs = [] for _ in range(n_coadd): psfs.append(galsim.Gaussian(fwhm=0.9).shear(g1=-0.1, g2=0.3)) coadd_dim = 225 coadd_cen = (coadd_dim - 1)/2 se_dim = int(np.ceil(coadd_dim * np.sqrt(2))) if se_dim % 2 == 0: se_dim += 1 se_cen = (se_dim - 1)/2 scale = 0.27 psf_dim = 33 psf_dim_half = (psf_dim - 1)/2 se_psf_dim = int(np.ceil(psf_dim * np.sqrt(2))) if se_psf_dim % 2 == 0: se_psf_dim += 1 se_psf_dim_half = (se_psf_dim - 1)/2 coadd_offset = coadd_cen - psf_dim_half world_origin = galsim.PositionD( x=coadd_cen*scale, y=coadd_cen*scale) origin = galsim.PositionD(x=se_cen, y=se_cen) coadd_wgts = rng.uniform(size=n_coadd) coadd_wgts /= np.sum(coadd_wgts) se_wcs_objs = [] for _ in range(n_coadd): if crazy_wcs: wcs = gen_affine_wcs( rng=rng, position_angle_range=(0, 360), dither_range=(5, 5), scale=scale, scale_frac_std=0.05, shear_std=0.1, world_origin=world_origin, origin=origin) else: wcs = gen_affine_wcs( rng=rng, position_angle_range=(0, 0), dither_range=(0, 0), scale=scale, scale_frac_std=0.0, shear_std=0.0, world_origin=world_origin, origin=origin) se_wcs_objs.append(wcs) se_psfs = [] se_offsets = [] for wcs, psf in zip(se_wcs_objs, psfs): pos = wcs.toImage(world_origin) xp = int(pos.x + 0.5) yp = int(pos.y + 0.5) dx = pos.x - xp dy = pos.y - yp se_offsets.append((xp - se_psf_dim_half, yp - se_psf_dim_half)) se_psfs.append(psf.drawImage( nx=se_psf_dim, ny=se_psf_dim, wcs=wcs.local(world_pos=world_origin), offset=galsim.PositionD(x=dx, y=dy)).array) coadd_psf = coadd_psfs( se_psfs, se_wcs_objs, coadd_wgts, scale, psf_dim, coadd_offset, se_offsets) true_coadd_psf = galsim.Sum( [psf.withFlux(wgt) for psf, wgt in zip(psfs, coadd_wgts)] ).drawImage( nx=psf_dim, ny=psf_dim, scale=scale).array true_coadd_psf /= np.sum(true_coadd_psf) if not crazy_psf and not crazy_wcs: rtol = 0 atol = 1e-7 else: rtol = 0 atol = 8e-4 if not np.allclose(coadd_psf, true_coadd_psf, rtol=rtol, atol=atol): import matplotlib.pyplot as plt import seaborn as sns fig, axs = plt.subplots(nrows=2, ncols=2) sns.heatmap(true_coadd_psf, ax=axs[0, 0]) sns.heatmap(coadd_psf, ax=axs[0, 1]) sns.heatmap(coadd_psf - true_coadd_psf, ax=axs[1, 0]) sns.heatmap( np.abs(coadd_psf - true_coadd_psf) < atol + rtol * np.abs(true_coadd_psf), ax=axs[1, 1]) print(np.max(np.abs(coadd_psf - true_coadd_psf))) assert np.allclose(coadd_psf, true_coadd_psf, rtol=rtol, atol=atol)
def test_coadd_psfs(crazy_wcs, crazy_psf): n_coadd = 10 rng = np.random.RandomState(seed=42) if crazy_psf: psfs = [] for _ in range(n_coadd): _fwhm = 2.9 * (1.0 + rng.normal() * 0.1) _g1 = rng.normal() * 0.3 _g2 = rng.normal() * 0.3 psfs.append(galsim.Gaussian(fwhm=_fwhm).shear(g1=_g1, g2=_g2)) else: psfs = [] for _ in range(n_coadd): psfs.append(galsim.Gaussian(fwhm=2.9).shear(g1=-0.1, g2=0.3)) scale = 0.213 coadd_psf_dim = 103 coadd_psf_cen = (coadd_psf_dim - 1)/2 se_psf_dim = 103 se_psf_cen = (se_psf_dim - 1)/2 coadd_wgts = rng.uniform(size=n_coadd) coadd_wgts /= np.sum(coadd_wgts) world_origin = galsim.PositionD( x=coadd_psf_cen * scale, y=coadd_psf_cen * scale) origin = galsim.PositionD(x=se_psf_cen, y=se_psf_cen) se_wcs_objs = [] for _ in range(n_coadd): if crazy_wcs: wcs = gen_affine_wcs( rng=rng, position_angle_range=(0, 360), dither_range=(5, 5), scale=scale, scale_frac_std=0.05, shear_std=0.1, world_origin=world_origin, origin=origin) else: wcs = gen_affine_wcs( rng=rng, position_angle_range=(0, 0), dither_range=(0, 0), scale=scale, scale_frac_std=0.0, shear_std=0.0, world_origin=world_origin, origin=origin) se_wcs_objs.append(wcs) se_psfs = [] for wcs, psf in zip(se_wcs_objs, psfs): # we need to offset the PSF images to match the image origin in the # stamp offset = np.array([ wcs.x0 - se_psf_cen, wcs.y0 - se_psf_cen]) se_psfs.append(psf.drawImage( nx=se_psf_dim, ny=se_psf_dim, wcs=wcs.local(world_pos=world_origin), offset=offset).array) coadd_psf = coadd_psfs( se_psfs, se_wcs_objs, coadd_wgts, scale, coadd_psf_dim) true_coadd_psf = galsim.Sum( [psf.withFlux(wgt) for psf, wgt in zip(psfs, coadd_wgts)] ).drawImage( nx=coadd_psf_dim, ny=coadd_psf_dim, scale=scale).array true_coadd_psf /= np.sum(true_coadd_psf) if not crazy_wcs: rtol = 0 atol = 5e-8 else: rtol = 0 atol = 5e-5 if not np.allclose(coadd_psf, true_coadd_psf, rtol=rtol, atol=atol): import matplotlib.pyplot as plt import seaborn as sns fig, axs = plt.subplots(nrows=2, ncols=2) sns.heatmap(true_coadd_psf, ax=axs[0, 0]) sns.heatmap(coadd_psf, ax=axs[0, 1]) sns.heatmap(coadd_psf - true_coadd_psf, ax=axs[1, 0]) sns.heatmap( np.abs(coadd_psf - true_coadd_psf) < atol + rtol * np.abs(true_coadd_psf), ax=axs[1, 1]) print(np.max(np.abs(coadd_psf - true_coadd_psf))) assert np.allclose(coadd_psf, true_coadd_psf, rtol=rtol, atol=atol)
def test_coadd_image_noise_interpfrac(crazy_wcs, crazy_obj): n_coadd = 10 rng = np.random.RandomState(seed=42) if crazy_obj: objs = [] for _ in range(n_coadd): _fwhm = 2.9 * (1.0 + rng.normal() * 0.1) _g1 = rng.normal() * 0.3 _g2 = rng.normal() * 0.3 objs.append(galsim.Gaussian(fwhm=_fwhm).shear(g1=_g1, g2=_g2)) else: objs = [] for _ in range(n_coadd): objs.append(galsim.Gaussian(fwhm=2.9).shear(g1=-0.1, g2=0.3)) coadd_dim = 53 coadd_cen = (coadd_dim - 1)/2 se_dim = int(np.ceil(coadd_dim * np.sqrt(2))) if se_dim % 2 == 0: se_dim += 1 se_cen = (se_dim - 1)/2 scale = 0.2 world_origin = galsim.PositionD( x=coadd_cen*scale, y=coadd_cen*scale) origin = galsim.PositionD(x=se_cen, y=se_cen) coadd_wgts = rng.uniform(size=n_coadd) coadd_wgts /= np.sum(coadd_wgts) se_wcs_objs = [] for _ in range(n_coadd): if crazy_wcs: wcs = gen_affine_wcs( rng=rng, position_angle_range=(0, 360), dither_range=(-5, 5), scale=scale, scale_frac_std=0.05, shear_std=0.1, world_origin=world_origin, origin=origin) else: wcs = gen_affine_wcs( rng=rng, position_angle_range=(0, 0), dither_range=(0, 0), scale=scale, scale_frac_std=0.0, shear_std=0.0, world_origin=world_origin, origin=origin) se_wcs_objs.append(wcs) se_images = [] se_noises = [] se_interp_fracs = [] for wcs, obj in zip(se_wcs_objs, objs): pos = wcs.toImage(world_origin) dx = pos.x - se_cen dy = pos.y - se_cen se_images.append(obj.drawImage( nx=se_dim, ny=se_dim, wcs=wcs.local(world_pos=world_origin), offset=galsim.PositionD(x=dx, y=dy)).array) se_noises.append(rng.normal(size=(se_dim, se_dim))) se_interp_fracs.append(rng.uniform(size=(se_dim, se_dim))) coadd_img, coadd_nse, coadd_intp = coadd_image_noise_interpfrac( se_images, se_noises, se_interp_fracs, se_wcs_objs, coadd_wgts, scale, coadd_dim) true_coadd_img = galsim.Sum( [obj.withFlux(wgt) for obj, wgt in zip(objs, coadd_wgts)] ).drawImage( nx=coadd_dim, ny=coadd_dim, scale=scale).array if not crazy_wcs: rtol = 0 atol = 5e-7 else: rtol = 0 atol = 5e-5 if not np.allclose(coadd_img, true_coadd_img, rtol=rtol, atol=atol): import matplotlib.pyplot as plt import seaborn as sns fig, axs = plt.subplots(nrows=2, ncols=2) sns.heatmap(true_coadd_img, ax=axs[0, 0]) sns.heatmap(coadd_img, ax=axs[0, 1]) sns.heatmap(coadd_img - true_coadd_img, ax=axs[1, 0]) sns.heatmap( np.abs(coadd_img - true_coadd_img) < atol + rtol * np.abs(true_coadd_img), ax=axs[1, 1]) print(np.max(np.abs(coadd_img - true_coadd_img))) assert np.allclose(coadd_img, true_coadd_img, rtol=rtol, atol=atol) assert np.all(np.isfinite(coadd_nse)) assert np.all(np.isfinite(coadd_intp)) assert np.all((coadd_intp >= 0) & (coadd_intp <= 1))
def _draw_objects(self): """ this is dumb, drawing into the full image when we don't need to """ self.imlist = [] shear = self.get('shear', None) cdisk = self['pdfs']['disk'] cbulge = self['pdfs'].get('bulge', None) cknots = self['pdfs'].get('knots', None) dims = self['dims'] cen = (np.array(dims) - 1.0) / 2.0 for band in range(self['nband']): objects = [] for iobj, obj_parts in enumerate(self.objlist): disk = obj_parts['disk'] * cdisk['color'][band] tparts = [disk] if cbulge is not None: bulge = obj_parts['bulge'] * cbulge['color'][band] tparts.append(bulge) if cknots is not None: knots = obj_parts['knots'] * cknots['color'][band] tparts.append(knots) if len(tparts) == 1: obj = tparts[0] else: obj = galsim.Sum(tparts) obj = obj.shift( dx=obj_parts['cen'][1], dy=obj_parts['cen'][0], ) if shear is not None and not self['shear_all']: obj = obj.shear( g1=shear[0], g2=shear[1], ) if band == 0: ocen = obj.centroid row = cen[0] + ocen.y / self['pixel_scale'] col = cen[1] + ocen.x / self['pixel_scale'] self._obj_data['y'][iobj] = row self._obj_data['x'][iobj] = col objects.append(obj) objects = galsim.Sum(objects) if shear is not None and self['shear_all']: objects = objects.shear( g1=shear[0], g2=shear[1], ) convolved_objects = galsim.Convolve(objects, self.psf) kw = {'scale': self['pixel_scale']} kw['method'] = self['draw_method'] dims = self.get('dims', None) if dims is not None: kw['nx'], kw['ny'] = dims[1], dims[0] image = convolved_objects.drawImage(**kw).array self.imlist.append(image)
def test(ntrial=1, dim=2000, show=False): import galsim import biggles import images rng = np.random.RandomState() nobj_per = 4 nknots = 100 knot_flux_frac = 0.001 nknots_low, nknots_high = 1, 100 nband = 3 noises = [0.0005, 0.001, 0.0015] scale = 0.263 psf = galsim.Gaussian(fwhm=0.9) dims = 64, 64 flux_low, flux_high = 0.5, 1.5 r50_low, r50_high = 0.1, 2.0 fracdev_low, fracdev_high = 0.001, 0.99 bulge_colors = np.array([0.5, 1.0, 1.5]) disk_colors = np.array([1.25, 1.0, 0.75]) knots_colors = np.array([1.5, 1.0, 0.5]) sigma = dims[0]/2.0/4.0*scale maxrad = dims[0]/2.0/2.0 * scale tm0 = time.time() nobj_meas = 0 for trial in range(ntrial): print("trial: %d/%d" % (trial+1, ntrial)) all_band_obj = [] for i in range(nobj_per): nknots = int(rng.uniform(low=nknots_low, high=nknots_high)) r50 = rng.uniform(low=r50_low, high=r50_high) flux = rng.uniform(low=flux_low, high=flux_high) dx, dy = rng.normal(scale=sigma, size=2).clip( min=-maxrad, max=maxrad, ) g1d, g2d = rng.normal(scale=0.2, size=2).clip(max=0.5) g1b = 0.5*g1d+rng.normal(scale=0.02) g2b = 0.5*g2d+rng.normal(scale=0.02) fracdev = rng.uniform(low=fracdev_low, high=fracdev_high) flux_bulge = fracdev*flux flux_disk = (1-fracdev)*flux flux_knots = nknots*knot_flux_frac*flux_disk print("fracdev:", fracdev, "nknots:", nknots) bulge_obj = galsim.DeVaucouleurs( half_light_radius=r50 ).shear(g1=g1b, g2=g2b) disk_obj = galsim.Exponential( half_light_radius=r50 ).shear(g1=g1d, g2=g2d) knots_obj = galsim.RandomWalk( npoints=nknots, profile=disk_obj, ) # .shear(g1=g1d, g2=g2d) band_objs = [] for band in range(nband): band_disk = disk_obj.withFlux(flux_disk*disk_colors[band]) band_bulge = bulge_obj.withFlux(flux_bulge*bulge_colors[band]) band_knots = knots_obj.withFlux(flux_knots*knots_colors[band]) obj = galsim.Sum(band_disk, band_bulge, band_knots).shift( dx=dx, dy=dy, ) obj = galsim.Convolve(obj, psf) band_objs.append(obj) all_band_obj.append(band_objs) jacob = ngmix.DiagonalJacobian( row=0, col=0, scale=scale, ) wcs = jacob.get_galsim_wcs() psfim = psf.drawImage(wcs=wcs).array psf_obs = get_psf_obs(psfim, jacob) dlist = [] for band in range(nband): band_objects = [o[band] for o in all_band_obj] obj = galsim.Sum(band_objects) im = obj.drawImage(nx=dims[1], ny=dims[0], wcs=wcs).array im = obj.drawImage(nx=dims[1], ny=dims[0], scale=scale).array im += rng.normal(scale=noises[band], size=im.shape) wt = im*0 + 1.0/noises[band]**2 dlist.append( dict( image=im, weight=wt, wcs=wcs, ) ) mer = MEDSifier(dlist) mg = mer.get_meds(0) mr = mer.get_meds(1) mi = mer.get_meds(2) nobj = mg.size print(" found", nobj, "objects") nobj_meas += nobj list_of_obs = [] for i in range(nobj): gobslist = mg.get_obslist(i, weight_type='uberseg') robslist = mr.get_obslist(i, weight_type='uberseg') iobslist = mi.get_obslist(i, weight_type='uberseg') mbo = ngmix.MultiBandObsList() mbo.append(gobslist) mbo.append(robslist) mbo.append(iobslist) list_of_obs.append(mbo) for mbo in list_of_obs: for obslist in mbo: for obs in obslist: obs.set_psf(psf_obs) prior = moflib.get_mof_prior(list_of_obs, "bdf", rng) mof_fitter = moflib.MOFStamps( list_of_obs, "bdf", prior=prior, ) band = 2 guess = moflib.get_stamp_guesses(list_of_obs, band, "bdf", rng) mof_fitter.go(guess) if show: # corrected images tab = biggles.Table(1, 2) rgb = images.get_color_image( dlist[2]['image'].transpose(), dlist[1]['image'].transpose(), dlist[0]['image'].transpose(), nonlinear=0.1, ) rgb *= 1.0/rgb.max() tab[0, 0] = images.view_mosaic( [rgb, mer.seg, mer.detim], titles=['image', 'seg', 'detim'], show=False, # dims=[dim, dim], ) imlist = [] for iobj, mobs in enumerate(list_of_obs): cmobs = mof_fitter.make_corrected_obs(iobj) gim = images.make_combined_mosaic( [mobs[0][0].image, cmobs[0][0].image], ) rim = images.make_combined_mosaic( [mobs[1][0].image, cmobs[1][0].image], ) iim = images.make_combined_mosaic( [mobs[2][0].image, cmobs[2][0].image], ) rgb = images.get_color_image( iim.transpose(), rim.transpose(), gim.transpose(), nonlinear=0.1, ) rgb *= 1.0/rgb.max() imlist.append(rgb) plt = images.view_mosaic(imlist, show=False) tab[0, 1] = plt tab.show(width=dim*2, height=dim) if ntrial > 1: if 'q' == input("hit a key: "): return total_time = time.time()-tm0 print("time per group:", total_time/ntrial) print("time per object:", total_time/nobj_meas)