Example #1
0
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
Example #2
0
    def addNoise(self, config, base, im, rng, current_var, draw_method,
                 logger):

        # Build the correlated noise
        cn = self.getCOSMOSNoise(config, base, rng)
        var = cn.getVariance()

        # Subtract off the current variance if any
        if current_var:
            logger.debug(
                'image %d, obj %d: Target variance is %f, current variance is %f',
                base.get('image_num', 0), base.get('obj_num', 0), var,
                current_var)
            if var < current_var:
                raise galsim.GalSimConfigError(
                    "Whitening already added more noise than the requested COSMOS noise."
                )
            cn -= galsim.UncorrelatedNoise(current_var, rng=rng, wcs=cn.wcs)

        # Add the noise to the image
        im.addNoise(cn)

        logger.debug(
            'image %d, obj %d: Added COSMOS correlated noise with variance = %f',
            base.get('image_num', 0), base.get('obj_num', 0), var)
        return var
Example #3
0
    def getNoise(self, i, rng=None, gsparams=None):
        """Returns the noise cf at index `i` as a CorrelatedNoise object.
        """
        if self.noise_file_name is None:
            cf = galsim.UncorrelatedNoise(rng, self.pixel_scale[i], self.variance[i], gsparams)

        else:

            if i >= len(self.noise_file_name):
                raise IndexError(
                    'index %d given to getNoise is out of range (0..%d)'%(
                        i,len(self.noise_file_name)-1))

            if self.noise_file_name[i] in self.saved_noise_im:
                im = self.saved_noise_im[self.noise_file_name[i]]
            else:
                import pyfits
                import os
                import numpy

                file_name = os.path.join(self.noise_dir,self.noise_file_name[i])
                array = pyfits.getdata(file_name)
                im = galsim.ImageViewD(numpy.ascontiguousarray(array.astype(numpy.float64)))
                self.saved_noise_im[self.noise_file_name[i]] = im

            cf = galsim.correlatednoise._BaseCorrelatedNoise(
                rng, galsim.InterpolatedImage(im, dx=self.pixel_scale[i], normalization="sb",
                                                calculate_stepk=False, calculate_maxk=False,
                                                x_interpolant='linear', gsparams=gsparams))
            cf.setVariance(self.variance[i])

        return cf
Example #4
0
 def getNoise(self, i, rng=None, gsparams=None):
     """Returns the noise correlation function at index `i` as a CorrelatedNoise object.
        Note: the return value from this function is not picklable, so this cannot be used
        across processes.
     """
     im, scale, var = self.getNoiseProperties(i)
     if im is None:
         cf = galsim.UncorrelatedNoise(var, rng=rng, scale=scale, gsparams=gsparams)
     else:
         ii = galsim.InterpolatedImage(im, normalization="sb",
                                       calculate_stepk=False, calculate_maxk=False,
                                       x_interpolant='linear', gsparams=gsparams)
         cf = galsim.correlatednoise._BaseCorrelatedNoise(rng, ii, im.wcs)
         cf = cf.withVariance(var)
     return cf
Example #5
0
def AddNoiseCOSMOS(noise, config, draw_method, rng, im, weight_im, current_var,
                   sky, logger):
    # NB: Identical for fft and phot

    req = {'file_name': str}
    opt = {'cosmos_scale': float, 'variance': float}

    kwargs = galsim.config.GetAllParams(noise,
                                        'noise',
                                        config,
                                        req=req,
                                        opt=opt,
                                        ignore=noise_ignore)[0]

    # Build the correlated noise
    cn = galsim.correlatednoise.getCOSMOSNoise(rng, **kwargs)
    var = cn.getVariance()

    # If we are saving the noise level in a weight image, do that now.
    if weight_im:
        weight_im += var

    # Subtract off the current variance if any
    if current_var:
        if var < current_var:
            raise RuntimeError(
                "Whitening already added more noise than requested COSMOS noise."
            )
        cn -= galsim.UncorrelatedNoise(rng, im.wcs, current_var)

    # Add the noise to the image
    im.addNoise(cn)

    if logger:
        logger.debug(
            'image %d, obj %d: Added COSMOS correlated noise with variance = %f',
            config['image_num'], config['obj_num'], var)
Example #6
0
def test_convolve_noise():
    """Test that noise propagation works properly for compount 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)

    # Convolve convolves the noise from a single component
    conv2 = galsim.Convolution([obj1, obj3])
    noise = galsim.Convolve([obj1.noise._profile, obj3, obj3])
    # xValue is too slow here.  Use drawImage to get variance.  (Just as CorrelatedNoise does.)
    variance = noise.drawImage(nx=1, ny=1, scale=1., method='sb')(1, 1)
    np.testing.assert_almost_equal(
        conv2.noise.getVariance(),
        variance,
        err_msg=
        "Convolution of two objects did not correctly propagate noise varinace"
    )
    conv2 = galsim.Convolution([obj2, obj3])
    noise = galsim.Convolve([obj2.noise._profile, obj3, obj3])
    variance = noise.drawImage(nx=1, ny=1, scale=1., method='sb')(1, 1)
    np.testing.assert_almost_equal(
        conv2.noise.getVariance(),
        variance,
        err_msg=
        "Convolution of two objects did not correctly propagate noise varinace"
    )

    # Convolution of multiple objects with noise attributes raises a warning and fails
    # to propagate noise properly.  (It takes the input noise from the first one.)
    conv2 = galsim.Convolution(obj1, obj2)
    conv3 = galsim.Convolution(obj1, obj2, obj3)
    with assert_warns(galsim.GalSimWarning):
        assert conv2.noise == obj1.noise.convolvedWith(obj2)
    with assert_warns(galsim.GalSimWarning):
        assert conv3.noise == obj1.noise.convolvedWith(
            galsim.Convolve(obj2, obj3))

    # Convolution with only one object uses that object's noise
    conv1 = galsim.Convolution(obj1)
    assert conv1.noise == obj1.noise

    # Other types don't propagate noise and give a warning about it.
    deconv = galsim.Deconvolution(obj2)
    autoconv = galsim.AutoConvolution(obj2)
    autocorr = galsim.AutoCorrelation(obj2)
    four = galsim.FourierSqrt(obj2)
    with assert_warns(galsim.GalSimWarning):
        assert deconv.noise is None
    with assert_warns(galsim.GalSimWarning):
        assert autoconv.noise is None
    with assert_warns(galsim.GalSimWarning):
        assert autocorr.noise is None
    with assert_warns(galsim.GalSimWarning):
        assert four.noise is None

    obj2.noise = None  # Remove obj2 noise for the rest.
    conv2 = galsim.Convolution(obj1, obj2)
    noise = galsim.Convolve([obj1.noise._profile, obj2, obj2])
    variance = noise.drawImage(nx=1, ny=1, scale=1., method='sb')(1, 1)
    np.testing.assert_almost_equal(
        conv2.noise.getVariance(),
        variance,
        err_msg=
        "Convolution of two objects did not correctly propagate noise varinace"
    )

    conv3 = galsim.Convolution(obj1, obj2, obj3)
    noise = galsim.Convolve([obj1.noise._profile, obj2, obj2, obj3, obj3])
    variance = noise.drawImage(nx=1, ny=1, scale=1., method='sb')(1, 1)
    np.testing.assert_almost_equal(
        conv3.noise.getVariance(),
        variance,
        err_msg=
        "Convolution of three objects did not correctly propagate noise varinace"
    )

    deconv = galsim.Deconvolution(obj2)
    autoconv = galsim.AutoConvolution(obj2)
    autocorr = galsim.AutoCorrelation(obj2)
    four = galsim.FourierSqrt(obj2)
    assert deconv.noise is None
    assert autoconv.noise is None
    assert autocorr.noise is None
    assert four.noise is None
Example #7
0
def test_crg_roundtrip_larger_target_psf():
    """Test that drawing a chromatic galaxy with a color gradient directly using an LSST-size PSF
    is equivalent to first drawing the galaxy to HST-like images, and then using ChromaticRealGalaxy
    to produce an LSST-like image.
    """
    # load some spectra
    bulge_SED = (galsim.SED(
        os.path.join(sedpath, 'CWW_E_ext.sed'),
        wave_type='ang',
        flux_type='flambda').thin(rel_err=1e-3).withFluxDensity(
            target_flux_density=0.3, wavelength=500.0))

    disk_SED = (galsim.SED(
        os.path.join(sedpath, 'CWW_Sbc_ext.sed'),
        wave_type='ang',
        flux_type='flambda').thin(rel_err=1e-3).withFluxDensity(
            target_flux_density=0.3, wavelength=500.0))

    bulge = galsim.Sersic(n=4, half_light_radius=0.6) * bulge_SED
    disk = galsim.Sersic(n=1, half_light_radius=0.4) * disk_SED
    # Decenter components a bit to make the test more complicated
    disk = disk.shift(0.05, 0.1)
    gal = (bulge + disk).shear(g1=0.3, g2=0.1)

    # Much faster to just use some achromatic HST-like PSFs.  We'll make them slightly different in
    # each band though.
    f606w_PSF = galsim.ChromaticObject(galsim.Gaussian(half_light_radius=0.05))
    f814w_PSF = galsim.ChromaticObject(galsim.Gaussian(half_light_radius=0.07))
    LSSTPSF = galsim.ChromaticAtmosphere(galsim.Kolmogorov(fwhm=0.7),
                                         600.0,
                                         zenith_angle=0.0 * galsim.degrees)

    f606w = galsim.Bandpass(os.path.join(bppath, "ACS_wfc_F606W.dat"),
                            'nm').truncate()
    f814w = galsim.Bandpass(os.path.join(bppath, "ACS_wfc_F814W.dat"), 'nm')
    LSST_i = galsim.Bandpass(os.path.join(bppath, "LSST_r.dat"), 'nm')

    truth_image = galsim.Convolve(LSSTPSF, gal).drawImage(LSST_i,
                                                          nx=24,
                                                          ny=24,
                                                          scale=0.2)
    f606w_image = galsim.Convolve(f606w_PSF, gal).drawImage(f606w,
                                                            nx=192,
                                                            ny=192,
                                                            scale=0.03)
    f814w_image = galsim.Convolve(f814w_PSF, gal).drawImage(f814w,
                                                            nx=192,
                                                            ny=192,
                                                            scale=0.03)

    crg = galsim.ChromaticRealGalaxy.makeFromImages(
        images=[f606w_image, f814w_image],
        bands=[f606w, f814w],
        PSFs=[f606w_PSF, f814w_PSF],
        xis=[galsim.UncorrelatedNoise(1e-16)] * 2,
        SEDs=[bulge_SED, disk_SED])

    test_image = galsim.Convolve(crg, LSSTPSF).drawImage(LSST_i,
                                                         nx=24,
                                                         ny=24,
                                                         scale=0.2)

    truth_mom = galsim.hsm.FindAdaptiveMom(truth_image)
    test_mom = galsim.hsm.FindAdaptiveMom(test_image)

    np.testing.assert_allclose(test_mom.moments_amp,
                               truth_mom.moments_amp,
                               rtol=1e-3,
                               atol=0)
    np.testing.assert_allclose(test_mom.moments_centroid.x,
                               truth_mom.moments_centroid.x,
                               rtol=0.,
                               atol=1e-2)
    np.testing.assert_allclose(test_mom.moments_centroid.y,
                               truth_mom.moments_centroid.y,
                               rtol=0.,
                               atol=1e-2)
    np.testing.assert_allclose(test_mom.moments_sigma,
                               truth_mom.moments_sigma,
                               rtol=1e-3,
                               atol=0)
    np.testing.assert_allclose(test_mom.observed_shape.g1,
                               truth_mom.observed_shape.g1,
                               rtol=0,
                               atol=1e-4)
    np.testing.assert_allclose(test_mom.observed_shape.g2,
                               truth_mom.observed_shape.g2,
                               rtol=0,
                               atol=1e-4)

    # Invalid arguments
    with assert_raises(ValueError):
        crg = galsim.ChromaticRealGalaxy.makeFromImages(
            images=[f606w_image],
            bands=[f606w, f814w],
            PSFs=[f606w_PSF, f814w_PSF],
            xis=[galsim.UncorrelatedNoise(1e-16)] * 2,
            SEDs=[bulge_SED, disk_SED])
    with assert_raises(ValueError):
        crg = galsim.ChromaticRealGalaxy.makeFromImages(
            images=[f606w_image, f814w_image],
            bands=[f606w],
            PSFs=[f606w_PSF, f814w_PSF],
            xis=[galsim.UncorrelatedNoise(1e-16)] * 2,
            SEDs=[bulge_SED, disk_SED])
    with assert_raises(ValueError):
        crg = galsim.ChromaticRealGalaxy.makeFromImages(
            images=[f606w_image, f814w_image],
            bands=[f606w, f814w],
            PSFs=[f606w_PSF],
            xis=[galsim.UncorrelatedNoise(1e-16)] * 2,
            SEDs=[bulge_SED, disk_SED])
    with assert_raises(ValueError):
        crg = galsim.ChromaticRealGalaxy.makeFromImages(
            images=[f606w_image, f814w_image],
            bands=[f606w, f814w],
            PSFs=[f606w_PSF, f814w_PSF],
            xis=[galsim.UncorrelatedNoise(1e-16)],
            SEDs=[bulge_SED, disk_SED])
    with assert_raises(ValueError):
        crg = galsim.ChromaticRealGalaxy.makeFromImages(
            images=[f606w_image, f814w_image],
            bands=[f606w, f814w],
            PSFs=[f606w_PSF, f814w_PSF],
            xis=[galsim.UncorrelatedNoise(1e-16)] * 2,
            SEDs=[bulge_SED, disk_SED, disk_SED])
Example #8
0
def test_whiten():
    """Test the options in config to whiten images
    """
    real_gal_dir = os.path.join('..','examples','data')
    real_gal_cat = 'real_galaxy_catalog_23.5_example.fits'
    config = {
        'image' : {
            'type' : 'Single',
            'random_seed' : 1234,
            'pixel_scale' : 0.05,
        },
        'stamp' : {
            'type' : 'Basic',
            'size' : 32,
        },
        'gal' : {
            'type' : 'RealGalaxy',
            'index' : 79,
            'flux' : 100,
        },
        'psf' : {  # This is really slow if we don't convolve by a PSF.
            'type' : 'Gaussian',
            'sigma' : 0.05
        },
        'input' : {
            'real_catalog' : {
                'dir' : real_gal_dir ,
                'file_name' : real_gal_cat
            }
        }
    }

    # First build by hand (no whitening yet)
    rng = galsim.BaseDeviate(1234 + 1)
    rgc = galsim.RealGalaxyCatalog(os.path.join(real_gal_dir, real_gal_cat))
    gal = galsim.RealGalaxy(rgc, index=79, flux=100, rng=rng)
    psf = galsim.Gaussian(sigma=0.05)
    final = galsim.Convolve(gal,psf)
    im1a = final.drawImage(nx=32, ny=32, scale=0.05)

    # Compare to what config builds
    galsim.config.ProcessInput(config)
    im1b, cv1b = galsim.config.BuildStamp(config, do_noise=False)
    np.testing.assert_equal(cv1b, 0.)
    np.testing.assert_equal(im1b.array, im1a.array)

    # Now add whitening, but no noise yet.
    cv1a = final.noise.whitenImage(im1a)
    print('From whiten, current_var = ',cv1a)
    galsim.config.RemoveCurrent(config)
    config['image']['noise'] =  { 'whiten' : True, }
    im1c, cv1c = galsim.config.BuildStamp(config, do_noise=False)
    print('From BuildStamp, current_var = ',cv1c)
    np.testing.assert_equal(cv1c, cv1a)
    np.testing.assert_equal(im1c.array, im1a.array)
    rng1 = rng.duplicate()  # Save current state of rng

    # 1. Gaussian noise
    #####
    config['image']['noise'] =  {
        'type' : 'Gaussian',
        'variance' : 50,
        'whiten' : True,
    }
    galsim.config.RemoveCurrent(config)
    im2a = im1a.copy()
    im2a.addNoise(galsim.GaussianNoise(sigma=math.sqrt(50-cv1a), rng=rng))
    im2b, cv2b = galsim.config.BuildStamp(config)
    np.testing.assert_almost_equal(cv2b, 50)
    np.testing.assert_almost_equal(im2b.array, im2a.array, decimal=5)

    # If whitening already added too much noise, raise an exception
    config['image']['noise']['variance'] = 1.e-5
    try:
        np.testing.assert_raises(RuntimeError, galsim.config.BuildStamp,config)
    except ImportError:
        pass

    # 2. Poisson noise
    #####
    config['image']['noise'] =  {
        'type' : 'Poisson',
        'sky_level_pixel' : 50,
        'whiten' : True,
    }
    galsim.config.RemoveCurrent(config)
    im3a = im1a.copy()
    sky = 50 - cv1a
    rng.reset(rng1.duplicate())
    im3a.addNoise(galsim.PoissonNoise(sky_level=sky, rng=rng))
    im3b, cv3b = galsim.config.BuildStamp(config)
    np.testing.assert_almost_equal(cv3b, 50, decimal=5)
    np.testing.assert_almost_equal(im3b.array, im3a.array, decimal=5)

    # It's more complicated if the sky is quoted per arcsec and the wcs is not uniform.
    config2 = galsim.config.CopyConfig(config)
    galsim.config.RemoveCurrent(config2)
    config2['image']['sky_level'] = 100
    config2['image']['wcs'] =  {
        'type' : 'UVFunction',
        'ufunc' : '0.05*x + 0.001*x**2',
        'vfunc' : '0.05*y + 0.001*y**2',
    }
    del config2['image']['pixel_scale']
    del config2['wcs']
    config2['image']['noise']['symmetrize'] = 4 # Also switch to symmetrize, just to mix it up.
    del config2['image']['noise']['whiten']
    rng.reset(1234+1) # Start fresh, since redoing the whitening/symmetrizing
    wcs = galsim.UVFunction(ufunc='0.05*x + 0.001*x**2', vfunc='0.05*y + 0.001*y**2')
    im3c = galsim.Image(32,32, wcs=wcs)
    im3c = final.drawImage(im3c)
    cv3c = final.noise.symmetrizeImage(im3c,4)
    sky = galsim.Image(im3c.bounds, wcs=wcs)
    wcs.makeSkyImage(sky, 100)
    mean_sky = np.mean(sky.array)
    im3c += sky
    extra_sky = 50 - cv3c
    im3c.addNoise(galsim.PoissonNoise(sky_level=extra_sky, rng=rng))
    im3d, cv3d = galsim.config.BuildStamp(config2)
    np.testing.assert_almost_equal(cv3d, 50 + mean_sky, decimal=4)
    np.testing.assert_almost_equal(im3d.array, im3c.array, decimal=5)

    config['image']['noise']['sky_level_pixel'] = 1.e-5
    try:
        np.testing.assert_raises(RuntimeError, galsim.config.BuildStamp,config)
    except ImportError:
        pass

    # 3. CCDNoise
    #####
    config['image']['noise'] =  {
        'type' : 'CCD',
        'sky_level_pixel' : 25,
        'read_noise' : 5,
        'gain' : 1,
        'whiten' : True,
    }
    galsim.config.RemoveCurrent(config)
    im4a = im1a.copy()
    rn = math.sqrt(25-cv1a)
    rng.reset(rng1.duplicate())
    im4a.addNoise(galsim.CCDNoise(sky_level=25, read_noise=rn, gain=1, rng=rng))
    im4b, cv4b = galsim.config.BuildStamp(config)
    np.testing.assert_almost_equal(cv4b, 50, decimal=5)
    np.testing.assert_almost_equal(im4b.array, im4a.array, decimal=5)

    # Repeat with gain != 1
    config['image']['noise']['gain'] = 3.7
    galsim.config.RemoveCurrent(config)
    im5a = im1a.copy()
    rn = math.sqrt(25-cv1a * 3.7**2)
    rng.reset(rng1.duplicate())
    im5a.addNoise(galsim.CCDNoise(sky_level=25, read_noise=rn, gain=3.7, rng=rng))
    im5b, cv5b = galsim.config.BuildStamp(config)
    np.testing.assert_almost_equal(cv5b, 50, decimal=5)
    np.testing.assert_almost_equal(im5b.array, im5a.array, decimal=5)

    # And again with a non-trivial sky image
    galsim.config.RemoveCurrent(config2)
    config2['image']['noise'] = config['image']['noise']
    config2['image']['noise']['symmetrize'] = 4
    del config2['image']['noise']['whiten']
    rng.reset(1234+1)
    im5c = galsim.Image(32,32, wcs=wcs)
    im5c = final.drawImage(im5c)
    cv5c = final.noise.symmetrizeImage(im5c, 4)
    sky = galsim.Image(im5c.bounds, wcs=wcs)
    wcs.makeSkyImage(sky, 100)
    mean_sky = np.mean(sky.array)
    im5c += sky
    rn = math.sqrt(25-cv5c * 3.7**2)
    im5c.addNoise(galsim.CCDNoise(sky_level=25, read_noise=rn, gain=3.7, rng=rng))
    im5d, cv5d = galsim.config.BuildStamp(config2)
    np.testing.assert_almost_equal(cv5d, 50 + mean_sky, decimal=4)
    np.testing.assert_almost_equal(im5d.array, im5c.array, decimal=5)

    config['image']['noise']['sky_level_pixel'] = 1.e-5
    config['image']['noise']['read_noise'] = 0
    try:
        np.testing.assert_raises(RuntimeError, galsim.config.BuildStamp,config)
    except ImportError:
        pass

    # 4. COSMOSNoise
    #####
    file_name = os.path.join(galsim.meta_data.share_dir,'acs_I_unrot_sci_20_cf.fits')
    config['image']['noise'] =  {
        'type' : 'COSMOS',
        'file_name' : file_name,
        'variance' : 50,
        'whiten' : True,
    }
    galsim.config.RemoveCurrent(config)
    im6a = im1a.copy()
    rng.reset(rng1.duplicate())
    noise = galsim.getCOSMOSNoise(file_name=file_name, variance=50, rng=rng)
    noise -= galsim.UncorrelatedNoise(cv1a, rng=rng, wcs=noise.wcs)
    im6a.addNoise(noise)
    im6b, cv6b = galsim.config.BuildStamp(config)
    np.testing.assert_almost_equal(cv6b, 50, decimal=5)
    np.testing.assert_almost_equal(im6b.array, im6a.array, decimal=5)

    config['image']['noise']['variance'] = 1.e-5
    del config['_current_cn_tag']
    try:
        np.testing.assert_raises(RuntimeError, galsim.config.BuildStamp,config)
    except ImportError:
        pass
Example #9
0
def test_cosmosnoise():
    """Test that the config layer COSMOS noise works with keywords.
    """
    import logging

    logger = None

    pix_scale = 0.03
    random_seed = 123

    # First make the image using COSMOSNoise without kwargs.
    config = {}
    # Either gal or psf is required, but it can be type = None, which means don't draw anything.
    config['gal'] = { 'type' : 'None' }
    config['stamp'] = {
        'type' : 'Basic',
        'size' : 64
    }
    config['image'] = {
        'pixel_scale' : pix_scale,
        'random_seed' : 123 # Note: this means the seed for the noise will really be 124
                            # since it is applied at the stamp level, so uses seed + obj_num
    }
    config['image']['noise'] = {
        'type' : 'COSMOS'
    }
    image = galsim.config.BuildStamp(config,logger=logger)[0]

    # Then make it using explicit kwargs to make sure they are getting passed through properly.
    config2 = {}
    config2['gal'] = config['gal']
    config2['stamp'] = {
        'type' : 'Basic',
        'xsize' : 64,  # Same thing, but cover the xsize, ysize options
        'ysize' : 64
    }
    config2['image'] = config['image']
    config2['image']['noise'] = {
        'type' : 'COSMOS',
        'file_name' : os.path.join(galsim.meta_data.share_dir,'acs_I_unrot_sci_20_cf.fits'),
        'cosmos_scale' : pix_scale
    }
    image2 = galsim.config.BuildStamp(config2,logger=logger)[0]

    # We used the same RNG and noise file / properties, so should get the same exact noise field.
    np.testing.assert_allclose(
        image.array, image2.array, rtol=1.e-5,
        err_msg='Config COSMOS noise does not reproduce results given kwargs')

    # Use a RealGalaxy with whitening to make sure that it properly handles any current_var
    # in the image already.
    # Detects bug Rachel found in issue #792
    config['gal'] = {
        'type' : 'RealGalaxy',
        'index' : 79,
        # Use a small flux to make sure that whitening doesn't add more noise than we will
        # request from the COSMOS noise.  (flux = 0.1 is too high.)
        'flux' : 0.01
    }
    real_gal_dir = os.path.join('..','examples','data')
    real_gal_cat = 'real_galaxy_catalog_23.5_example.fits'
    config['input'] = {
        'real_catalog' : {
            'dir' : real_gal_dir ,
            'file_name' : real_gal_cat
        }
    }
    config['image']['noise']['whiten'] = True
    galsim.config.ProcessInput(config)
    image3, current_var3 = galsim.config.BuildStamp(config, logger=logger)
    print('From BuildStamp, current_var = ',current_var3)

    # Build the same image by hand to make sure it matches what config drew.
    rng = galsim.BaseDeviate(124)
    rgc = galsim.RealGalaxyCatalog(os.path.join(real_gal_dir, real_gal_cat))
    gal = galsim.RealGalaxy(rgc, index=79, flux=0.01, rng=rng)
    image4 = gal.drawImage(image=image3.copy())
    current_var4 = gal.noise.whitenImage(image4)
    print('After whitening, current_var = ',current_var4)
    noise = galsim.correlatednoise.getCOSMOSNoise(
            rng=rng,
            file_name=os.path.join(galsim.meta_data.share_dir,'acs_I_unrot_sci_20_cf.fits'),
            cosmos_scale=pix_scale)

    # Check that the COSMOSNoiseBuilder calculates the right variance.
    var1 = noise.getVariance()
    var2 = galsim.config.CalculateNoiseVariance(config)
    print('Full noise variance = ',noise.getVariance())
    print('From config.CalculateNoiseVar = ',var2)
    np.testing.assert_almost_equal(var2, var1, err_msg="COSMOSNoise calculated the wrong variance")

    # Finish whitening steps.
    np.testing.assert_equal(
        current_var3, noise.getVariance(),
        err_msg='Config COSMOS noise with whitening does not return the correct current_var')
    noise -= galsim.UncorrelatedNoise(current_var4, rng=rng, wcs=image4.wcs)
    print('After subtract current_var, noise variance = ',noise.getVariance())
    image4.addNoise(noise)
    np.testing.assert_equal(
        image3.array, image4.array,
        err_msg='Config COSMOS noise with whitening does not reproduce manually drawn image')

    # If CalculateNoiseVar happens before using the noise, there is a slightly different code
    # path, but it should return the same answer of course.
    del config['_current_cn_tag']
    var3 = galsim.config.CalculateNoiseVariance(config)
    print('From config.CalculateNoiseVar = ',var3)
    np.testing.assert_almost_equal(var3, var1, err_msg="COSMOSNoise calculated the wrong variance")

    # AddNoiseVariance should add the variance to an image
    image5 = galsim.Image(32,32)
    galsim.config.AddNoiseVariance(config, image5)
    np.testing.assert_almost_equal(image5.array, var1,
                                   err_msg="AddNoiseVariance added the wrong variance")
Example #10
0
def test_dep_correlatednoise():
    """Test the deprecated methods in galsim/deprecated/correlatednoise.py
    """
    rng = galsim.BaseDeviate(123)
    n1 = galsim.UncorrelatedNoise(variance=0.01,
                                  scale=1.3,
                                  rng=rng.duplicate())
    n2 = galsim.UncorrelatedNoise(variance=0.01,
                                  scale=1.3,
                                  rng=rng.duplicate())

    b = galsim.BoundsI(1, 3, 1, 3)
    mat = check_dep(n1.calculateCovarianceMatrix, bounds=b, scale=1.9)
    # No replacement, so nothing to compare with.

    check_dep(n1.setVariance, variance=1.7)
    np.testing.assert_almost_equal(n1.getVariance(), 1.7)

    check_dep(n1.scaleVariance, variance_ratio=1.9)
    np.testing.assert_almost_equal(n1.getVariance(), 1.7 * 1.9)

    n2 = n2.withVariance(1.7 * 1.9)

    n2 = n2.expand(4.3)
    n3 = check_dep(n1.createExpanded, scale=4.3)
    gsobject_compare(n3, n2)

    check_dep(n1.applyExpansion, scale=4.3)
    gsobject_compare(n1, n2)

    n2 = n2.shear(g1=0.3, g2=-0.13)
    n3 = check_dep(n1.createSheared, g1=0.3, g2=-0.13)
    gsobject_compare(n3, n2)

    check_dep(n1.applyShear, g1=0.3, g2=-0.13)
    gsobject_compare(n1, n2)

    n2 = n2.dilate(0.54)
    n3 = check_dep(n1.createDilated, scale=0.54)
    gsobject_compare(n3, n2)

    check_dep(n1.applyDilation, scale=0.54)
    gsobject_compare(n1, n2)

    n2 = n2.magnify(1.1)
    n3 = check_dep(n1.createMagnified, mu=1.1)
    gsobject_compare(n3, n2)

    check_dep(n1.applyMagnification, mu=1.1)
    gsobject_compare(n1, n2)

    n2 = n2.lens(g1=0.31, g2=0.48, mu=0.22)
    n3 = check_dep(n1.createLensed, g1=0.31, g2=0.48, mu=0.22)
    gsobject_compare(n3, n2)

    check_dep(n1.applyLensing, g1=0.31, g2=0.48, mu=0.22)
    gsobject_compare(n1, n2)

    n2 = n2.rotate(38.4 * galsim.degrees)
    n3 = check_dep(n1.createRotated, 38.4 * galsim.degrees)
    gsobject_compare(n3, n2)

    check_dep(n1.applyRotation, theta=38.4 * galsim.degrees)
    gsobject_compare(n1, n2)

    n2 = n2.transform(0.1, 1.09, -1.32, -0.09)
    n3 = check_dep(n1.createTransformed,
                   dudx=0.1,
                   dudy=1.09,
                   dvdx=-1.32,
                   dvdy=-0.09)
    gsobject_compare(n3, n2)

    check_dep(n1.applyTransformation,
              dudx=0.1,
              dudy=1.09,
              dvdx=-1.32,
              dvdy=-0.09)
    gsobject_compare(n1, n2)

    g = galsim.Gaussian(sigma=0.34)
    n2 = n2.convolvedWith(g)
    check_dep(n1.convolveWith, g)
    gsobject_compare(n1, n2)

    im1 = n1.drawImage()
    im2 = check_dep(n2.draw)
    np.testing.assert_almost_equal(im1.scale, im2.scale)
    np.testing.assert_equal(im1.bounds, im2.bounds)
    np.testing.assert_array_almost_equal(im1.array, im2.array)

    n1.whitenImage(im1)
    check_dep(n2.applyWhiteningTo, im2)
    np.testing.assert_array_almost_equal(im1.array, im2.array)
Example #11
0
    def __init__(self, real_galaxy_catalog, index=None, id=None, random=False,
                 rng=None, x_interpolant=None, k_interpolant=None, flux=None, flux_rescale=None,
                 pad_factor=4, noise_pad_size=0, gsparams=None, logger=None):


        if rng is None:
            self.rng = galsim.BaseDeviate()
        elif not isinstance(rng, galsim.BaseDeviate):
            raise TypeError("The rng provided to RealGalaxy constructor is not a BaseDeviate")
        else:
            self.rng = rng
        self._rng = self.rng.duplicate()  # This is only needed if we want to make sure eval(repr)
                                          # results in the same object.

        if flux is not None and flux_rescale is not None:
            raise TypeError("Cannot supply a flux and a flux rescaling factor!")

        if isinstance(real_galaxy_catalog, tuple):
            # Special (undocumented) way to build a RealGalaxy without needing the rgc directly
            # by providing the things we need from it.  Used by COSMOSGalaxy.
            self.gal_image, self.psf_image, noise_image, pixel_scale, var = real_galaxy_catalog
            use_index = 0  # For the logger statements below.
            if logger:
                logger.debug('RealGalaxy %d: Start RealGalaxy constructor.',use_index)
            self.catalog_file = None
        else:
            # Get the index to use in the 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.getIndexForID(id)
            elif random:
                ud = galsim.UniformDeviate(self.rng)
                use_index = int(real_galaxy_catalog.nobjects * ud())
                if hasattr(real_galaxy_catalog, 'weight'):
                    # If weight factors are available, make sure the random selection uses the
                    # weights to remove the catalog-level selection effects (flux_radius-dependent
                    # probability of making a postage stamp for a given object).
                    while ud() > real_galaxy_catalog.weight[use_index]:
                        # Pick another one to try.
                        use_index = int(real_galaxy_catalog.nobjects * ud())
            else:
                raise AttributeError('No method specified for selecting a galaxy!')
            if logger:
                logger.debug('RealGalaxy %d: Start RealGalaxy constructor.',use_index)

            # Read in the galaxy, PSF images; for now, rely on pyfits to make I/O errors.
            self.gal_image = real_galaxy_catalog.getGal(use_index)
            if logger:
                logger.debug('RealGalaxy %d: Got gal_image',use_index)

            self.psf_image = real_galaxy_catalog.getPSF(use_index)
            if logger:
                logger.debug('RealGalaxy %d: Got psf_image',use_index)

            #self.noise = real_galaxy_catalog.getNoise(use_index, self.rng, gsparams)
            # We need to duplication some of the RealGalaxyCatalog.getNoise() function, since we
            # want it to be possible to have the RealGalaxyCatalog in another process, and the
            # BaseCorrelatedNoise object is not picklable.  So we just build it here instead.
            noise_image, pixel_scale, var = real_galaxy_catalog.getNoiseProperties(use_index)
            if logger:
                logger.debug('RealGalaxy %d: Got noise_image',use_index)
            self.catalog_file = real_galaxy_catalog.getFileName()

        if noise_image is None:
            self.noise = galsim.UncorrelatedNoise(var, rng=self.rng, scale=pixel_scale,
                                                  gsparams=gsparams)
        else:
            ii = galsim.InterpolatedImage(noise_image, normalization="sb",
                                          calculate_stepk=False, calculate_maxk=False,
                                          x_interpolant='linear', gsparams=gsparams)
            self.noise = galsim.correlatednoise._BaseCorrelatedNoise(self.rng, ii, noise_image.wcs)
            self.noise = self.noise.withVariance(var)
        if logger:
            logger.debug('RealGalaxy %d: Finished building noise',use_index)

        # Save any other relevant information as instance attributes
        self.catalog = real_galaxy_catalog
        self.index = use_index
        self.pixel_scale = float(pixel_scale)
        self._x_interpolant = x_interpolant
        self._k_interpolant = k_interpolant
        self._pad_factor = pad_factor
        self._noise_pad_size = noise_pad_size
        self._flux = flux
        self._gsparams = gsparams

        # Convert noise_pad to the right noise to pass to InterpolatedImage
        if noise_pad_size:
            noise_pad = self.noise
        else:
            noise_pad = 0.

        # Build the InterpolatedImage of the PSF.
        self.original_psf = galsim.InterpolatedImage(
            self.psf_image, x_interpolant=x_interpolant, k_interpolant=k_interpolant,
            flux=1.0, gsparams=gsparams)
        if logger:
            logger.debug('RealGalaxy %d: Made original_psf',use_index)

        # Build the InterpolatedImage of the galaxy.
        # Use the stepK() value of the PSF as a maximum value for stepK of the galaxy.
        # (Otherwise, low surface brightness galaxies can get a spuriously high stepk, which
        # leads to problems.)
        self.original_gal = galsim.InterpolatedImage(
                self.gal_image, x_interpolant=x_interpolant, k_interpolant=k_interpolant,
                pad_factor=pad_factor, noise_pad_size=noise_pad_size,
                calculate_stepk=self.original_psf.stepK(),
                calculate_maxk=self.original_psf.maxK(),
                noise_pad=noise_pad, rng=self.rng, gsparams=gsparams)
        if logger:
            logger.debug('RealGalaxy %d: Made original_gal',use_index)

        # If flux is None, leave flux as given by original image
        if flux is not None:
            flux_rescale = flux / self.original_gal.getFlux()
        if flux_rescale is not None:
            self.original_gal *= flux_rescale
            self.noise *= flux_rescale**2

        # Calculate the PSF "deconvolution" kernel
        psf_inv = galsim.Deconvolve(self.original_psf, gsparams=gsparams)

        # Initialize the SBProfile attribute
        GSObject.__init__(
            self, galsim.Convolve([self.original_gal, psf_inv], gsparams=gsparams))
        if logger:
            logger.debug('RealGalaxy %d: Made gsobject',use_index)

        # Save the noise in the image as an accessible attribute
        self.noise = self.noise.convolvedWith(psf_inv, gsparams)
        if logger:
            logger.debug('RealGalaxy %d: Finished building RealGalaxy',use_index)
Example #12
0
def test_metacal_tracking():
    """Test that the noise tracking works for the metacal use case involving deconvolution and
    reconvolution by almost the same PSF.

    This test is similar to the above test_uncorrelated_noise_tracking, except the modifications
    are based on what is done for the metacal procedure.
    """
    import math

    def check_noise(noise_image, noise, msg):
        # A helper function to check that the current noise in the image is properly described
        # by the given CorrelatedNoise object
        noise2 = galsim.CorrelatedNoise(noise_image)
        print('noise = ', noise)
        print('noise2 = ', noise2)
        np.testing.assert_almost_equal(noise.getVariance(),
                                       noise2.getVariance(),
                                       decimal=CHECKNOISE_NDECIMAL,
                                       err_msg=msg +
                                       ': variance does not match.')
        cf_im1 = galsim.Image(8, 8, wcs=noise_image.wcs)
        cf_im2 = cf_im1.copy()
        noise.drawImage(image=cf_im1)
        noise2.drawImage(image=cf_im2)
        np.testing.assert_almost_equal(cf_im1.array,
                                       cf_im2.array,
                                       decimal=CHECKNOISE_NDECIMAL,
                                       err_msg=msg +
                                       ': image of cf does not match.')

    def check_symm_noise(noise_image, msg):
        # A helper funciton to see if a noise image has 4-fold symmetric noise.
        im2 = noise_image.copy()
        # Clear out any wcs to make the test simpler
        im2.wcs = galsim.PixelScale(1.)
        noise = galsim.CorrelatedNoise(im2)
        cf = noise.drawImage(
            galsim.Image(bounds=galsim.BoundsI(-1, 1, -1, 1), scale=1))
        # First check the variance
        print('variance: ', cf(0, 0), noise.getVariance())
        np.testing.assert_almost_equal(cf(0, 0) / noise.getVariance(),
                                       1.0,
                                       decimal=VAR_NDECIMAL,
                                       err_msg=msg +
                                       ':: noise variance is wrong.')
        cf_plus = np.array([cf(1, 0), cf(-1, 0), cf(0, 1), cf(0, -1)])
        cf_cross = np.array([cf(1, 1), cf(-1, -1), cf(-1, 1), cf(1, -1)])
        print('plus pattern: ', cf_plus)
        print('diff relative to dc: ', (cf_plus - np.mean(cf_plus)) / cf(0, 0))
        print('cross pattern: ', cf_cross)
        print('diff relative to dc: ',
              (cf_cross - np.mean(cf_cross)) / cf(0, 0))
        # For now, don't make these asserts.  Just print whether they will pass or fail.
        if True:
            if np.all(np.abs((cf_plus - np.mean(cf_plus)) / cf(0, 0)) < 0.01):
                print('plus test passes')
            else:
                print('*** FAIL ***')
                print(msg + ': plus pattern is not constant')
            if np.all(
                    np.abs((cf_cross - np.mean(cf_cross)) / cf(0, 0)) < 0.01):
                print('cross test passes')
            else:
                print('*** FAIL ***')
                print(msg + ': cross pattern is not constant')
        else:
            np.testing.assert_almost_equal(
                (cf_plus - np.mean(cf_plus)) / cf(0, 0),
                0.0,
                decimal=2,
                err_msg=msg + ': plus pattern is not constant')
            np.testing.assert_almost_equal(
                (cf_cross - np.mean(cf_cross)) / cf(0, 0),
                0.0,
                decimal=2,
                err_msg=msg + ': cross pattern is not constant')

    seed = 1234567  # For use as a unit test, we need a specific seed
    #seed = 0  # During testing, it's useful to see how numbers flop around to know if
    # something is systematic or random.
    rng = galsim.BaseDeviate(seed)

    noise_var = 1.3
    im_size = 1024
    dg = 0.1  # This is bigger than metacal would use, but it makes the test easier.

    # Use a non-trivial wcs...
    #wcs = galsim.JacobianWCS(0.26, 0.04, -0.04, -0.26)  # Rotation + flip.  No shear.
    wcs = galsim.JacobianWCS(0.26, 0.03, 0.08, -0.21)  # Fully complex
    #dudx =  0.12*0.26
    #dudy =  1.10*0.26
    #dvdx = -0.915*0.26
    #dvdy = -0.04*0.26
    #wcs = galsim.JacobianWCS(dudx, dudy, dvdx, dvdy)  # Even more extreme

    # And an asymmetric PSF
    #orig_psf = galsim.Gaussian(fwhm=0.9).shear(g1=0.05, g2=0.03)
    # This one is small enough not to be fully Nyquist sampled, which makes things harder.
    orig_psf = galsim.Gaussian(fwhm=0.7).shear(g1=0.05, g2=0.03)

    # pixel is the pixel in world coords
    pixel = wcs.toWorld(galsim.Pixel(scale=1))
    pixel_inv = galsim.Deconvolve(pixel)

    psf_image = orig_psf.drawImage(nx=im_size, ny=im_size, wcs=wcs)

    # Metacal only has access to the PSF as an image, so use this from here on.
    psf = galsim.InterpolatedImage(psf_image)
    psf_nopix = galsim.Convolve([psf, pixel_inv])
    psf_inv = galsim.Deconvolve(psf)

    # Not what is done currently, but using a smoother target PSF helps make sure the
    # zeros in the deconvolved PSF get adequately zeroed out.
    def get_target_psf(psf):
        dk = 0.1  # The resolution in k space for the KImage
        small_kval = 1.e-2  # Find the k where the given psf hits this kvalue
        smaller_kval = 3.e-3  # Target PSF will have this kvalue at the same k

        kim = psf.drawKImage(scale=dk)
        karr_r = kim.real.array
        # Find the smallest r where the kval < small_kval
        nk = karr_r.shape[0]
        kx, ky = np.meshgrid(np.arange(-nk / 2, nk / 2),
                             np.arange(-nk / 2, nk / 2))
        ksq = (kx**2 + ky**2) * dk**2
        ksq_max = np.min(ksq[karr_r < small_kval * psf.flux])

        # We take our target PSF to be the (round) Gaussian that is even smaller at this ksq
        # exp(-0.5 * ksq_max * sigma_sq) = smaller_kval
        sigma_sq = -2. * np.log(smaller_kval) / ksq_max
        return galsim.Gaussian(sigma=np.sqrt(sigma_sq))

    # The target PSF dilates the part without the pixel, but reconvolve by the real pixel.
    #psf_target_nopix = psf_nopix.dilate(1. + 2.*dg)
    #psf_target_nopix = orig_psf.dilate(1. + 4.*dg)
    psf_target_nopix = get_target_psf(psf_nopix.shear(g1=dg))
    print('PSF target HLR = ', psf_target_nopix.calculateHLR())
    print('PSF target FWHM = ', psf_target_nopix.calculateFWHM())
    psf_target = galsim.Convolve([psf_target_nopix, pixel])

    # Make an image of pure (white) Gaussian noise
    # Normally, there would be a galaxy in this image, but for the tests, we just have noise.
    obs_image = galsim.Image(im_size, im_size, init_value=0, wcs=wcs)
    obs_image.addNoise(
        galsim.GaussianNoise(rng=rng, sigma=math.sqrt(noise_var)))

    # The noise on this image should be describable as an UncorrelatedNoise object:
    noise = galsim.UncorrelatedNoise(variance=noise_var, wcs=wcs)
    check_noise(obs_image, noise, 'initial UncorrelatedNoise model is wrong')

    # Make an InterpolatedImage profile to use for manipulating this image
    # We can get away with no padding here, since our image is so large, but normally, you would
    # probably want to pad this with noise padding.
    ii = galsim.InterpolatedImage(obs_image, pad_factor=1)
    ii.noise = noise

    # If we draw it back, the attached noise attribute should still be correct
    check_noise(ii.drawImage(obs_image.copy(), method='no_pixel'), ii.noise,
                'noise model is wrong for InterpolatedImage')

    # Here is the metacal process for which we want to understand the noise.
    # We'll try a few different methods.
    shear = galsim.Shear(g1=dg)
    sheared_obj = galsim.Convolve(ii, psf_inv).shear(shear)
    final_obj = galsim.Convolve(psf_target, sheared_obj)
    final_image = final_obj.drawImage(obs_image.copy(), method='no_pixel')

    try:
        check_symm_noise(final_image, 'Initial image')
        #didnt_fail = True
        # This bit doesn't work while we are not actually raising exceptions in check_symm_noise
        # So we expect to see **FAIL** text at this point.
        print(
            'The above tests are expected to **FAIL**.  This is not a problem.'
        )
        didnt_fail = False
    except AssertionError as e:
        print('As expected initial image fails symmetric noise test:')
        print(e)
        didnt_fail = False
    if didnt_fail:
        assert False, 'Initial image was expected to fail symmetric noise test, but passed.'

    if True:
        print('\n\nStrategy 1:')
        # Strategy 1: Use the noise attribute attached to ii and use it to either whiten or
        #             symmetrize the noise in the final image.
        # Note: The check_noise tests fail.  I think because the convolve and deconvolve impose
        #       a maxk = that of the psf.  Which is too small for an accurate rendering of the
        #       correlation function (here just an autocorrelation of a Pixel.
        # The whiten tests kind of work, but they add a lot of extra noise.  Much more than
        # strategy 4 below.  So the level of correlation remaining is pretty well below the
        # dc variance.  Symmetrize doesn't add much noise, but the residual correlation is about
        # the same, which means it doesn't pass the test relative to the lower dc variance.

        # First, deconvolve and reconvolve by the same PSF:
        test_obj = galsim.Convolve([ii, psf, psf_inv])
        # This fails...
        if False:
            check_noise(
                test_obj.drawImage(obs_image.copy(),
                                   method='no_pixel'), test_obj.noise,
                'noise model is wrong after convolve/deconvolve by psf')

        # Now use a slightly dilated PSF for the reconvolution:
        test_obj = galsim.Convolve([ii, psf_target, psf_inv])
        if False:
            check_noise(
                test_obj.drawImage(obs_image.copy(), method='no_pixel'),
                test_obj.noise, 'noise model is wrong for dilated target psf')

        # Finally, include the shear step.  This was done above with sheared_obj, final_obj.
        if False:
            check_noise(final_image, final_obj.noise,
                        'noise model is wrong when including small shear')

        # If we whiten using this noise model, we should get back to white noise.
        t3 = time.time()
        final_image2 = final_image.copy()  # Don't clobber the original
        final_var = final_image2.whitenNoise(final_obj.noise)
        t4 = time.time()
        print('Noise tracking method with whiten: final_var = ', final_var)
        print('Check: direct variance = ', np.var(final_image2.array))
        check_symm_noise(final_image2, 'noise whitening does not work')
        print('Time for noise tracking with whiten = ', t4 - t3)

        # Using symmetrizeNoise should add less noise, but also work.
        t3 = time.time()
        final_image2 = final_image.copy()
        final_var = final_image2.symmetrizeNoise(final_obj.noise)
        t4 = time.time()
        print('Noise tracking method with symmetrize: final_var = ', final_var)
        print('Check: direct variance = ', np.var(final_image2.array))
        check_symm_noise(final_image2, 'noise symmetrizing does not work')
        print('Time for noise tracking with symmetrize = ', t4 - t3)

    if True:
        print('\n\nStrategy 2:')
        # Strategy 2: Don't trust the noise tracking. Track a noise image through the same process
        #             and then measure the noise from that image.  Use it to either whiten or
        #             symmetrize the noise in the final image.
        # Note: This method doesn't work any better.  The added noise for whitening is even more
        # than strategy 1.  And the remaining correlations are still similarly significant for the
        # symmetrize version.  A little smaller than strategy 1, but not enough to pass our tests.

        # Make another noise image, since we don't actually have access to a pure noise image
        # for real objects.  But we should be able to estimate the variance in the image.
        t3 = time.time()
        noise_image = galsim.Image(im_size, im_size, init_value=0, wcs=wcs)
        noise_image.addNoise(
            galsim.GaussianNoise(rng=rng, sigma=math.sqrt(noise_var)))
        noise_ii = galsim.InterpolatedImage(noise_image, pad_factor=1)
        sheared_noise_obj = galsim.Convolve(noise_ii, psf_inv).shear(shear)
        final_noise_obj = galsim.Convolve(psf_target, sheared_noise_obj)
        final_noise_image = final_noise_obj.drawImage(obs_image.copy(),
                                                      method='no_pixel')

        # Use this to construct an appropriate CorrelatedNoise object
        noise = galsim.CorrelatedNoise(final_noise_image)
        t4 = time.time()
        final_image2 = final_image.copy()
        final_var = final_image2.whitenNoise(noise)
        t5 = time.time()

        check_noise(
            final_noise_image, noise,
            'noise model is wrong when direct measuring the final noise image')

        print('Direct noise method with whiten: final_var = ', final_var)
        # Neither of these work currently, so maybe a bug in the whitening code?
        # Or possibly in my logic here.
        check_symm_noise(
            final_image2,
            'whitening the noise using direct noise model failed')
        print('Time for direct noise with whitening = ', t5 - t3)

        t6 = time.time()
        final_image2 = final_image.copy()
        final_var = final_image2.symmetrizeNoise(noise)
        t7 = time.time()

        print('Direct noise method with symmetrize: final_var = ', final_var)
        check_symm_noise(
            final_image2,
            'symmetrizing the noise using direct noise model failed')
        print('Time for direct noise with symmetrizing = ', t7 - t6 + t4 - t3)

    if False:
        print('\n\nStrategy 3:')
        # Strategy 3: Make a noise field and do the same operations as we do to the main image
        #             except use the opposite shear value.  Add this noise field to the final
        #             image to get a symmetric noise field.
        # Note: This method works!  But only for square pixels.  However, they may be rotated
        # or flipped. Just not sheared.
        # Update: I think this method won't ever work for non-square pixels.  The reason it works
        # for square pixels is that in that case, it is equivalent to strategy 4.
        t3 = time.time()

        # Make another noise image
        rev_image = galsim.Image(im_size, im_size, init_value=0, wcs=wcs)
        rev_image.addNoise(
            galsim.GaussianNoise(rng=rng, sigma=math.sqrt(noise_var)))
        rev_ii = galsim.InterpolatedImage(rev_image, pad_factor=1)

        rev_sheared_obj = galsim.Convolve(rev_ii, psf_inv).shear(-shear)
        rev_final_obj = galsim.Convolve(psf_target, rev_sheared_obj)
        rev_final_image = rev_final_obj.drawImage(obs_image.copy(),
                                                  method='no_pixel')

        # Add the reverse-sheared noise image to the original image.
        final_image2 = final_image + rev_final_image
        t4 = time.time()

        # The noise variance in the end should be 2x as large as the original
        final_var = np.var(final_image2.array)
        print('Reverse shear method: final_var = ', final_var)
        check_symm_noise(final_image2, 'using reverse shear does not work')
        print('Time for reverse shear method = ', t4 - t3)

    if True:
        print('\n\nStrategy 4:')
        # Strategy 4: Make a noise field and do the same operations as we do to the main image,
        #             then rotate it by 90 degress and add it to the final image.
        # This method works!  Even for an arbitrarily sheared wcs.
        t3 = time.time()

        # Make another noise image
        noise_image = galsim.Image(im_size, im_size, init_value=0, wcs=wcs)
        noise_image.addNoise(
            galsim.GaussianNoise(rng=rng, sigma=math.sqrt(noise_var)))
        noise_ii = galsim.InterpolatedImage(noise_image, pad_factor=1)

        noise_sheared_obj = galsim.Convolve(noise_ii, psf_inv).shear(shear)
        noise_final_obj = galsim.Convolve(psf_target, noise_sheared_obj)
        noise_final_image = noise_final_obj.drawImage(obs_image.copy(),
                                                      method='no_pixel')

        # Rotate the image by 90 degrees
        rot_noise_final_image = galsim.Image(
            np.ascontiguousarray(np.rot90(noise_final_image.array)))

        # Add the rotated noise image to the original image.
        final_image2 = final_image + rot_noise_final_image
        t4 = time.time()

        # The noise variance in the end should be 2x as large as the original
        final_var = np.var(final_image2.array)
        print('Rotate image method: final_var = ', final_var)
        check_symm_noise(final_image2,
                         'using rotated noise image does not work')
        print('Time for rotate image method = ', t4 - t3)

    if False:
        print('\n\nStrategy 5:')
        # Strategy 5: The same as strategy 3, except we target the effective net transformation
        #             done by strategy 4.
        # I think this strategy probably can't work for non-square pixels, because the shear
        # happens before the convolution by the PSF.  And if the wcs is non-square, then the
        # PSF is sheared relative to the pixels.  That shear isn't being accounted for here,
        # so the net result isn't equivalent to rotating by 90 degrees at the end.
        t3 = time.time()

        # Make another noise image
        rev_image = galsim.Image(im_size, im_size, init_value=0, wcs=wcs)
        rev_image.addNoise(
            galsim.GaussianNoise(rng=rng, sigma=math.sqrt(noise_var)))
        rev_ii = galsim.InterpolatedImage(rev_image, pad_factor=1)

        # Find the effective transformation to apply in sky coordinates that matches what
        # you would get by applying the shear in sky coords, going to image coords and then
        # rotating by 90 degrees.
        #
        # If J is the jacobian of the wcs, and S1 is the applied shear, then we want to find
        # S2 such that J^-1 S2 = R90 J^-1 S1
        jac = wcs.jacobian()
        J = jac.getMatrix()
        Jinv = jac.inverse().getMatrix()
        S1 = shear.getMatrix()
        R90 = np.array([[0, -1], [1, 0]])
        S2 = J.dot(R90).dot(Jinv).dot(S1)
        scale, rev_shear, rev_theta, flip = galsim.JacobianWCS(
            *S2.flatten()).getDecomposition()
        # Flip should be False, and scale should be essentially 1.0.
        assert flip == False
        assert abs(scale - 1.) < 1.e-8

        rev_sheared_obj = galsim.Convolve(
            rev_ii, psf_inv).rotate(rev_theta).shear(rev_shear)
        rev_final_obj = galsim.Convolve(psf_target, rev_sheared_obj)
        rev_final_image = rev_final_obj.drawImage(obs_image.copy(),
                                                  method='no_pixel')

        # Add the reverse-sheared noise image to the original image.
        final_image2 = final_image + rev_final_image
        t4 = time.time()

        # The noise variance in the end should be 2x as large as the original
        final_var = np.var(final_image2.array)
        print('Alternate reverse shear method: final_var = ', final_var)
        check_symm_noise(final_image2,
                         'using alternate reverse shear does not work')
        print('Time for alternate reverse shear method = ', t4 - t3)
Example #13
0
def test_cosmosnoise():
    """Test that the config layer COSMOS noise works with keywords.
    """
    import logging

    logger = None

    pix_scale = 0.03
    random_seed = 123

    # First make the image using COSMOSNoise without kwargs.
    config = {}
    # Either gal or psf is required, so just give it a Gaussian with 0 flux.
    config['gal'] = {'type': 'Gaussian', 'sigma': 0.1, 'flux': 0}
    config['image'] = {
        'type': 'Single',
        'pixel_scale': pix_scale,
        'random_seed':
        123  # Note: this means the seed for the noise will really be 124
        # since it is applied at the stamp level, so uses seed + obj_num
    }
    config['image']['noise'] = {'type': 'COSMOS'}
    image = galsim.config.BuildImage(config, logger=logger)

    # Then make using kwargs explicitly, to make sure they are getting passed through properly.
    config2 = {}
    # Either gal or psf is required, so just give it a Gaussian with 0 flux.
    config2['gal'] = config['gal']
    config2['image'] = config['image']
    config2['image']['noise'] = {
        'type':
        'COSMOS',
        'file_name':
        os.path.join(galsim.meta_data.share_dir, 'acs_I_unrot_sci_20_cf.fits'),
        'cosmos_scale':
        pix_scale
    }
    image2 = galsim.config.BuildImage(config2, logger=logger)

    # We used the same RNG and noise file / properties, so should get the same exact noise field.
    np.testing.assert_allclose(
        image.array,
        image2.array,
        rtol=1.e-5,
        err_msg='Config COSMOS noise does not reproduce results given kwargs')

    # Use a RealGalaxy with whitening to make sure that it properly handles any current_var
    # in the image already.
    # Detects bug Rachel found in issue #792
    config['gal'] = {
        'type': 'RealGalaxy',
        'index': 79,
        # Use a small flux to make sure that whitening doesn't add more noise than we will
        # request from the COSMOS noise.  (flux = 0.1 is too high.)
        'flux': 0.01
    }
    real_gal_dir = os.path.join('..', 'examples', 'data')
    real_gal_cat = 'real_galaxy_catalog_23.5_example.fits'
    config['input'] = {
        'real_catalog': {
            'dir': real_gal_dir,
            'file_name': real_gal_cat
        }
    }
    config['image']['noise']['whiten'] = True
    galsim.config.ProcessInput(config)
    image3 = galsim.config.BuildImage(config, logger=logger)

    # Build the same image by hand to make sure it matches what config drew.
    rng = galsim.BaseDeviate(124)
    rgc = galsim.RealGalaxyCatalog(os.path.join(real_gal_dir, real_gal_cat))
    gal = galsim.RealGalaxy(rgc, index=79, flux=0.01, rng=rng)
    image4 = gal.drawImage(image=image3.copy())
    current_var = gal.noise.whitenImage(image4)
    noise = galsim.correlatednoise.getCOSMOSNoise(
        rng=rng,
        file_name=os.path.join(galsim.meta_data.share_dir,
                               'acs_I_unrot_sci_20_cf.fits'),
        cosmos_scale=pix_scale)
    noise -= galsim.UncorrelatedNoise(current_var, rng=rng, wcs=image4.wcs)
    image4.addNoise(noise)
    image3.write('image3.fits')
    image4.write('image4.fits')
    np.testing.assert_equal(
        image3.array,
        image4.array,
        err_msg=
        'Config COSMOS noise with whiting does not reproduce manually drawn image'
    )
Example #14
0
    def __init__(self, real_galaxy_catalog, index=None, id=None, random=False,
                 rng=None, x_interpolant=None, k_interpolant=None, flux=None, pad_factor=4,
                 noise_pad_size=0, gsparams=None, logger=None):

        import numpy as np

        if rng is None:
            rng = galsim.BaseDeviate()
        elif not isinstance(rng, galsim.BaseDeviate):
            raise TypeError("The rng provided to RealGalaxy constructor is not a BaseDeviate")
 
        # 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.getIndexForID(id)
        elif random is True:
            uniform_deviate = galsim.UniformDeviate(rng)
            use_index = int(real_galaxy_catalog.nobjects * uniform_deviate()) 
        else:
            raise AttributeError('No method specified for selecting a galaxy!')

        if logger:
            logger.debug('RealGalaxy %d: Start RealGalaxy constructor.',use_index)


        # read in the galaxy, PSF images; for now, rely on pyfits to make I/O errors.
        self.gal_image = real_galaxy_catalog.getGal(use_index)
        if logger:
            logger.debug('RealGalaxy %d: Got gal_image',use_index)

        self.psf_image = real_galaxy_catalog.getPSF(use_index)
        if logger:
            logger.debug('RealGalaxy %d: Got psf_image',use_index)

        #self.noise = real_galaxy_catalog.getNoise(use_index, rng, gsparams)
        # This is a duplication of the RealGalaxyCatalog.getNoise() function, since we
        # want it to be possible to have the RealGalaxyCatalog in another process, and the
        # BaseCorrelatedNoise object is not picklable.  So we just build it here instead.
        noise_image, pixel_scale, var = real_galaxy_catalog.getNoiseProperties(use_index)
        if logger:
            logger.debug('RealGalaxy %d: Got noise_image',use_index)

        if noise_image is None:
            self.noise = galsim.UncorrelatedNoise(var, rng=rng, scale=pixel_scale, gsparams=gsparams)
        else:
            ii = galsim.InterpolatedImage(noise_image, scale=pixel_scale, normalization="sb",
                                          calculate_stepk=False, calculate_maxk=False,
                                          x_interpolant='linear', gsparams=gsparams)
            self.noise = galsim.correlatednoise._BaseCorrelatedNoise(rng, ii)
            self.noise = self.noise.withVariance(var)
        if logger:
            logger.debug('RealGalaxy %d: Finished building noise',use_index)

        # Save any other relevant information as instance attributes
        self.catalog_file = real_galaxy_catalog.getFileName()
        self.index = use_index
        self.pixel_scale = float(pixel_scale)

        # Convert noise_pad to the right noise to pass to InterpolatedImage
        if noise_pad_size:
            noise_pad = self.noise
        else:
            noise_pad = 0.

        # Build the InterpolatedImage of the PSF.
        self.original_psf = galsim.InterpolatedImage(
            self.psf_image, x_interpolant=x_interpolant, k_interpolant=k_interpolant, 
            flux=1.0, scale=self.pixel_scale, gsparams=gsparams)
        if logger:
            logger.debug('RealGalaxy %d: Made original_psf',use_index)

        # Build the InterpolatedImage of the galaxy.
        # Use the stepK() value of the PSF as a maximum value for stepK of the galaxy.
        # (Otherwise, low surface brightness galaxies can get a spuriously high stepk, which
        # leads to problems.)
        self.original_image = galsim.InterpolatedImage(
                self.gal_image, x_interpolant=x_interpolant, k_interpolant=k_interpolant,
                scale=self.pixel_scale, pad_factor=pad_factor, noise_pad_size=noise_pad_size,
                calculate_stepk=self.original_psf.stepK(),
                calculate_maxk=self.original_psf.maxK(),
                noise_pad=noise_pad, rng=rng, gsparams=gsparams)
        if logger:
            logger.debug('RealGalaxy %d: Made original_image',use_index)

        # If flux is None, leave flux as given by original image
        if flux is not None:
            self.original_image = self.original_image.withFlux(flux)

        # Calculate the PSF "deconvolution" kernel
        psf_inv = galsim.Deconvolve(self.original_psf, gsparams=gsparams)
        # Initialize the SBProfile attribute
        GSObject.__init__(
            self, galsim.Convolve([self.original_image, psf_inv], gsparams=gsparams))
        if logger:
            logger.debug('RealGalaxy %d: Made gsobject',use_index)

        # Save the noise in the image as an accessible attribute
        self.noise = self.noise.convolvedWith(psf_inv, gsparams)
        if logger:
            logger.debug('RealGalaxy %d: Finished building RealGalaxy',use_index)