Exemple #1
0
def test_convolve_flux_scaling():
    """Test flux scaling for Convolve.
    """
    # decimal point to go to for parameter value comparisons
    param_decimal = 12
    test_flux = 17.9
    test_sigma = 1.8
    test_hlr = 1.9

    # init with Gaussian and DeVauc only (should be ok given last tests)
    obj = galsim.Convolve(
        [galsim.Gaussian(sigma=test_sigma, flux=np.sqrt(test_flux)),
         galsim.DeVaucouleurs(half_light_radius=test_hlr, flux=np.sqrt(test_flux))])
    obj *= 2.
    np.testing.assert_almost_equal(
        obj.flux, test_flux * 2., decimal=param_decimal,
        err_msg="Flux param inconsistent after __imul__.")
    obj = galsim.Convolve(
        [galsim.Gaussian(sigma=test_sigma, flux=np.sqrt(test_flux)),
         galsim.DeVaucouleurs(half_light_radius=test_hlr, flux=np.sqrt(test_flux))])
    obj /= 2.
    np.testing.assert_almost_equal(
        obj.flux, test_flux / 2., decimal=param_decimal,
        err_msg="Flux param inconsistent after __idiv__.")
    obj = galsim.Convolve(
        [galsim.Gaussian(sigma=test_sigma, flux=np.sqrt(test_flux)),
         galsim.DeVaucouleurs(half_light_radius=test_hlr, flux=np.sqrt(test_flux))])
    obj2 = obj * 2.
    # First test that original obj is unharmed...
    np.testing.assert_almost_equal(
        obj.flux, test_flux, decimal=param_decimal,
        err_msg="Flux param inconsistent after __rmul__ (original).")
    # Then test new obj2 flux
    np.testing.assert_almost_equal(
        obj2.flux, test_flux * 2., decimal=param_decimal,
        err_msg="Flux param inconsistent after __rmul__ (result).")
    obj = galsim.Convolve(
        [galsim.Gaussian(sigma=test_sigma, flux=np.sqrt(test_flux)),
         galsim.DeVaucouleurs(half_light_radius=test_hlr, flux=np.sqrt(test_flux))])
    obj2 = 2. * obj
    # First test that original obj is unharmed...
    np.testing.assert_almost_equal(
        obj.flux, test_flux, decimal=param_decimal,
        err_msg="Flux param inconsistent after __mul__ (original).")
    # Then test new obj2 flux
    np.testing.assert_almost_equal(
        obj2.flux, test_flux * 2., decimal=param_decimal,
        err_msg="Flux param inconsistent after __mul__ (result).")
    obj = galsim.Convolve(
        [galsim.Gaussian(sigma=test_sigma, flux=np.sqrt(test_flux)),
         galsim.DeVaucouleurs(half_light_radius=test_hlr, flux=np.sqrt(test_flux))])
    obj2 = obj / 2.
    # First test that original obj is unharmed...
    np.testing.assert_almost_equal(
        obj.flux, test_flux, decimal=param_decimal,
        err_msg="Flux param inconsistent after __div__ (original).")
    # Then test new obj2 flux
    np.testing.assert_almost_equal(
        obj2.flux, test_flux / 2., decimal=param_decimal,
        err_msg="Flux param inconsistent after __div__ (result).")
Exemple #2
0
def test_convolve_flux_scaling():
    """Test flux scaling for Convolve.
    """
    import time
    t1 = time.time()
    # init with Gaussian and DeVauc only (should be ok given last tests)
    obj = galsim.Convolve(
        [galsim.Gaussian(sigma=test_sigma, flux=np.sqrt(test_flux)),
         galsim.DeVaucouleurs(half_light_radius=test_hlr, flux=np.sqrt(test_flux))])
    obj *= 2.
    np.testing.assert_almost_equal(
        obj.getFlux(), test_flux * 2., decimal=param_decimal,
        err_msg="Flux param inconsistent after __imul__.")
    obj = galsim.Convolve(
        [galsim.Gaussian(sigma=test_sigma, flux=np.sqrt(test_flux)),
         galsim.DeVaucouleurs(half_light_radius=test_hlr, flux=np.sqrt(test_flux))])
    obj /= 2.
    np.testing.assert_almost_equal(
        obj.getFlux(), test_flux / 2., decimal=param_decimal,
        err_msg="Flux param inconsistent after __idiv__.")
    obj = galsim.Convolve(
        [galsim.Gaussian(sigma=test_sigma, flux=np.sqrt(test_flux)),
         galsim.DeVaucouleurs(half_light_radius=test_hlr, flux=np.sqrt(test_flux))])
    obj2 = obj * 2.
    # First test that original obj is unharmed... (also tests that .copy() is working)
    np.testing.assert_almost_equal(
        obj.getFlux(), test_flux, decimal=param_decimal,
        err_msg="Flux param inconsistent after __rmul__ (original).")
    # Then test new obj2 flux
    np.testing.assert_almost_equal(
        obj2.getFlux(), test_flux * 2., decimal=param_decimal,
        err_msg="Flux param inconsistent after __rmul__ (result).")
    obj = galsim.Convolve(
        [galsim.Gaussian(sigma=test_sigma, flux=np.sqrt(test_flux)),
         galsim.DeVaucouleurs(half_light_radius=test_hlr, flux=np.sqrt(test_flux))])
    obj2 = 2. * obj
    # First test that original obj is unharmed... (also tests that .copy() is working)
    np.testing.assert_almost_equal(
        obj.getFlux(), test_flux, decimal=param_decimal,
        err_msg="Flux param inconsistent after __mul__ (original).")
    # Then test new obj2 flux
    np.testing.assert_almost_equal(
        obj2.getFlux(), test_flux * 2., decimal=param_decimal,
        err_msg="Flux param inconsistent after __mul__ (result).")
    obj = galsim.Convolve(
        [galsim.Gaussian(sigma=test_sigma, flux=np.sqrt(test_flux)),
         galsim.DeVaucouleurs(half_light_radius=test_hlr, flux=np.sqrt(test_flux))])
    obj2 = obj / 2.
    # First test that original obj is unharmed... (also tests that .copy() is working)
    np.testing.assert_almost_equal(
        obj.getFlux(), test_flux, decimal=param_decimal,
        err_msg="Flux param inconsistent after __div__ (original).")
    # Then test new obj2 flux
    np.testing.assert_almost_equal(
        obj2.getFlux(), test_flux / 2., decimal=param_decimal,
        err_msg="Flux param inconsistent after __div__ (result).")
    t2 = time.time()
    print 'time for %s = %.2f'%(funcname(),t2-t1)
def test_largeshear():
    """Test the application of a large shear to a Sersic SBProfile against a known result.
    """
    import time
    t1 = time.time()
    e1 = 0.0
    e2 = 0.5

    myShear = galsim.Shear(e1=e1, e2=e2)
    # test the SBProfile version using applyShear
    savedImg = galsim.fits.read(os.path.join(imgdir, "sersic_largeshear.fits"))
    dx = 0.2
    myImg = galsim.ImageF(savedImg.bounds, scale=dx)
    myImg.setCenter(0,0)

    devauc = galsim.DeVaucouleurs(flux=1, half_light_radius=1)
    devauc.applyShear(myShear)
    devauc.draw(myImg,scale=dx, normalization="surface brightness", use_true_center=False)
    np.testing.assert_array_almost_equal(
            myImg.array, savedImg.array, 5,
            err_msg="Using GSObject applyShear disagrees with expected result")
    devauc = galsim.DeVaucouleurs(flux=1, half_light_radius=1)
    devauc2 = devauc.createSheared(myShear)
    devauc2.draw(myImg,scale=dx, normalization="surface brightness", use_true_center=False)
    np.testing.assert_array_almost_equal(
            myImg.array, savedImg.array, 5,
            err_msg="Using GSObject createSheared disagrees with expected result")

    # Check with default_params
    devauc = galsim.DeVaucouleurs(flux=1, half_light_radius=1, gsparams=default_params)
    devauc.applyShear(myShear)
    devauc.draw(myImg,scale=dx, normalization="surface brightness", use_true_center=False)
    np.testing.assert_array_almost_equal(
            myImg.array, savedImg.array, 5,
            err_msg="Using GSObject applyShear with default_params disagrees with expected result")
    devauc = galsim.DeVaucouleurs(flux=1, half_light_radius=1, gsparams=galsim.GSParams())
    devauc.applyShear(myShear)
    devauc.draw(myImg,scale=dx, normalization="surface brightness", use_true_center=False)
    np.testing.assert_array_almost_equal(
            myImg.array, savedImg.array, 5,
            err_msg="Using GSObject applyShear with GSParams() disagrees with expected result")
 
    # Test photon shooting.
    # Convolve with a small gaussian to smooth out the central peak.
    devauc2 = galsim.Convolve(devauc, galsim.Gaussian(sigma=0.3))
    do_shoot(devauc2,myImg,"sheared DeVauc")

    # Test kvalues.
    # Testing a sheared devauc requires a rather large fft.  What we really care about 
    # testing though is the accuracy of the applyShear function.  So just shear a Gaussian here.
    gauss = galsim.Gaussian(sigma=2.3)
    gauss.applyShear(myShear)
    do_kvalue(gauss, "sheared Gaussian")

    t2 = time.time()
    print 'time for %s = %.2f'%(funcname(),t2-t1)
Exemple #4
0
def test_largeshear():
    """Test the application of a large shear to a Sersic profile against a known result.
    """
    e1 = 0.0
    e2 = 0.5

    myShear = galsim.Shear(e1=e1, e2=e2)
    savedImg = galsim.fits.read(os.path.join(imgdir, "sersic_largeshear.fits"))
    dx = 0.2
    myImg = galsim.ImageF(savedImg.bounds, scale=dx)
    myImg.setCenter(0,0)

    devauc = galsim.DeVaucouleurs(flux=1, half_light_radius=1)
    devauc2 = devauc.shear(myShear)
    devauc2.drawImage(myImg,scale=dx, method="sb", use_true_center=False)
    np.testing.assert_array_almost_equal(
            myImg.array, savedImg.array, 5,
            err_msg="Using GSObject shear disagrees with expected result")
    np.testing.assert_almost_equal(
            myImg.array.max(), devauc2.max_sb, 5,
            err_msg="sheared profile max_sb did not match maximum pixel value")

    # Check with default_params
    devauc = galsim.DeVaucouleurs(flux=1, half_light_radius=1, gsparams=default_params)
    devauc = devauc.shear(myShear)
    devauc.drawImage(myImg,scale=dx, method="sb", use_true_center=False)
    np.testing.assert_array_almost_equal(
            myImg.array, savedImg.array, 5,
            err_msg="Using GSObject shear with default_params disagrees with expected result")
    devauc = galsim.DeVaucouleurs(flux=1, half_light_radius=1, gsparams=galsim.GSParams())
    devauc = devauc._shear(myShear)
    devauc.drawImage(myImg,scale=dx, method="sb", use_true_center=False)
    np.testing.assert_array_almost_equal(
            myImg.array, savedImg.array, 5,
            err_msg="Using GSObject shear with GSParams() disagrees with expected result")

    # Convolve with a small gaussian to smooth out the central peak.
    devauc2 = galsim.Convolve(devauc, galsim.Gaussian(sigma=0.3))
    check_basic(devauc2, "sheared DeVauc")

    # Test photon shooting.
    do_shoot(devauc2,myImg,"sheared DeVauc")

    # Test kvalues.
    # Testing a sheared devauc requires a rather large fft.  What we really care about
    # testing though is the accuracy of the shear function.  So just shear a Gaussian here.
    gauss = galsim.Gaussian(sigma=2.3)
    gauss = gauss.shear(myShear)
    do_kvalue(gauss,myImg, "sheared Gaussian")

    # Check picklability
    do_pickle(gauss, lambda x: x.drawImage())
    do_pickle(gauss)
    do_pickle(gauss._sbp)
def makeBulge(redshift, SEDs):
    bulgeG1, bulgeG2, mono_bulge_HLR = 0.12, 0.07, 0.5
    mono_bulge = galsim.DeVaucouleurs(half_light_radius=mono_bulge_HLR)
    bulge_SED = SEDs['CWW_E_ext'].atRedshift(redshift)
    bulge = mono_bulge * bulge_SED
    bulge = bulge.shear(g1=bulgeG1, g2=bulgeG2)
    return bulge
Exemple #6
0
    def get_galsim_light_source(self, band_index, psf_sigma_degrees,
                                image_parameters):
        def apply_shear_and_shift(galaxy):
            return (galaxy.shear(
                q=self._axis_ratio,
                beta=(90. - self._gal_angle_deg) * galsim.degrees,
            ).shift(
                self._common_fields.get_world_offset(
                    image_parameters).as_galsim_position()))

        flux_nelec = (self._common_fields.get_flux_nmgy(band_index) *
                      image_parameters.band_nelec_per_nmgy[band_index])
        half_light_radius_deg = self._half_light_radius_arcsec / ARCSEC_PER_DEGREE
        exponential_profile = apply_shear_and_shift(
            galsim.Exponential(
                half_light_radius=half_light_radius_deg,
                flux=flux_nelec * (1 - self._gal_frac_dev),
            ))
        de_vaucouleurs_profile = apply_shear_and_shift(
            galsim.DeVaucouleurs(
                half_light_radius=half_light_radius_deg,
                flux=flux_nelec * self._gal_frac_dev,
            ))
        galaxy = exponential_profile + de_vaucouleurs_profile
        psf = galsim.Gaussian(flux=1, sigma=psf_sigma_degrees)
        return galsim.Convolve([galaxy, psf])
    def _get_dev_model(self, spec):
        obj = galsim.DeVaucouleurs(
            half_light_radius=spec['hlr'],
            flux=spec['Flux'],
        )

        return obj
Exemple #8
0
    def _get_object(self):

        hlr, flux = self._get_hlr_flux()

        disk_hlr = hlr

        if self.g_pdf is None:
            disk_g1, disk_g2 = 0.0, 0.0
        else:
            disk_g1, disk_g2 = self.g_pdf.sample2d()

        all_obj = {}

        if 'bulge' in self['pdfs']:
            hlr_fac, fracdev, gfac, bulge_offset = self._get_bulge_stats()

            bulge_hlr = disk_hlr * hlr_fac
            bulge_g1, bulge_g2 = gfac * disk_g1, gfac * disk_g2

            disk_flux = (1 - fracdev) * flux
            bulge_flux = fracdev * flux

            bulge = galsim.DeVaucouleurs(
                half_light_radius=bulge_hlr,
                flux=bulge_flux,
            ).shear(
                g1=bulge_g1,
                g2=bulge_g2,
            ).shift(
                dx=bulge_offset[1],
                dy=bulge_offset[0],
            )
            all_obj['bulge'] = bulge

        else:
            disk_flux = flux

        disk = galsim.Exponential(
            half_light_radius=disk_hlr,
            flux=disk_flux,
        ).shear(
            g1=disk_g1,
            g2=disk_g2,
        )
        all_obj['disk'] = disk

        if 'knots' in self['pdfs']:
            nknots, knots_flux = self._get_knots_stats(disk_flux)

            knots = galsim.RandomWalk(
                npoints=nknots,
                half_light_radius=disk_hlr,
                flux=knots_flux,
            ).shear(g1=disk_g1, g2=disk_g2)

            all_obj['knots'] = knots

        obj_cen1, obj_cen2 = self.position_pdf.sample()
        all_obj['cen'] = np.array([obj_cen1, obj_cen2])
        return all_obj
Exemple #9
0
    def create_source(self, fractions, half_light_radius,
                      minor_major_axis_ratio, position_angle):
        """Create a model for the on-sky profile of a single source.

        Size and shape parameter values for any component that is not
        present (because its fraction is zero) are ignored.

        Parameters
        ----------
        fractions : array
            Array of length 2 giving the disk and bulge fractions, respectively,
            which must be in the range [0,1] (but this is not checked). If
            their sum is less than one, the remainder is modeled as a point-like
            component.
        half_light_radius : array
            Array of length 2 giving the disk and bulge half-light radii in
            arcseconds, respectively.
        minor_major_axis_ratio : array
            Array of length 2 giving the dimensionless on-sky ellipse
            minor / major axis ratio for the disk and bulge components,
            respectively.
        position_angle : array
            Array of length 2 giving the position angle in degrees of the on-sky
            disk and bluge ellipses, respectively.  Angles are measured counter
            clockwise relative to the +x axis.

        Returns
        -------
        galsim.GSObject
            A object representing the sum of all requested components with its
            total flux normalized to one.
        """
        # This is a no-op but still required to define the namespace.
        import galsim

        components = []
        if fractions[0] > 0:
            # Disk component
            components.append(
                galsim.Exponential(
                    flux=fractions[0],
                    half_light_radius=half_light_radius[0]).shear(
                        q=minor_major_axis_ratio[0],
                        beta=position_angle[0] * galsim.degrees))
        if fractions[1] > 0:
            components.append(
                galsim.DeVaucouleurs(
                    flux=fractions[1],
                    half_light_radius=half_light_radius[1]).shear(
                        q=minor_major_axis_ratio[1],
                        beta=position_angle[1] * galsim.degrees))
        star_fraction = 1 - fractions.sum()
        if star_fraction > 0:
            # Model a point-like source with a tiny (0.001 arcsec) Gaussian.
            # TODO: sigma should be in arcsec here, not microns!
            components.append(
                galsim.Gaussian(flux=star_fraction,
                                sigma=1e-3 * self.image.scale))
        # Combine the components and transform to focal-plane microns.
        return galsim.Add(components, gsparams=self.gsparams)
Exemple #10
0
def test_ne():
    """Test base.py GSObjects for not-equals."""
    # Define some universal gsps
    gsp = galsim.GSParams(maxk_threshold=1.1e-3, folding_threshold=5.1e-3)

    # Sersic.  Params include n, half_light_radius, scale_radius, flux, trunc, flux_untruncated
    # and gsparams.
    # The following should all test unequal:
    gals = [galsim.Sersic(n=1.1, half_light_radius=1.0),
            galsim.Sersic(n=1.2, half_light_radius=1.0),
            galsim.Sersic(n=1.1, half_light_radius=1.1),
            galsim.Sersic(n=1.1, scale_radius=1.0),
            galsim.Sersic(n=1.1, half_light_radius=1.0, flux=1.1),
            galsim.Sersic(n=1.1, half_light_radius=1.0, trunc=1.8),
            galsim.Sersic(n=1.1, half_light_radius=1.0, trunc=1.8, flux_untruncated=True),
            galsim.Sersic(n=1.1, half_light_radius=1.0, gsparams=gsp)]
    all_obj_diff(gals)

    # DeVaucouleurs.  Params include half_light_radius, scale_radius, flux, trunc, flux_untruncated,
    # and gsparams.
    # The following should all test unequal:
    gals = [galsim.DeVaucouleurs(half_light_radius=1.0),
            galsim.DeVaucouleurs(half_light_radius=1.1),
            galsim.DeVaucouleurs(scale_radius=1.0),
            galsim.DeVaucouleurs(half_light_radius=1.0, flux=1.1),
            galsim.DeVaucouleurs(half_light_radius=1.0, trunc=2.0),
            galsim.DeVaucouleurs(half_light_radius=1.0, trunc=2.0, flux_untruncated=True),
            galsim.DeVaucouleurs(half_light_radius=1.0, gsparams=gsp)]
    all_obj_diff(gals)
Exemple #11
0
def test_knots_hlr():
    """
    Create a random walk galaxy and test that the half light radius
    is consistent with the requested value

    Note for DeV profile we don't test npoints=3 because it fails
    """

    # for checking accuracy, we need expected standard deviation of
    # the result
    interp_npts = np.array(
        [6, 7, 8, 9, 10, 15, 20, 30, 50, 75, 100, 150, 200, 500, 1000])
    interp_hlr = np.array([
        7.511, 7.597, 7.647, 7.68, 7.727, 7.827, 7.884, 7.936, 7.974, 8.0,
        8.015, 8.019, 8.031, 8.027, 8.043
    ]) / 8.0
    interp_std = np.array([
        2.043, 2.029, 1.828, 1.817, 1.67, 1.443, 1.235, 1.017, 0.8046, 0.6628,
        0.5727, 0.4703, 0.4047, 0.255, 0.1851
    ]) / 8.0

    hlr = 8.0

    # test these npoints
    npt_vals = [3, 10, 30, 60, 100, 1000]

    # should be within 5 sigma
    nstd = 5

    # number of trials
    ntrial_vals = [100] * len(npt_vals)

    profs = [
        galsim.Gaussian(half_light_radius=hlr),
        galsim.Exponential(half_light_radius=hlr),
        galsim.DeVaucouleurs(half_light_radius=hlr),
    ]
    for prof in profs:
        for ipts, npoints in enumerate(npt_vals):

            # DeV profile will fail for npoints==3
            if isinstance(prof, galsim.DeVaucouleurs) and npoints == 3:
                continue

            ntrial = ntrial_vals[ipts]

            hlr_calc = np.zeros(ntrial)
            for i in range(ntrial):
                #rw=galsim.RandomKnots(npoints, hlr)
                rw = galsim.RandomKnots(npoints, profile=prof)
                hlr_calc[i] = rw.calculateHLR()

            mn = hlr_calc.mean()

            std_check = np.interp(npoints, interp_npts, interp_std * hlr)
            mess = "hlr for npoints: %d outside of expected range" % npoints
            assert abs(mn - hlr) < nstd * std_check, mess
Exemple #12
0
def test_sersic_flux_scaling():
    """Test flux scaling for Sersic.
    """
    # decimal point to go to for parameter value comparisons
    param_decimal = 12
    test_hlr = 1.8
    test_flux = 17.9
    test_sersic_trunc = [0., 8.5]

    if __name__ != "__main__":
        # If doing a pytest run, we don't actually need to do all 4 sersic n values.
        # Two should be enough to notice if there is a problem, and the full list will be tested
        # when running python test_base.py to try to diagnose the problem.
        test_sersic_n = [1.5, -4]
    else:
        test_sersic_n = [1.5, 2.5, 4, -4]  # -4 means use explicit DeVauc rather than n=4

    # loop through sersic n
    for test_n in test_sersic_n:
        # loop through sersic truncation
        for test_trunc in test_sersic_trunc:
            # init with hlr and flux only (should be ok given last tests)
            # n=-4 is code to use explicit DeVaucouleurs rather than Sersic(n=4).
            # It should be identical.
            if test_n == -4:
                init_obj = galsim.DeVaucouleurs(half_light_radius=test_hlr, flux=test_flux,
                                           trunc=test_trunc)
            else:
                init_obj = galsim.Sersic(test_n, half_light_radius=test_hlr, flux=test_flux,
                                    trunc=test_trunc)

            obj2 = init_obj * 2.
            np.testing.assert_almost_equal(
                init_obj.flux, test_flux, decimal=param_decimal,
                err_msg="Flux param inconsistent after __rmul__ (original).")
            np.testing.assert_almost_equal(
                obj2.flux, test_flux * 2., decimal=param_decimal,
                err_msg="Flux param inconsistent after __rmul__ (result).")

            obj2 = 2. * init_obj
            np.testing.assert_almost_equal(
                init_obj.flux, test_flux, decimal=param_decimal,
                err_msg="Flux param inconsistent after __mul__ (original).")
            np.testing.assert_almost_equal(
                obj2.flux, test_flux * 2., decimal=param_decimal,
                err_msg="Flux param inconsistent after __mul__ (result).")

            obj2 = init_obj / 2.
            np.testing.assert_almost_equal(
                 init_obj.flux, test_flux, decimal=param_decimal,
                 err_msg="Flux param inconsistent after __div__ (original).")
            np.testing.assert_almost_equal(
                obj2.flux, test_flux / 2., decimal=param_decimal,
                err_msg="Flux param inconsistent after __div__ (result).")
Exemple #13
0
    def __init__(self, identifier, redshift, ab_magnitude, ri_color,
                 cosmic_shear_g1, cosmic_shear_g2, dx_arcsecs, dy_arcsecs,
                 beta_radians, disk_flux, disk_hlr_arcsecs, disk_q, bulge_flux,
                 bulge_hlr_arcsecs, bulge_q, agn_flux):
        self.identifier = identifier
        self.redshift = redshift
        self.ab_magnitude = ab_magnitude
        self.ri_color = ri_color
        self.dx_arcsecs = dx_arcsecs
        self.dy_arcsecs = dy_arcsecs
        self.cosmic_shear_g1 = cosmic_shear_g1
        self.cosmic_shear_g2 = cosmic_shear_g2
        components = []
        # Initialize second-moments tensor. Note that we can only add the tensors for the
        # n = 1,4 components, as we do below, since they have the same centroid.
        self.second_moments = np.zeros((2, 2))
        total_flux = disk_flux + bulge_flux + agn_flux
        self.disk_fraction = disk_flux / total_flux
        self.bulge_fraction = bulge_flux / total_flux
        if disk_flux > 0:
            disk = galsim.Exponential(
                flux=disk_flux, half_light_radius=disk_hlr_arcsecs).shear(
                    q=disk_q, beta=beta_radians * galsim.radians)
            components.append(disk)
            self.second_moments += self.disk_fraction * sersic_second_moments(
                n=1, hlr=disk_hlr_arcsecs, q=disk_q, beta=beta_radians)

        if bulge_flux > 0:
            bulge = galsim.DeVaucouleurs(
                flux=bulge_flux, half_light_radius=bulge_hlr_arcsecs).shear(
                    q=bulge_q, beta=beta_radians * galsim.radians)
            components.append(bulge)
            self.second_moments += self.bulge_fraction * sersic_second_moments(
                n=1, hlr=bulge_hlr_arcsecs, q=bulge_q, beta=beta_radians)
        # GalSim does not currently provide a "delta-function" component to model the AGN
        # so we use a very narrow Gaussian. See this GalSim issue for details:
        # https://github.com/GalSim-developers/GalSim/issues/533
        if agn_flux > 0:
            agn = galsim.Gaussian(flux=agn_flux, sigma=1e-8)
            components.append(agn)

        # Combine the components into our final profile.
        self.profile = galsim.Add(components)
        # Apply transforms to build the final model.

        self.model = self.get_transformed_model()

        # Shear the second moments, if necessary.
        if self.cosmic_shear_g1 != 0 or self.cosmic_shear_g2 != 0:
            self.second_moments = sheared_second_moments(
                self.second_moments, self.cosmic_shear_g1,
                self.cosmic_shear_g2)
Exemple #14
0
def test_hsmparams():
    """Test the ability to set/change parameters that define how moments/shape estimation are done."""
    import time
    t1 = time.time()

    # First make some profile, and make sure that we get the same answers when we specify default
    # hsmparams or don't specify hsmparams at all.
    default_hsmparams = galsim.hsm.HSMParams(nsig_rg=3.0,
                                             nsig_rg2=3.6,
                                             max_moment_nsig2=25.0,
                                             regauss_too_small=1,
                                             adapt_order=2,
                                             max_mom2_iter=400,
                                             num_iter_default=-1,
                                             bound_correct_wt=0.25,
                                             max_amoment=8000.,
                                             max_ashift=15.,
                                             ksb_moments_max=4,
                                             failed_moments=-1000.)
    bulge = galsim.DeVaucouleurs(half_light_radius = 0.3)
    disk = galsim.Exponential(half_light_radius = 0.5)
    disk.applyShear(e1=0.2, e2=-0.3)
    psf = galsim.Kolmogorov(fwhm = 0.6)
    pix = galsim.Pixel(0.18)
    gal = bulge + disk   # equal weighting, i.e., B/T=0.5
    tot_gal = galsim.Convolve(gal, psf, pix)
    tot_psf = galsim.Convolve(psf, pix)
    tot_gal_image = tot_gal.draw(dx=0.18)
    tot_psf_image = tot_psf.draw(dx=0.18)

    res = tot_gal_image.FindAdaptiveMom()
    res_def = tot_gal_image.FindAdaptiveMom(hsmparams = default_hsmparams)
    assert(equal_hsmshapedata(res, res_def)), 'Moment outputs differ when using default HSMParams'

    res2 = galsim.hsm.EstimateShear(tot_gal_image, tot_psf_image)
    res2_def = galsim.hsm.EstimateShear(tot_gal_image, tot_psf_image, hsmparams = default_hsmparams)
    assert(equal_hsmshapedata(res, res_def)), 'Shear outputs differ when using default HSMParams'

    try:
        # Then check failure modes: force it to fail by changing HSMParams.
        new_params_niter = galsim.hsm.HSMParams(max_mom2_iter = res.moments_n_iter-1)
        new_params_size = galsim.hsm.HSMParams(max_amoment = 0.3*res.moments_sigma**2)
        np.testing.assert_raises(RuntimeError, galsim.hsm.FindAdaptiveMom, tot_gal_image,
                                 hsmparams=new_params_niter)
        np.testing.assert_raises(RuntimeError, galsim.hsm.EstimateShear, tot_gal_image,
                                 tot_psf_image, hsmparams=new_params_size)
    except ImportError:
        print 'The assert_raises tests require nose'

    t2 = time.time()
    print 'time for %s = %.2f'%(funcname(),t2-t1)
Exemple #15
0
def test_sersic_shoot():
    """Test Sersic with photon shooting.  Particularly the flux of the final image.
    """
    rng = galsim.BaseDeviate(1234)
    obj = galsim.Sersic(n=1.5, half_light_radius=3.5, flux=1.e4)
    im = galsim.Image(100, 100, scale=1)
    im.setCenter(0, 0)
    added_flux, photons = obj.drawPhot(im,
                                       poisson_flux=False,
                                       rng=rng.duplicate())
    print('obj.flux = ', obj.flux)
    print('added_flux = ', added_flux)
    print('photon fluxes = ', photons.flux.min(), '..', photons.flux.max())
    print('image flux = ', im.array.sum())
    assert np.isclose(added_flux, obj.flux)
    assert np.isclose(im.array.sum(), obj.flux)
    photons2 = obj.makePhot(poisson_flux=False, rng=rng)
    assert photons2 == photons, "Sersic makePhot not equivalent to drawPhot"

    obj = galsim.DeVaucouleurs(half_light_radius=3.5, flux=1.e4)
    # Need a larger image for devauc wings
    im = galsim.Image(1000, 1000, scale=1)
    im.setCenter(0, 0)
    added_flux, photons = obj.drawPhot(im,
                                       poisson_flux=False,
                                       rng=rng.duplicate())
    print('obj.flux = ', obj.flux)
    print('added_flux = ', added_flux)
    print('photon fluxes = ', photons.flux.min(), '..', photons.flux.max())
    print('image flux = ', im.array.sum())
    assert np.isclose(added_flux, obj.flux)
    assert np.isclose(im.array.sum(), obj.flux)
    photons2 = obj.makePhot(poisson_flux=False, rng=rng)
    assert photons2 == photons, "Sersic makePhot not equivalent to drawPhot"

    # Can do up to around n=6 with this image if hlr is smaller.
    obj = galsim.Sersic(half_light_radius=0.9, n=6.2, flux=1.e4)
    added_flux, photons = obj.drawPhot(im,
                                       poisson_flux=False,
                                       rng=rng.duplicate())
    print('obj.flux = ', obj.flux)
    print('added_flux = ', added_flux)
    print('photon fluxes = ', photons.flux.min(), '..', photons.flux.max())
    print('image flux = ', im.array.sum())
    assert np.isclose(added_flux, obj.flux)
    assert np.isclose(im.array.sum(), obj.flux)
    photons2 = obj.makePhot(poisson_flux=False, rng=rng)
    assert photons2 == photons, "Sersic makePhot not equivalent to drawPhot"
Exemple #16
0
def test_devaucouleurs():
    """Test various ways to build a DeVaucouleurs
    """
    config = {
        'gal1' : { 'type' : 'DeVaucouleurs' , 'half_light_radius' : 2 },
        'gal2' : { 'type' : 'DeVaucouleurs' , 'half_light_radius' : 1.7, 'flux' : 100 },
        'gal3' : { 'type' : 'DeVaucouleurs' , 'half_light_radius' : 3.5, 'flux' : 1.e6,
                   'ellip' : { 'type' : 'QBeta' , 'q' : 0.6, 'beta' : 0.39 * galsim.radians }
                 },
        'gal4' : { 'type' : 'DeVaucouleurs' , 'half_light_radius' : 1, 'flux' : 50,
                   'dilate' : 3, 'ellip' : galsim.Shear(e1=0.3),
                   'rotate' : 12 * galsim.degrees,
                   'magnify' : 1.03, 'shear' : galsim.Shear(g1=0.03, g2=-0.05),
                   'shift' : { 'type' : 'XY', 'x' : 0.7, 'y' : -1.2 }
                 },
        'gal5' : { 'type' : 'DeVaucouleurs' , 'half_light_radius' : 1, 'flux' : 50,
                   'gsparams' : { 'folding_threshold' : 1.e-4 }
                 }
    }

    gal1a = galsim.config.BuildGSObject(config, 'gal1')[0]
    gal1b = galsim.DeVaucouleurs(half_light_radius = 2)
    gsobject_compare(gal1a, gal1b)

    gal2a = galsim.config.BuildGSObject(config, 'gal2')[0]
    gal2b = galsim.DeVaucouleurs(half_light_radius = 1.7, flux = 100)
    gsobject_compare(gal2a, gal2b)

    gal3a = galsim.config.BuildGSObject(config, 'gal3')[0]
    gal3b = galsim.DeVaucouleurs(half_light_radius = 3.5, flux = 1.e6)
    gal3b = gal3b.shear(q = 0.6, beta = 0.39 * galsim.radians)
    gsobject_compare(gal3a, gal3b)

    gal4a = galsim.config.BuildGSObject(config, 'gal4')[0]
    gal4b = galsim.DeVaucouleurs(half_light_radius = 1, flux = 50)
    gal4b = gal4b.dilate(3).shear(e1 = 0.3).rotate(12 * galsim.degrees).magnify(1.03)
    gal4b = gal4b.shear(g1 = 0.03, g2 = -0.05).shift(dx = 0.7, dy = -1.2)
    gsobject_compare(gal4a, gal4b)

    gal5a = galsim.config.BuildGSObject(config, 'gal5')[0]
    gsparams = galsim.GSParams(folding_threshold=1.e-4)
    gal5b = galsim.DeVaucouleurs(half_light_radius=1, flux=50, gsparams=gsparams)
    gsobject_compare(gal5a, gal5b, conv=galsim.Gaussian(sigma=1))

    try:
        # Make sure they don't match when using the default GSParams
        gal5c = galsim.DeVaucouleurs(half_light_radius=1, flux=50)
        np.testing.assert_raises(AssertionError,gsobject_compare, gal5a, gal5c,
                                 conv=galsim.Gaussian(sigma=1))
    except ImportError:
        print('The assert_raises tests require nose')
Exemple #17
0
    def render_galaxy(
        self,
        galaxy_params: Tensor,
        psf: galsim.GSObject,
        slen: int,
        offset: Optional[Tensor] = None,
    ) -> Tensor:
        assert offset is None or offset.shape == (2, )
        if isinstance(galaxy_params, Tensor):
            galaxy_params = galaxy_params.cpu().detach()
        total_flux, disk_frac, beta_radians, disk_q, a_d, bulge_q, a_b = galaxy_params
        bulge_frac = 1 - disk_frac

        disk_flux = total_flux * disk_frac
        bulge_flux = total_flux * bulge_frac

        components = []
        if disk_flux > 0:
            b_d = a_d * disk_q
            disk_hlr_arcsecs = np.sqrt(a_d * b_d)
            disk = galsim.Exponential(
                flux=disk_flux, half_light_radius=disk_hlr_arcsecs).shear(
                    q=disk_q,
                    beta=beta_radians * galsim.radians,
                )
            components.append(disk)
        if bulge_flux > 0:
            b_b = bulge_q * a_b
            bulge_hlr_arcsecs = np.sqrt(a_b * b_b)
            bulge = galsim.DeVaucouleurs(
                flux=bulge_flux, half_light_radius=bulge_hlr_arcsecs).shear(
                    q=bulge_q, beta=beta_radians * galsim.radians)
            components.append(bulge)
        galaxy = galsim.Add(components)
        gal_conv = galsim.Convolution(galaxy, psf)
        offset = offset if offset is None else offset.numpy()
        image = gal_conv.drawImage(nx=slen,
                                   ny=slen,
                                   method="auto",
                                   scale=self.pixel_scale,
                                   offset=offset)
        return torch.from_numpy(image.array).reshape(1, slen, slen)
    def _get_bd_model(self, spec):
        rng = self.rng

        flux = spec['Flux']

        fracdev = rng.uniform(low=0.0, high=1.0)

        bulge_flux = fracdev * flux
        disk_flux = (1.0 - fracdev) * flux

        disk_hlr = spec['hlr']
        if 'bulge_size_factor' in spec:
            frange = spec['bulge_size_factor']['range']
            bulge_hlr = disk_hlr * rng.uniform(
                low=frange[0],
                high=frange[1],
            )
        else:
            bulge_hlr = disk_hlr

        if 'knots' in spec:
            disk_flux, knot_flux = self._split_flux_with_knots(spec, disk_flux)

        disk = galsim.Exponential(
            half_light_radius=disk_hlr,
            flux=disk_flux,
        )
        bulge = galsim.DeVaucouleurs(
            half_light_radius=bulge_hlr,
            flux=bulge_flux,
        )

        if 'knots' in spec:
            knots = self._get_knots(spec, disk_hlr, knot_flux)
            disk = galsim.Add([disk, knots])

        disk = self._add_ellipticity(disk, spec)
        bulge = self._add_ellipticity(bulge, spec)

        return galsim.Add([disk, bulge])
Exemple #19
0
def main():

    p = get_params()

    rng = galsim.UniformDeviate(p.random_seed)

    #where to save images
    image_dir = os.path.join('/home', 'ckrawiec', 'sims', 'images')

    target_file_name = "stamps_{0}_.fits".format(p.id)
    template_file_name = "template_stamps_{0}_.fits".format(p.id)

    if p.noise_suppression == False:
        gal_name = os.path.splitext(target_file_name)
    else:
        gal_name = os.path.splitext(template_file_name)

    #initial noise
    noise = galsim.GaussianNoise(rng)

    #create test image to determine noise level
    if p.noise_suppression == False:
        test_psf = galsim.Moffat(3.5,
                                 half_light_radius=p.psf_hlr * p.pixel_scale)
        test_psf = test_psf.shear(e2=p.psf_e2)

        test_bulge = galsim.DeVaucouleurs(half_light_radius=(
            (p.gal_hlr_max - p.gal_hlr_min) / 2. + p.gal_hlr_min) *
                                          p.pixel_scale)
        test_disk = galsim.Exponential(half_light_radius=(
            (p.gal_hlr_max - p.gal_hlr_min) / 2. + p.gal_hlr_min) *
                                       p.pixel_scale)
        test_gal = 0.5 * test_bulge + 0.5 * test_disk
        test_gal = test_gal.withFlux(p.gal_flux_min)

        test_image = galsim.ImageF(p.stamp_size,
                                   p.stamp_size,
                                   scale=p.pixel_scale)

        test_final = galsim.Convolve([test_psf, test_gal])
        test_final.drawImage(test_image)

        noise_var = test_image.addNoiseSNR(noise,
                                           p.gal_snr_min,
                                           preserve_flux=True)
        print noise_var

        #final noise
        noise = galsim.GaussianNoise(rng, sigma=np.sqrt(noise_var))

    #make galaxy image
    gal_image = galsim.ImageF(p.nx_tiles * p.stamp_size,
                              p.ny_tiles * p.stamp_size,
                              scale=p.pixel_scale)

    #make ellipticity distribution from sigma
    ellip_dist = BobsEDist(p.gal_ellip_sigma, rng)

    for ifile in range(p.n_files):
        #all files have same psf
        psf = galsim.Moffat(3.5, half_light_radius=p.psf_hlr * p.pixel_scale)
        psf = psf.shear(e2=p.psf_e2)
        psf_image = galsim.ImageF(p.stamp_size,
                                  p.stamp_size,
                                  scale=p.pixel_scale)
        psf.drawImage(psf_image)

        for iy in range(p.ny_tiles):
            for ix in range(p.nx_tiles):

                b = galsim.BoundsI(ix * p.stamp_size + 1,
                                   (ix + 1) * p.stamp_size,
                                   iy * p.stamp_size + 1,
                                   (iy + 1) * p.stamp_size)
                sub_gal_image = gal_image[b]

                hlr = (rng() * (p.gal_hlr_max - p.gal_hlr_min) +
                       p.gal_hlr_min) * p.pixel_scale
                flux = rng() * (p.gal_flux_max -
                                p.gal_flux_min) + p.gal_flux_min
                bulge_frac = rng()

                e1, e2 = ellip_dist.sample()

                #galaxy = ExponentialDisk + DeVaucouleurs
                this_bulge = galsim.DeVaucouleurs(half_light_radius=hlr)
                this_disk = galsim.Exponential(half_light_radius=hlr)

                #same ellipticity
                this_bulge = this_bulge.shear(e1=e1, e2=e2)
                this_disk = this_disk.shear(e1=e1, e2=e2)

                #Apply a shift in disk center within one pixel
                shift_r = p.pixel_scale / 2.
                dx = shift_r * (rng() * 2. - 1.)
                dy = shift_r * (rng() * 2. - 1.)
                this_disk = this_disk.shift(dx, dy)

                #Apply a shift in bulge center within circle of radius hlr
                theta = rng() * 2. * np.pi
                r = rng() * hlr
                dx = r * np.cos(theta)
                dy = r * np.sin(theta)
                this_bulge = this_bulge.shift(dx, dy)

                this_gal = bulge_frac * this_bulge + (1 -
                                                      bulge_frac) * this_disk
                this_gal = this_gal.withFlux(flux)

                #All galaxies have same applied shear
                this_gal = this_gal.shear(g1=p.g1, g2=p.g2)

                final = galsim.Convolve([psf, this_gal])

                final.drawImage(sub_gal_image)

                if p.noise_suppression == False:
                    sub_gal_image.addNoise(noise)

        gal_file = os.path.join(
            image_dir,
            ''.join([gal_name[0],
                     str(ifile + 1).zfill(2), gal_name[1]]))
        psf_file = os.path.join(
            image_dir, ''.join([gal_name[0],
                                str(ifile + 1).zfill(2), '.psf']))
        gal_image.write(gal_file)
        psf_image.write(psf_file)
Exemple #20
0
    if (abs((e10[i]**2) * (e20[i]**2)) > 1.0):
        e10[i] = 0.0
        e20[i] = 0.0

gsparams=galsim.GSParams(folding_threshold=1.e-2,maxk_threshold=2.e-3,\
                         xvalue_accuracy=1.e-4,kvalue_accuracy=1.e-4,\
                         shoot_accuracy=1.e-4,minimum_fft_size=64)

#psf1=galsim.Moffat(fwhm=psf_fwhm[0],beta=2.5,gsparams=gsparams) #to be continue
#psf1=psf1.shear(e1=e1_psf,e2=e2_psf)
psf1 = galsim.Gaussian(fwhm=psf_fwhm[0], gsparams=gsparams)

#psf1=galsim.Kolmogorov(fwhm=psf_fwhm[0],gsparams=gsparams)
gal1 = galsim.Gaussian(half_light_radius=2, gsparams=gsparams)
gal2 = galsim.Exponential(half_light_radius=1, gsparams=gsparams)
gal3 = galsim.DeVaucouleurs(half_light_radius=1, gsparams=gsparams)
gal4 = galsim.Sersic(half_light_radius=1, n=2.5,
                     gsparams=gsparams)  #to be continue

psf = psf1
final_epsf_image = psf1.drawImage(scale=pixel_scale)
gal = [gal1, gal2, gal3, gal4]
for i in range(m):
    BJe1array = [[], [], [], []]
    BJe2array = [[], [], [], []]
    RGe1array = [[], [], [], []]
    RGe2array = [[], [], [], []]
    Me1array = [[], [], [], []]
    Me2array = [[], [], [], []]
    for j in range(4):
        for p in range(2):
Exemple #21
0
of the LSST stack.  But it's still better to save the script as
well, even if it can't usually be run.
"""

import galsim
import lsst.shapelet.tractor

GALAXY_RADIUS = 8.0
PSF_SIGMA = 2.0
E1 = 0.3
E2 = -0.2
PROFILES = [
    ("exp", galsim.Exponential(half_light_radius=GALAXY_RADIUS), 9, 8),
    ("ser2", galsim.Sersic(n=2.0, half_light_radius=GALAXY_RADIUS), 9, 8),
    ("ser3", galsim.Sersic(n=3.0, half_light_radius=GALAXY_RADIUS), 9, 8),
    ("dev", galsim.DeVaucouleurs(half_light_radius=GALAXY_RADIUS), 9, 8),
]

MAKE_COMPONENT_IMAGES = False


def makeGaussian(flux, e1, e2, sigma):
    g = galsim.Gaussian(flux=flux, sigma=sigma)
    g.applyShear(e1=e1, e2=e2)
    return g


def main():
    for profile, exactGal, nComponents, maxRadius in PROFILES:
        exactGal.applyShear(e1=E1, e2=E2)
        psf = galsim.Gaussian(sigma=PSF_SIGMA)
Exemple #22
0
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)
Exemple #23
0
def main(argv):
    # Where to find and output data
    path, filename = os.path.split(__file__)
    datapath = os.path.abspath(os.path.join(path, "data/"))
    outpath = os.path.abspath(os.path.join(path, "output/"))

    # In non-script code, use getLogger(__name__) at module scope instead.
    logging.basicConfig(format="%(message)s",
                        level=logging.INFO,
                        stream=sys.stdout)
    logger = logging.getLogger("demo12")

    # initialize (pseudo-)random number generator
    random_seed = 1234567
    rng = galsim.BaseDeviate(random_seed)

    # read in SEDs
    SED_names = ['CWW_E_ext', 'CWW_Sbc_ext', 'CWW_Scd_ext', 'CWW_Im_ext']
    SEDs = {}
    for SED_name in SED_names:
        SED_filename = os.path.join(galsim.meta_data.share_dir,
                                    '{0}.sed'.format(SED_name))
        # Here we create some galsim.SED objects to hold star or galaxy spectra.  The most
        # convenient way to create realistic spectra is to read them in from a two-column ASCII
        # file, where the first column is wavelength and the second column is flux. Wavelengths in
        # the example SED files are in Angstroms, flux in flambda.  We use a set of files that are
        # distributed with GalSim in the share/ directory.
        SED = galsim.SED(SED_filename, wave_type='Ang', flux_type='flambda')
        # The normalization of SEDs affects how many photons are eventually drawn into an image.
        # One way to control this normalization is to specify the flux density in photons per nm
        # at a particular wavelength.  For example, here we normalize such that the photon density
        # is 1 photon per nm at 500 nm.
        SEDs[SED_name] = SED.withFluxDensity(target_flux_density=1.0,
                                             wavelength=500)
    logger.debug('Successfully read in SEDs')

    # read in the LSST filters
    filter_names = 'ugrizy'
    filters = {}
    for filter_name in filter_names:
        filter_filename = os.path.join(datapath,
                                       'LSST_{0}.dat'.format(filter_name))
        # Here we create some galsim.Bandpass objects to represent the filters we're observing
        # through.  These include the entire imaging system throughput including the atmosphere,
        # reflective and refractive optics, filters, and the CCD quantum efficiency.  These are
        # also conveniently read in from two-column ASCII files where the first column is
        # wavelength and the second column is dimensionless throughput. The example filter files
        # units of nanometers for the wavelength type, so we specify that using the required
        # `wave_type` argument.
        filters[filter_name] = galsim.Bandpass(filter_filename, wave_type='nm')
        # For speed, we can thin out the wavelength sampling of the filter a bit.
        # In the following line, `rel_err` specifies the relative error when integrating over just
        # the filter (however, this is not necessarily the relative error when integrating over the
        # filter times an SED).
        filters[filter_name] = filters[filter_name].thin(rel_err=1e-4)
    logger.debug('Read in filters')

    pixel_scale = 0.2  # arcseconds

    #-----------------------------------------------------------------------------------------------
    # Part A: chromatic de Vaucouleurs galaxy

    # Here we create a chromatic version of a de Vaucouleurs profile using the Chromatic class.
    # This class lets one create chromatic versions of any galsim GSObject class.  The first
    # argument is the GSObject instance to be chromaticized, and the second argument is the
    # profile's SED.

    logger.info('')
    logger.info('Starting part A: chromatic De Vaucouleurs galaxy')
    redshift = 0.8
    mono_gal = galsim.DeVaucouleurs(half_light_radius=0.5)
    SED = SEDs['CWW_E_ext'].atRedshift(redshift)
    gal = galsim.Chromatic(mono_gal, SED)

    # You can still shear, shift, and dilate the resulting chromatic object.
    gal = gal.shear(g1=0.5, g2=0.3).dilate(1.05).shift((0.0, 0.1))
    logger.debug('Created Chromatic')

    # convolve with PSF to make final profile
    PSF = galsim.Moffat(fwhm=0.6, beta=2.5)
    final = galsim.Convolve([gal, PSF])
    logger.debug('Created final profile')

    # draw profile through LSST filters
    gaussian_noise = galsim.GaussianNoise(rng, sigma=0.1)
    for filter_name, filter_ in filters.iteritems():
        img = galsim.ImageF(64, 64, scale=pixel_scale)
        final.drawImage(filter_, image=img)
        img.addNoise(gaussian_noise)
        logger.debug('Created {0}-band image'.format(filter_name))
        out_filename = os.path.join(outpath,
                                    'demo12a_{0}.fits'.format(filter_name))
        galsim.fits.write(img, out_filename)
        logger.debug('Wrote {0}-band image to disk'.format(filter_name))
        logger.info('Added flux for {0}-band image: {1}'.format(
            filter_name, img.added_flux))

    logger.info(
        'You can display the output in ds9 with a command line that looks something like:'
    )
    logger.info(
        'ds9 output/demo12a_*.fits -match scale -zoom 2 -match frame image &')

    #-----------------------------------------------------------------------------------------------
    # Part B: chromatic bulge+disk galaxy

    logger.info('')
    logger.info('Starting part B: chromatic bulge+disk galaxy')
    redshift = 0.8
    # make a bulge ...
    mono_bulge = galsim.DeVaucouleurs(half_light_radius=0.5)
    bulge_SED = SEDs['CWW_E_ext'].atRedshift(redshift)
    # The `*` operator can be used as a shortcut for creating a chromatic version of a GSObject:
    bulge = mono_bulge * bulge_SED
    bulge = bulge.shear(g1=0.12, g2=0.07)
    logger.debug('Created bulge component')
    # ... and a disk ...
    mono_disk = galsim.Exponential(half_light_radius=2.0)
    disk_SED = SEDs['CWW_Im_ext'].atRedshift(redshift)
    disk = mono_disk * disk_SED
    disk = disk.shear(g1=0.4, g2=0.2)
    logger.debug('Created disk component')
    # ... and then combine them.
    bdgal = 1.1 * (
        0.8 * bulge + 4 * disk
    )  # you can add and multiply ChromaticObjects just like GSObjects
    bdfinal = galsim.Convolve([bdgal, PSF])
    # Note that at this stage, our galaxy is chromatic but our PSF is still achromatic.  Part C)
    # below will dive into chromatic PSFs.
    logger.debug('Created bulge+disk galaxy final profile')

    # draw profile through LSST filters
    gaussian_noise = galsim.GaussianNoise(rng, sigma=0.02)
    for filter_name, filter_ in filters.iteritems():
        img = galsim.ImageF(64, 64, scale=pixel_scale)
        bdfinal.drawImage(filter_, image=img)
        img.addNoise(gaussian_noise)
        logger.debug('Created {0}-band image'.format(filter_name))
        out_filename = os.path.join(outpath,
                                    'demo12b_{0}.fits'.format(filter_name))
        galsim.fits.write(img, out_filename)
        logger.debug('Wrote {0}-band image to disk'.format(filter_name))
        logger.info('Added flux for {0}-band image: {1}'.format(
            filter_name, img.added_flux))

    logger.info(
        'You can display the output in ds9 with a command line that looks something like:'
    )
    logger.info(
        'ds9 -rgb -blue -scale limits -0.2 0.8 output/demo12b_r.fits -green -scale limits'
        +
        ' -0.25 1.0 output/demo12b_i.fits -red -scale limits -0.25 1.0 output/demo12b_z.fits'
        + ' -zoom 2 &')

    #-----------------------------------------------------------------------------------------------
    # Part C: chromatic PSF

    logger.info('')
    logger.info('Starting part C: chromatic PSF')
    redshift = 0.0
    mono_gal = galsim.Exponential(half_light_radius=0.5)
    SED = SEDs['CWW_Im_ext'].atRedshift(redshift)
    # Here's another way to set the normalization of the SED.  If we want 50 counts to be drawn
    # when observing an object with this SED through the LSST g-band filter, for instance, then we
    # can do:
    SED = SED.withFlux(50.0, filters['g'])
    # The flux drawn through other bands, which sample different parts of the SED and have different
    # throughputs, will, of course, be different.
    gal = mono_gal * SED
    gal = gal.shear(g1=0.5, g2=0.3)
    logger.debug('Created `Chromatic` galaxy')

    # For a ground-based PSF, two chromatic effects are introduced by the atmosphere:
    # (i) differential chromatic refraction (DCR), and (ii) wavelength-dependent seeing.
    #
    # DCR shifts the position of the PSF as a function of wavelength.  Blue light is shifted
    # toward the zenith slightly more than red light.
    #
    # Kolmogorov turbulence in the atmosphere leads to a seeing size (e.g., FWHM) that scales with
    # wavelength to the (-0.2) power.
    #
    # The ChromaticAtmosphere function will attach both of these effects to a fiducial PSF at
    # some fiducial wavelength.

    # First we define a monochromatic PSF to be the fiducial PSF.
    PSF_500 = galsim.Moffat(beta=2.5, fwhm=0.5)
    # Then we use ChromaticAtmosphere to manipulate this fiducial PSF as a function of wavelength.
    # ChromaticAtmosphere also needs to know the wavelength of the fiducial PSF, and the location
    # and orientation of the object with respect to the zenith.  This final piece of information
    # can be specified in several ways (see the ChromaticAtmosphere docstring for all of them).
    # Here are a couple ways: let's pretend our object is located near M101 on the sky, we observe
    # it 1 hour before it transits and we're observing from Mauna Kea.
    ra = galsim.HMS_Angle("14:03:13")  # hours : minutes : seconds
    dec = galsim.DMS_Angle("54:20:57")  # degrees : minutes : seconds
    m101 = galsim.CelestialCoord(ra, dec)
    latitude = 19.8207 * galsim.degrees  # latitude of Mauna Kea
    HA = -1.0 * galsim.hours  # Hour angle = one hour before transit

    # Then we can compute the zenith angle and parallactic angle (which is is the position angle
    # of the zenith measured from North through East) of this object:
    za, pa = galsim.dcr.zenith_parallactic_angles(m101,
                                                  HA=HA,
                                                  latitude=latitude)
    # And then finally, create the chromatic PSF
    PSF = galsim.ChromaticAtmosphere(PSF_500,
                                     500.0,
                                     zenith_angle=za,
                                     parallactic_angle=pa)
    # We could have also just passed `m101`, `latitude` and `HA` to ChromaticAtmosphere directly:
    PSF = galsim.ChromaticAtmosphere(PSF_500,
                                     500.0,
                                     obj_coord=m101,
                                     latitude=latitude,
                                     HA=HA)
    # and proceed like normal.

    # convolve with galaxy to create final profile
    final = galsim.Convolve([gal, PSF])
    logger.debug('Created chromatic PSF finale profile')

    # Draw profile through LSST filters
    gaussian_noise = galsim.GaussianNoise(rng, sigma=0.03)
    for filter_name, filter_ in filters.iteritems():
        img = galsim.ImageF(64, 64, scale=pixel_scale)
        final.drawImage(filter_, image=img)
        img.addNoise(gaussian_noise)
        logger.debug('Created {0}-band image'.format(filter_name))
        out_filename = os.path.join(outpath,
                                    'demo12c_{0}.fits'.format(filter_name))
        galsim.fits.write(img, out_filename)
        logger.debug('Wrote {0}-band image to disk'.format(filter_name))
        logger.info('Added flux for {0}-band image: {1}'.format(
            filter_name, img.added_flux))

    logger.info(
        'You can display the output in ds9 with a command line that looks something like:'
    )
    logger.info(
        'ds9 output/demo12c_*.fits -match scale -zoom 2 -match frame image -blink &'
    )
Exemple #24
0
def main(argv):
    """
    Make a fits image cube where each frame has two images of the same galaxy drawn 
    with regular FFT convolution and with photon shooting.

    We do this for 5 different PSFs and 5 different galaxies, each with 4 different (random)
    fluxes, sizes, and shapes.
    """
    logging.basicConfig(format="%(message)s",
                        level=logging.INFO,
                        stream=sys.stdout)
    logger = logging.getLogger("demo7")

    # To turn off logging:
    #logger.propagate = False

    # Define some parameters we'll use below.

    # Make output directory if not already present.
    if not os.path.isdir('output'):
        os.mkdir('output')

    file_name = os.path.join('output', 'cube_phot.fits.gz')

    random_seed = 553728
    sky_level = 1.e4  # ADU / arcsec^2
    pixel_scale = 0.28  # arcsec
    nx = 64
    ny = 64

    gal_flux_min = 1.e4  # Range for galaxy flux
    gal_flux_max = 1.e5
    gal_hlr_min = 0.3  # arcsec
    gal_hlr_max = 1.3  # arcsec
    gal_e_min = 0.  # Range for ellipticity
    gal_e_max = 0.8

    psf_fwhm = 0.65  # arcsec

    # This script is set up as a comparison between using FFTs for doing the convolutions and
    # shooting photons.  The two methods have trade-offs in speed and accuracy which vary
    # with the kind of profile being drawn and the S/N of the object, among other factors.
    # In addition, for each method, there are a number of parameters GalSim uses that control
    # aspects of the calculation that further affect the speed and accuracy.
    #
    # We encapsulate these parameters with an object called GSParams.  The default values
    # are intended to be accurate enough for normal precision shear tests, without sacrificing
    # too much speed.
    #
    # Any PSF or galaxy object can be given a gsparams argument on construction that can
    # have different values to make the calculation more or less accurate (typically trading
    # off for speed or memory).
    #
    # In this script, we adjust some of the values slightly, just to show you how it works.
    # You could play around with these values and see what effect they have on the drawn images.
    # Usually, it requires a pretty drastic change in these parameters for you to be able to
    # notice the difference by eye.  But subtle effects that may impact the shapes of galaxies
    # can happen well before then.

    # Type help(galsim.GSParams) for the complete list of parameters and more detailed
    # documentation, including the default values for each parameter.
    gsparams = galsim.GSParams(
        alias_threshold=
        1.e-2,  # maximum fractional flux that may be aliased around edge of FFT
        maxk_threshold=
        2.e-3,  # k-values less than this may be excluded off edge of FFT
        xvalue_accuracy=
        1.e-4,  # approximations in real space aim to be this accurate
        kvalue_accuracy=
        1.e-4,  # approximations in fourier space aim to be this accurate
        shoot_accuracy=
        1.e-4,  # approximations in photon shooting aim to be this accurate
        minimum_fft_size=64)  # minimum size of ffts

    logger.info('Starting demo script 7')

    # Make the pixel:
    pix = galsim.Pixel(xw=pixel_scale)

    # Make the PSF profiles:
    psf1 = galsim.Gaussian(fwhm=psf_fwhm, gsparams=gsparams)
    psf2 = galsim.Moffat(fwhm=psf_fwhm, beta=2.4, gsparams=gsparams)
    psf3_inner = galsim.Gaussian(fwhm=psf_fwhm, flux=0.8, gsparams=gsparams)
    psf3_outer = galsim.Gaussian(fwhm=2 * psf_fwhm,
                                 flux=0.2,
                                 gsparams=gsparams)
    psf3 = psf3_inner + psf3_outer
    atmos = galsim.Gaussian(fwhm=psf_fwhm, gsparams=gsparams)
    optics = galsim.OpticalPSF(lam_over_diam=0.6 * psf_fwhm,
                               obscuration=0.4,
                               defocus=0.1,
                               astig1=0.3,
                               astig2=-0.2,
                               coma1=0.2,
                               coma2=0.1,
                               spher=-0.3,
                               gsparams=gsparams)
    psf4 = galsim.Convolve([atmos, optics
                            ])  # Convolve inherits the gsparams from the first
    # item in the list.  (Or you can supply a gsparams
    # argument explicitly if you want to override this.)
    atmos = galsim.Kolmogorov(fwhm=psf_fwhm, gsparams=gsparams)
    optics = galsim.Airy(lam_over_diam=0.3 * psf_fwhm, gsparams=gsparams)
    psf5 = galsim.Convolve([atmos, optics])
    psfs = [psf1, psf2, psf3, psf4, psf5]
    psf_names = [
        "Gaussian", "Moffat", "Double Gaussian", "OpticalPSF",
        "Kolmogorov * Airy"
    ]
    psf_times = [0, 0, 0, 0, 0]
    psf_fft_times = [0, 0, 0, 0, 0]
    psf_phot_times = [0, 0, 0, 0, 0]

    # Make the galaxy profiles:
    gal1 = galsim.Gaussian(half_light_radius=1, gsparams=gsparams)
    gal2 = galsim.Exponential(half_light_radius=1, gsparams=gsparams)
    gal3 = galsim.DeVaucouleurs(half_light_radius=1, gsparams=gsparams)
    gal4 = galsim.Sersic(half_light_radius=1, n=2.5, gsparams=gsparams)
    bulge = galsim.Sersic(half_light_radius=0.7, n=3.2, gsparams=gsparams)
    disk = galsim.Sersic(half_light_radius=1.2, n=1.5, gsparams=gsparams)
    gal5 = 0.4 * bulge + 0.6 * disk  # Net half-light radius is only approximate for this one.
    gals = [gal1, gal2, gal3, gal4, gal5]
    gal_names = [
        "Gaussian", "Exponential", "Devaucouleurs", "n=2.5 Sersic",
        "Bulge + Disk"
    ]
    gal_times = [0, 0, 0, 0, 0]
    gal_fft_times = [0, 0, 0, 0, 0]
    gal_phot_times = [0, 0, 0, 0, 0]

    # Other times to keep track of:
    setup_times = 0
    fft_times = 0
    phot_times = 0
    noise_times = 0

    # Loop over combinations of psf, gal, and make 4 random choices for flux, size, shape.
    all_images = []
    k = 0
    for ipsf in range(len(psfs)):
        psf = psfs[ipsf]
        psf_name = psf_names[ipsf]
        for igal in range(len(gals)):
            gal = gals[igal]
            gal_name = gal_names[igal]
            for i in range(4):
                logger.debug('Start work on image %d', i)
                t1 = time.time()

                # Initialize the random number generator we will be using.
                rng = galsim.UniformDeviate(random_seed + k)

                # Get a new copy, we'll want to keep the original unmodified.
                gal1 = gal.copy()

                # Generate random variates:
                flux = rng() * (gal_flux_max - gal_flux_min) + gal_flux_min
                gal1.setFlux(flux)

                hlr = rng() * (gal_hlr_max - gal_hlr_min) + gal_hlr_min
                gal1.applyDilation(hlr)

                beta_ellip = rng() * 2 * math.pi * galsim.radians
                ellip = rng() * (gal_e_max - gal_e_min) + gal_e_min
                gal_shape = galsim.Shear(e=ellip, beta=beta_ellip)
                gal1.applyShear(gal_shape)

                # Build the final object by convolving the galaxy, PSF and pixel response.
                final = galsim.Convolve([psf, pix, gal1])
                # For photon shooting, need a version without the pixel (see below).
                final_nopix = galsim.Convolve([psf, gal1])

                # Create the large, double width output image
                image = galsim.ImageF(2 * nx + 2, ny)

                # Rather than provide a dx= argument to the draw commands, we can also
                # set the pixel scale in the image itself with setScale.
                image.setScale(pixel_scale)

                # Assign the following two "ImageViews", fft_image and phot_image.
                # Using the syntax below, these are views into the larger image.
                # Changes/additions to the sub-images referenced by the views are automatically
                # reflected in the original image.
                fft_image = image[galsim.BoundsI(1, nx, 1, ny)]
                phot_image = image[galsim.BoundsI(nx + 3, 2 * nx + 2, 1, ny)]

                logger.debug(
                    '   Read in training sample galaxy and PSF from file')
                t2 = time.time()

                # Draw the profile
                final.draw(fft_image)

                logger.debug(
                    '   Drew fft image.  Total drawn flux = %f.  .flux = %f',
                    fft_image.array.sum(), final.getFlux())
                t3 = time.time()

                # Add Poisson noise
                sky_level_pixel = sky_level * pixel_scale**2
                fft_image.addNoise(
                    galsim.PoissonNoise(rng, sky_level=sky_level_pixel))

                t4 = time.time()

                # The next two lines are just to get the output from this demo script
                # to match the output from the parsing of demo7.yaml.
                rng = galsim.UniformDeviate(random_seed + k)
                rng()
                rng()
                rng()
                rng()

                # Repeat for photon shooting image.
                # Photon shooting automatically convolves by the pixel, so we've made sure not
                # to include it in the profile!
                final_nopix.drawShoot(phot_image,
                                      max_extra_noise=sky_level_pixel / 100,
                                      rng=rng)
                t5 = time.time()

                # For photon shooting, galaxy already has Poisson noise, so we want to make
                # sure not to add that noise again!  Thus, we just add sky noise, which
                # is Poisson with the mean = sky_level_pixel
                pd = galsim.PoissonDeviate(rng, mean=sky_level_pixel)
                # DeviateNoise just adds the action of the given deviate to every pixel.
                phot_image.addNoise(galsim.DeviateNoise(pd))
                # For PoissonDeviate, the mean is not zero, so for a background-subtracted
                # image, we need to subtract the mean back off when we are done.
                phot_image -= sky_level_pixel

                logger.debug(
                    '   Added Poisson noise.  Image fluxes are now %f and %f',
                    fft_image.array.sum(), phot_image.array.sum())
                t6 = time.time()

                # Store that into the list of all images
                all_images += [image]

                k = k + 1
                logger.info(
                    '%d: %s * %s, flux = %.2e, hlr = %.2f, ellip = (%.2f,%.2f)',
                    k, gal_name, psf_name, flux, hlr, gal_shape.getE1(),
                    gal_shape.getE2())
                logger.debug('   Times: %f, %f, %f, %f, %f', t2 - t1, t3 - t2,
                             t4 - t3, t5 - t4, t6 - t5)

                psf_times[ipsf] += t6 - t1
                psf_fft_times[ipsf] += t3 - t2
                psf_phot_times[ipsf] += t5 - t4
                gal_times[igal] += t6 - t1
                gal_fft_times[igal] += t3 - t2
                gal_phot_times[igal] += t5 - t4
                setup_times += t2 - t1
                fft_times += t3 - t2
                phot_times += t5 - t4
                noise_times += t4 - t3 + t6 - t5

    logger.info('Done making images of galaxies')
    logger.info('')
    logger.info('Some timing statistics:')
    logger.info('   Total time for setup steps = %f', setup_times)
    logger.info('   Total time for regular fft drawing = %f', fft_times)
    logger.info('   Total time for photon shooting = %f', phot_times)
    logger.info('   Total time for adding noise = %f', noise_times)
    logger.info('')
    logger.info('Breakdown by PSF type:')
    for ipsf in range(len(psfs)):
        logger.info('   %s: Total time = %f  (fft: %f, phot: %f)',
                    psf_names[ipsf], psf_times[ipsf], psf_fft_times[ipsf],
                    psf_phot_times[ipsf])
    logger.info('')
    logger.info('Breakdown by Galaxy type:')
    for igal in range(len(gals)):
        logger.info('   %s: Total time = %f  (fft: %f, phot: %f)',
                    gal_names[igal], gal_times[igal], gal_fft_times[igal],
                    gal_phot_times[igal])
    logger.info('')

    # Now write the image to disk.
    # With any write command, you can optionally compress the file using several compression
    # schemes:
    #   'gzip' uses gzip on the full output file.
    #   'bzip2' uses bzip2 on the full output file.
    #   'rice' uses rice compression on the image, leaving the fits headers readable.
    #   'gzip_tile' uses gzip in tiles on the output image, leaving the fits headers readable.
    #   'hcompress' uses hcompress on the image, but it is only valid for 2-d data, so it
    #               doesn't work for writeCube.
    #   'plio' uses plio on the image, but it is only valid for positive integer data.
    # Furthermore, the first three have standard filename extensions associated with them,
    # so if you don't specify a compression, but the filename ends with '.gz', '.bz2' or '.fz',
    # the corresponding compression will be selected automatically.
    # In other words, the `compression='gzip'` specification is actually optional here:
    galsim.fits.writeCube(all_images, file_name, compression='gzip')
    logger.info('Wrote fft image to fits data cube %r', file_name)
Exemple #25
0
def main(argv):
    """
    Make a fits image cube using parameters from an input catalog
      - The number of images in the cube matches the number of rows in the catalog.
      - Each image size is computed automatically by GalSim based on the Nyquist size.
      - Only galaxies.  No stars.
      - PSF is Moffat
      - Each galaxy is bulge plus disk: deVaucouleurs + Exponential.
      - A fraction of the disk flux is placed into point sources, which can model
        knots of star formation.
      - The catalog's columns are:
         0 PSF beta (Moffat exponent)
         1 PSF FWHM
         2 PSF e1
         3 PSF e2
         4 PSF trunc
         5 Disc half-light-radius
         6 Disc e1
         7 Disc e2
         8 Bulge half-light-radius
         9 Bulge e1
        10 Bulge e2
        11 Galaxy dx (the two components have same center)
        12 Galaxy dy
      - Applied shear is the same for each galaxy
      - Noise is Poisson using a nominal sky value of 1.e6
    """
    logging.basicConfig(format="%(message)s",
                        level=logging.INFO,
                        stream=sys.stdout)
    logger = logging.getLogger("demo4")

    # Define some parameters we'll use below and make directories if needed.
    cat_file_name = os.path.join('input', 'galsim_default_input.asc')
    if not os.path.isdir('output'):
        os.mkdir('output')
    multi_file_name = os.path.join('output', 'multi.fits')

    random_seed = 8241573
    sky_level = 1.e6  # ADU / arcsec^2
    pixel_scale = 1.0  # arcsec / pixel  (size units in input catalog are pixels)
    gal_flux = 1.e6  # arbitrary choice, makes nice (not too) noisy images
    gal_g1 = -0.009  #
    gal_g2 = 0.011  #

    # the fraction of flux in each component
    # 40% is in the bulge, 60% in a disk.  70% of that disk light is placed
    # into point sources distributed as a random walk

    bulge_frac = 0.4
    disk_frac = 0.6
    knot_frac = 0.42
    smooth_disk_frac = 0.18

    # number of knots of star formation.  To simulate a nice irregular (all the
    # flux is in knots) we find ~100 is a minimum number needed, but we will
    # just use 10 here to make the demo run fast.

    n_knots = 10

    xsize = 64  # pixels
    ysize = 64  # pixels

    logger.info('Starting demo script 4 using:')
    logger.info('    - parameters taken from catalog %r', cat_file_name)
    logger.info('    - Moffat PSF (parameters from catalog)')
    logger.info('    - pixel scale = %.2f', pixel_scale)
    logger.info('    - Bulge + Disc galaxies (parameters from catalog)')
    logger.info('    - 100 Point sources, distributed as random walk')
    logger.info('    - Applied gravitational shear = (%.3f,%.3f)', gal_g1,
                gal_g2)
    logger.info('    - Poisson noise (sky level = %.1e).', sky_level)

    # Read in the input catalog
    cat = galsim.Catalog(cat_file_name)

    # save a list of the galaxy images in the "images" list variable:
    images = []
    for k in range(cat.nobjects):
        # Initialize the (pseudo-)random number generator that we will be using below.
        # Use a different random seed for each object to get different noise realizations.
        # Using sequential random seeds here is safer than it sounds.  We use Mersenne Twister
        # random number generators that are designed to be used with this kind of seeding.
        # However, to be extra safe, we actually initialize one random number generator with this
        # seed, generate and throw away two random values with that, and then use the next value
        # to seed a completely different Mersenne Twister RNG.  The result is that successive
        # RNGs created this way produce very independent random number streams.
        rng = galsim.BaseDeviate(random_seed + k + 1)

        # Take the Moffat beta from the first column (called 0) of the input catalog:
        # Note: cat.get(k,col) returns a string.  To get the value as a float, use either
        #       cat.getFloat(k,col) or float(cat.get(k,col))
        beta = cat.getFloat(k, 0)
        # A Moffat's size may be either scale_radius, fwhm, or half_light_radius.
        # Here we use fwhm, taking from the catalog as well.
        fwhm = cat.getFloat(k, 1)
        # A Moffat profile may be truncated if desired
        # The units for this are expected to be arcsec (or specifically -- whatever units
        # you are using for all the size values as defined by the pixel_scale).
        trunc = cat.getFloat(k, 4)
        # Note: You may omit the flux, since the default is flux=1.
        psf = galsim.Moffat(beta=beta, fwhm=fwhm, trunc=trunc)

        # Take the (e1, e2) shape parameters from the catalog as well.
        psf = psf.shear(e1=cat.getFloat(k, 2), e2=cat.getFloat(k, 3))

        # Galaxy is a bulge + disk(+knots) with parameters taken from the catalog:

        # put some fraction of the disk light into knots of star formation

        disk_hlr = cat.getFloat(k, 5)
        disk_e1 = cat.getFloat(k, 6)
        disk_e2 = cat.getFloat(k, 7)
        bulge_hlr = cat.getFloat(k, 8)
        bulge_e1 = cat.getFloat(k, 9)
        bulge_e2 = cat.getFloat(k, 10)

        smooth_disk = galsim.Exponential(flux=smooth_disk_frac,
                                         half_light_radius=disk_hlr)

        knots = galsim.RandomKnots(n_knots,
                                   half_light_radius=disk_hlr,
                                   flux=knot_frac,
                                   rng=rng)

        disk = galsim.Add([smooth_disk, knots])
        disk = disk.shear(e1=disk_e1, e2=disk_e2)

        # the rest of the light goes into the bulge
        bulge = galsim.DeVaucouleurs(flux=bulge_frac,
                                     half_light_radius=bulge_hlr)
        bulge = bulge.shear(e1=bulge_e1, e2=bulge_e2)

        # The flux of an Add object is the sum of the component fluxes.
        # Note that in demo3.py, a similar addition was performed by the binary operator "+".
        gal = galsim.Add([disk, bulge])

        # This flux may be overridden by withFlux.  The relative fluxes of the components
        # remains the same, but the total flux is set to gal_flux.
        gal = gal.withFlux(gal_flux)
        gal = gal.shear(g1=gal_g1, g2=gal_g2)

        # The center of the object is normally placed at the center of the postage stamp image.
        # You can change that with shift:
        gal = gal.shift(dx=cat.getFloat(k, 11), dy=cat.getFloat(k, 12))

        final = galsim.Convolve([psf, gal])

        # Draw the profile
        image = galsim.ImageF(xsize, ysize)
        final.drawImage(image, scale=pixel_scale)

        # Add Poisson noise to the image:
        image.addNoise(galsim.PoissonNoise(rng, sky_level * pixel_scale**2))

        logger.info('Drew image for object at row %d in the input catalog' % k)

        # Add the image to our list of images
        images.append(image)

    # Now write the images to a multi-extension fits file.  Each image will be in its own HDU.
    galsim.fits.writeMulti(images, multi_file_name)
    logger.info('Images written to multi-extension fits file %r',
                multi_file_name)
Exemple #26
0
def test_hsmparams_nodefault():
    """Test that when non-default hsmparams are used, the results change."""
    import time
    # First make some profile
    bulge = galsim.DeVaucouleurs(half_light_radius=0.3)
    disk = galsim.Exponential(half_light_radius=0.5)
    disk = disk.shear(e1=0.2, e2=-0.3)
    psf = galsim.Kolmogorov(fwhm=0.6)
    gal = bulge + disk  # equal weighting, i.e., B/T=0.5
    tot_gal = galsim.Convolve(gal, psf)
    tot_gal_image = tot_gal.drawImage(scale=0.18)
    tot_psf_image = psf.drawImage(scale=0.18)

    # Check that recompute_flux changes give results that are as expected
    test_t = time.time()
    res = galsim.hsm.EstimateShear(tot_gal_image, tot_psf_image)
    dt = time.time() - test_t
    res2 = galsim.hsm.EstimateShear(tot_gal_image,
                                    tot_psf_image,
                                    recompute_flux='sum')
    assert (res.moments_amp <
            res2.moments_amp), 'Incorrect behavior with recompute_flux=sum'
    res3 = galsim.hsm.EstimateShear(tot_gal_image,
                                    tot_psf_image,
                                    recompute_flux='none')
    assert (
        res3.moments_amp == 0), 'Incorrect behavior with recompute_flux=none'

    # Check that results, timing change as expected with nsig_rg
    # For this, use Gaussian as galaxy and for ePSF, i.e., no extra pixel response
    p = galsim.Gaussian(fwhm=10.)
    g = galsim.Gaussian(fwhm=20.)
    g = g.shear(g1=0.5)
    obj = galsim.Convolve(g, p)
    # HSM allows a slop of 1.e-8 on nsig_rg, which means that default float32 images don't
    # actually end up with different result when using nsig_rg=0. rather than 3.
    im = obj.drawImage(scale=1., method='no_pixel', dtype=float)
    psf_im = p.drawImage(scale=1., method='no_pixel', dtype=float)
    test_t1 = time.time()
    g_res = galsim.hsm.EstimateShear(im, psf_im)
    test_t2 = time.time()
    g_res2 = galsim.hsm.EstimateShear(
        im, psf_im, hsmparams=galsim.hsm.HSMParams(nsig_rg=0.))
    dt2 = time.time() - test_t2
    dt1 = test_t2 - test_t1
    if test_timing:
        assert (
            dt2 > dt1
        ), 'Should take longer to estimate shear without truncation of galaxy'
    assert (not equal_hsmshapedata(
        g_res, g_res2)), 'Results should differ with diff nsig_rg'
    assert g_res != g_res2, 'Results should differ with diff nsig_rg'

    # Check that results, timing change as expected with max_moment_nsig2
    test_t2 = time.time()
    res2 = galsim.hsm.EstimateShear(
        tot_gal_image,
        tot_psf_image,
        hsmparams=galsim.hsm.HSMParams(max_moment_nsig2=9.))
    dt2 = time.time() - test_t2
    if test_timing:
        assert (
            dt2 < dt
        ), 'Should be faster to estimate shear with lower max_moment_nsig2'
    assert (not equal_hsmshapedata(
        res, res2)), 'Outputs same despite change in max_moment_nsig2'
    assert res != res2, 'Outputs same despite change in max_moment_nsig2'
    assert (res.moments_sigma >
            res2.moments_sigma), 'Sizes do not change as expected'
    assert (res.moments_amp >
            res2.moments_amp), 'Amplitudes do not change as expected'

    # Check that max_amoment, max_ashift work as expected
    try:
        np.testing.assert_raises(
            RuntimeError,
            galsim.hsm.EstimateShear,
            tot_gal_image,
            tot_psf_image,
            hsmparams=galsim.hsm.HSMParams(max_amoment=10.))
        np.testing.assert_raises(
            RuntimeError,
            galsim.hsm.EstimateShear,
            tot_gal_image,
            tot_psf_image,
            guess_centroid=galsim.PositionD(47.,
                                            tot_gal_image.trueCenter().y),
            hsmparams=galsim.hsm.HSMParams(max_ashift=0.1))
    except ImportError:
        print('The assert_raises tests require nose')
Exemple #27
0
def test_hsmparams():
    """Test the ability to set/change parameters that define how moments/shape estimation are done."""
    # First make some profile, and make sure that we get the same answers when we specify default
    # hsmparams or don't specify hsmparams at all.
    default_hsmparams = galsim.hsm.HSMParams(nsig_rg=3.0,
                                             nsig_rg2=3.6,
                                             max_moment_nsig2=25.0,
                                             regauss_too_small=1,
                                             adapt_order=2,
                                             convergence_threshold=1.e-6,
                                             max_mom2_iter=400,
                                             num_iter_default=-1,
                                             bound_correct_wt=0.25,
                                             max_amoment=8000.,
                                             max_ashift=15.,
                                             ksb_moments_max=4,
                                             failed_moments=-1000.)
    bulge = galsim.DeVaucouleurs(half_light_radius=0.3)
    disk = galsim.Exponential(half_light_radius=0.5)
    disk = disk.shear(e1=0.2, e2=-0.3)
    psf = galsim.Kolmogorov(fwhm=0.6)
    gal = bulge + disk  # equal weighting, i.e., B/T=0.5
    tot_gal = galsim.Convolve(gal, psf)
    tot_gal_image = tot_gal.drawImage(scale=0.18)
    tot_psf_image = psf.drawImage(scale=0.18)

    res = tot_gal_image.FindAdaptiveMom()
    res_def = tot_gal_image.FindAdaptiveMom(hsmparams=default_hsmparams)
    assert (equal_hsmshapedata(
        res, res_def)), 'Moment outputs differ when using default HSMParams'
    assert res == res_def, 'Moment outputs differ when using default HSMParams'

    res2 = galsim.hsm.EstimateShear(tot_gal_image, tot_psf_image)
    res2_def = galsim.hsm.EstimateShear(tot_gal_image,
                                        tot_psf_image,
                                        hsmparams=default_hsmparams)
    assert (equal_hsmshapedata(
        res, res_def)), 'Shear outputs differ when using default HSMParams'
    assert res == res_def, 'Shear outputs differ when using default HSMParams'

    do_pickle(default_hsmparams)
    do_pickle(
        galsim.hsm.HSMParams(nsig_rg=1.0,
                             nsig_rg2=1.6,
                             max_moment_nsig2=2.0,
                             regauss_too_small=0,
                             adapt_order=0,
                             convergence_threshold=1.e-8,
                             max_mom2_iter=100,
                             num_iter_default=4,
                             bound_correct_wt=0.05,
                             max_amoment=80.,
                             max_ashift=5.,
                             ksb_moments_max=2,
                             failed_moments=99.))
    do_pickle(res)
    do_pickle(res2)
    do_pickle(galsim._galsim.CppShapeData())

    try:
        # Then check failure modes: force it to fail by changing HSMParams.
        new_params_niter = galsim.hsm.HSMParams(
            max_mom2_iter=res.moments_n_iter - 1)
        new_params_size = galsim.hsm.HSMParams(max_amoment=0.3 *
                                               res.moments_sigma**2)
        np.testing.assert_raises(RuntimeError,
                                 galsim.hsm.FindAdaptiveMom,
                                 tot_gal_image,
                                 hsmparams=new_params_niter)
        np.testing.assert_raises(RuntimeError,
                                 galsim.hsm.EstimateShear,
                                 tot_gal_image,
                                 tot_psf_image,
                                 hsmparams=new_params_size)
    except ImportError:
        print('The assert_raises tests require nose')
Exemple #28
0
def main(argv):
    """
    Make a fits image cube where each frame has two images of the same galaxy drawn 
    with regular FFT convolution and with photon shooting.

    We do this for 5 different PSFs and 5 different galaxies, each with 4 different (random)
    fluxes, sizes, and shapes.
    """
    logging.basicConfig(format="%(message)s",
                        level=logging.INFO,
                        stream=sys.stdout)
    logger = logging.getLogger("demo7")

    # To turn off logging:
    #logger.propagate = False

    # To turn on the debugging messages:
    #logger.setLevel(logging.DEBUG)

    # Define some parameters we'll use below.

    # Make output directory if not already present.
    if not os.path.isdir('output'):
        os.mkdir('output')

    file_name = os.path.join('output', 'cube_phot.fits.gz')

    random_seed = 553728
    sky_level = 1.e4  # ADU / arcsec^2
    pixel_scale = 0.28  # arcsec
    nx = 64
    ny = 64

    gal_flux_min = 1.e4  # Range for galaxy flux
    gal_flux_max = 1.e5
    gal_hlr_min = 0.3  # arcsec
    gal_hlr_max = 1.3  # arcsec
    gal_e_min = 0.  # Range for ellipticity
    gal_e_max = 0.8

    psf_fwhm = 0.65  # arcsec

    # This script is set up as a comparison between using FFTs for doing the convolutions and
    # shooting photons.  The two methods have trade-offs in speed and accuracy which vary
    # with the kind of profile being drawn and the S/N of the object, among other factors.
    # In addition, for each method, there are a number of parameters GalSim uses that control
    # aspects of the calculation that further affect the speed and accuracy.
    #
    # We encapsulate these parameters with an object called GSParams.  The default values
    # are intended to be accurate enough for normal precision shear tests, without sacrificing
    # too much speed.
    #
    # Any PSF or galaxy object can be given a gsparams argument on construction that can
    # have different values to make the calculation more or less accurate (typically trading
    # off for speed or memory).
    #
    # In this script, we adjust some of the values slightly, just to show you how it works.
    # You could play around with these values and see what effect they have on the drawn images.
    # Usually, it requires a pretty drastic change in these parameters for you to be able to
    # notice the difference by eye.  But subtle effects that may impact the shapes of galaxies
    # can happen well before then.

    # Type help(galsim.GSParams) for the complete list of parameters and more detailed
    # documentation, including the default values for each parameter.
    gsparams = galsim.GSParams(
        folding_threshold=
        1.e-2,  # maximum fractional flux that may be folded around edge of FFT
        maxk_threshold=
        2.e-3,  # k-values less than this may be excluded off edge of FFT
        xvalue_accuracy=
        1.e-4,  # approximations in real space aim to be this accurate
        kvalue_accuracy=
        1.e-4,  # approximations in fourier space aim to be this accurate
        shoot_accuracy=
        1.e-4,  # approximations in photon shooting aim to be this accurate
        minimum_fft_size=64)  # minimum size of ffts

    logger.info('Starting demo script 7')

    # Make the PSF profiles:
    psf1 = galsim.Gaussian(fwhm=psf_fwhm, gsparams=gsparams)
    psf2 = galsim.Moffat(fwhm=psf_fwhm, beta=2.4, gsparams=gsparams)
    psf3_inner = galsim.Gaussian(fwhm=psf_fwhm, flux=0.8, gsparams=gsparams)
    psf3_outer = galsim.Gaussian(fwhm=2 * psf_fwhm,
                                 flux=0.2,
                                 gsparams=gsparams)
    psf3 = psf3_inner + psf3_outer
    atmos = galsim.Gaussian(fwhm=psf_fwhm, gsparams=gsparams)
    # The OpticalPSF and set of Zernike values chosen below correspond to a reasonably well aligned,
    # smallish ~0.3m / 12 inch diameter telescope with a central obscuration of ~0.12m or 5 inches
    # diameter, being used in optical wavebands.
    # In the Noll convention, the value of the Zernike coefficient also gives the RMS optical path
    # difference across a circular pupil.  An RMS difference of ~0.5 or larger indicates that parts
    # of the wavefront are in fully destructive interference, and so we might expect aberrations to
    # become strong when Zernike aberrations summed in quadrature approach 0.5 wave.
    # The aberrations chosen in this case correspond to operating close to a 0.25 wave RMS optical
    # path difference.  Unlike in demo3, we specify the aberrations by making a list that we pass
    # in using the 'aberrations' kwarg.  The order of aberrations starting from index 4 is defocus,
    # astig1, astig2, coma1, coma2, trefoil1, trefoil2, spher as in the Noll convention.
    # We ignore the first 4 values so that the index number corresponds to the Zernike index
    # in the Noll convention. This will be particularly convenient once we start allowing
    # coefficients beyond spherical (index 11).  c.f. The Wikipedia page about the Noll indices:
    #
    #     http://en.wikipedia.org/wiki/Zernike_polynomials#Zernike_polynomials

    aberrations = [0.0] * 12  # Set the initial size.
    aberrations[4] = 0.06  # Noll index 4 = Defocus
    aberrations[5:7] = [0.12, -0.08]  # Noll index 5,6 = Astigmatism
    aberrations[7:9] = [0.07, 0.04]  # Noll index 7,8 = Coma
    aberrations[11] = -0.13  # Noll index 11 = Spherical
    # You could also define these all at once if that is more convenient:
    #aberrations = [0.0, 0.0, 0.0, 0.0, 0.06, 0.12, -0.08, 0.07, 0.04, 0.0, 0.0, -0.13]

    optics = galsim.OpticalPSF(lam_over_diam=0.6 * psf_fwhm,
                               obscuration=0.4,
                               aberrations=aberrations,
                               gsparams=gsparams)
    psf4 = galsim.Convolve([atmos, optics
                            ])  # Convolve inherits the gsparams from the first
    # item in the list.  (Or you can supply a gsparams
    # argument explicitly if you want to override this.)
    atmos = galsim.Kolmogorov(fwhm=psf_fwhm, gsparams=gsparams)
    optics = galsim.Airy(lam_over_diam=0.3 * psf_fwhm, gsparams=gsparams)
    psf5 = galsim.Convolve([atmos, optics])
    psfs = [psf1, psf2, psf3, psf4, psf5]
    psf_names = [
        "Gaussian", "Moffat", "Double Gaussian", "OpticalPSF",
        "Kolmogorov * Airy"
    ]
    psf_times = [0, 0, 0, 0, 0]
    psf_fft_times = [0, 0, 0, 0, 0]
    psf_phot_times = [0, 0, 0, 0, 0]

    # Make the galaxy profiles:
    gal1 = galsim.Gaussian(half_light_radius=1, gsparams=gsparams)
    gal2 = galsim.Exponential(half_light_radius=1, gsparams=gsparams)
    gal3 = galsim.DeVaucouleurs(half_light_radius=1, gsparams=gsparams)
    gal4 = galsim.Sersic(half_light_radius=1, n=2.5, gsparams=gsparams)
    # A Sersic profile may be truncated if desired.
    # The units for this are expected to be arcsec (or specifically -- whatever units
    # you are using for all the size values as defined by the pixel_scale).
    bulge = galsim.Sersic(half_light_radius=0.7,
                          n=3.2,
                          trunc=8.5,
                          gsparams=gsparams)
    disk = galsim.Sersic(half_light_radius=1.2, n=1.5, gsparams=gsparams)
    gal5 = 0.4 * bulge + 0.6 * disk  # Net half-light radius is only approximate for this one.
    gals = [gal1, gal2, gal3, gal4, gal5]
    gal_names = [
        "Gaussian", "Exponential", "Devaucouleurs", "n=2.5 Sersic",
        "Bulge + Disk"
    ]
    gal_times = [0, 0, 0, 0, 0]
    gal_fft_times = [0, 0, 0, 0, 0]
    gal_phot_times = [0, 0, 0, 0, 0]

    # Other times to keep track of:
    setup_times = 0
    fft_times = 0
    phot_times = 0
    noise_times = 0

    # Loop over combinations of psf, gal, and make 4 random choices for flux, size, shape.
    all_images = []
    k = 0
    for ipsf in range(len(psfs)):
        psf = psfs[ipsf]
        psf_name = psf_names[ipsf]
        logger.info('psf %d: %s', ipsf + 1, psf)
        # Note that this implicitly calls str(psf).  We've made an effort to give all GalSim
        # objects an informative but relatively succinct str representation.  Some details may
        # be missing, but it should look essentially like how you would create the object.
        logger.debug('repr = %r', psf)
        # The repr() version are a bit more pedantic in form and should be completely informative,
        # to the point where two objects that are not identical should never have equal repr
        # strings. As such the repr strings may in some cases be somewhat unwieldy.  For instance,
        # since we set non-default gsparams in these, the repr includes that information, but
        # it is omitted from the str for brevity.
        for igal in range(len(gals)):
            gal = gals[igal]
            gal_name = gal_names[igal]
            logger.info('   galaxy %d: %s', igal + 1, gal)
            logger.debug('   repr = %r', gal)
            for i in range(4):
                logger.debug('      Start work on image %d', i)
                t1 = time.time()

                # Initialize the random number generator we will be using.
                rng = galsim.UniformDeviate(random_seed + k)

                # Generate random variates:
                flux = rng() * (gal_flux_max - gal_flux_min) + gal_flux_min

                # Use a new variable name, since we'll want to keep the original unmodified.
                this_gal = gal.withFlux(flux)

                hlr = rng() * (gal_hlr_max - gal_hlr_min) + gal_hlr_min
                this_gal = this_gal.dilate(hlr)

                beta_ellip = rng() * 2 * math.pi * galsim.radians
                ellip = rng() * (gal_e_max - gal_e_min) + gal_e_min
                gal_shape = galsim.Shear(e=ellip, beta=beta_ellip)
                this_gal = this_gal.shear(gal_shape)

                # Build the final object by convolving the galaxy and PSF.
                final = galsim.Convolve([this_gal, psf])

                # Create the large, double width output image
                # Rather than provide a scale= argument to the drawImage commands, we can also
                # set the pixel scale in the image constructor.
                # Note: You can also change it after the construction with im.scale=pixel_scale
                image = galsim.ImageF(2 * nx + 2, ny, scale=pixel_scale)

                # Assign the following two Image "views", fft_image and phot_image.
                # Using the syntax below, these are views into the larger image.
                # Changes/additions to the sub-images referenced by the views are automatically
                # reflected in the original image.
                fft_image = image[galsim.BoundsI(1, nx, 1, ny)]
                phot_image = image[galsim.BoundsI(nx + 3, 2 * nx + 2, 1, ny)]

                logger.debug(
                    '      Read in training sample galaxy and PSF from file')
                t2 = time.time()

                # Draw the profile
                # This default rendering method (method='auto') usually defaults to FFT, since
                # that is normally the most efficient method.  However, we can also set method
                # to 'fft' explicitly to force it to always use FFTs for the convolution
                # by the pixel response.  (In this case, it doesn't have any effect, since
                # the 'auto' method would have always chosen 'fft' anyway, so this is just
                # for illustrative purposes.)
                final.drawImage(fft_image, method='fft')

                logger.debug(
                    '      Drew fft image.  Total drawn flux = %f.  .flux = %f',
                    fft_image.array.sum(), final.getFlux())
                t3 = time.time()

                # Add Poisson noise
                sky_level_pixel = sky_level * pixel_scale**2
                fft_image.addNoise(
                    galsim.PoissonNoise(rng, sky_level=sky_level_pixel))

                t4 = time.time()

                # The next two lines are just to get the output from this demo script
                # to match the output from the parsing of demo7.yaml.
                rng = galsim.UniformDeviate(random_seed + k)
                rng()
                rng()
                rng()
                rng()

                # Repeat for photon shooting image.
                # The max_extra_noise parameter indicates how much extra noise per pixel we are
                # willing to tolerate.  The sky noise will be adding a variance of sky_level_pixel,
                # so we allow up to 1% of that extra.
                final.drawImage(phot_image,
                                method='phot',
                                max_extra_noise=sky_level_pixel / 100,
                                rng=rng)
                t5 = time.time()

                # For photon shooting, galaxy already has Poisson noise, so we want to make
                # sure not to add that noise again!  Thus, we just add sky noise, which
                # is Poisson with the mean = sky_level_pixel
                pd = galsim.PoissonDeviate(rng, mean=sky_level_pixel)
                # DeviateNoise just adds the action of the given deviate to every pixel.
                phot_image.addNoise(galsim.DeviateNoise(pd))
                # For PoissonDeviate, the mean is not zero, so for a background-subtracted
                # image, we need to subtract the mean back off when we are done.
                phot_image -= sky_level_pixel

                logger.debug(
                    '      Added Poisson noise.  Image fluxes are now %f and %f',
                    fft_image.array.sum(), phot_image.array.sum())
                t6 = time.time()

                # Store that into the list of all images
                all_images += [image]

                k = k + 1
                logger.info(
                    '      %d: flux = %.2e, hlr = %.2f, ellip = (%.2f,%.2f)',
                    k, flux, hlr, gal_shape.getE1(), gal_shape.getE2())
                logger.debug('      Times: %f, %f, %f, %f, %f', t2 - t1,
                             t3 - t2, t4 - t3, t5 - t4, t6 - t5)

                psf_times[ipsf] += t6 - t1
                psf_fft_times[ipsf] += t3 - t2
                psf_phot_times[ipsf] += t5 - t4
                gal_times[igal] += t6 - t1
                gal_fft_times[igal] += t3 - t2
                gal_phot_times[igal] += t5 - t4
                setup_times += t2 - t1
                fft_times += t3 - t2
                phot_times += t5 - t4
                noise_times += t4 - t3 + t6 - t5

    logger.info('Done making images of galaxies')
    logger.info('')
    logger.info('Some timing statistics:')
    logger.info('   Total time for setup steps = %f', setup_times)
    logger.info('   Total time for regular fft drawing = %f', fft_times)
    logger.info('   Total time for photon shooting = %f', phot_times)
    logger.info('   Total time for adding noise = %f', noise_times)
    logger.info('')
    logger.info('Breakdown by PSF type:')
    for ipsf in range(len(psfs)):
        logger.info('   %s: Total time = %f  (fft: %f, phot: %f)',
                    psf_names[ipsf], psf_times[ipsf], psf_fft_times[ipsf],
                    psf_phot_times[ipsf])
    logger.info('')
    logger.info('Breakdown by Galaxy type:')
    for igal in range(len(gals)):
        logger.info('   %s: Total time = %f  (fft: %f, phot: %f)',
                    gal_names[igal], gal_times[igal], gal_fft_times[igal],
                    gal_phot_times[igal])
    logger.info('')

    # Now write the image to disk.
    # With any write command, you can optionally compress the file using several compression
    # schemes:
    #   'gzip' uses gzip on the full output file.
    #   'bzip2' uses bzip2 on the full output file.
    #   'rice' uses rice compression on the image, leaving the fits headers readable.
    #   'gzip_tile' uses gzip in tiles on the output image, leaving the fits headers readable.
    #   'hcompress' uses hcompress on the image, but it is only valid for 2-d data, so it
    #               doesn't work for writeCube.
    #   'plio' uses plio on the image, but it is only valid for positive integer data.
    # Furthermore, the first three have standard filename extensions associated with them,
    # so if you don't specify a compression, but the filename ends with '.gz', '.bz2' or '.fz',
    # the corresponding compression will be selected automatically.
    # In other words, the `compression='gzip'` specification is actually optional here:
    galsim.fits.writeCube(all_images, file_name, compression='gzip')
    logger.info('Wrote fft image to fits data cube %r', file_name)
Exemple #29
0
def galSimFakeSersic(flux, gal, psfImage=None, scaleRad=False, returnObj=True,
                     expAll=False, devAll=False, plotFake=False, trunc=0,
                     drawMethod="no_pixel", addPoisson=False, scale=1.0,
                     transform=None, addShear=False):
    """
    Make a fake single Sersic galaxy using the galSim.Sersic function

    Inputs: total flux of the galaxy, and a record array that stores the
    necessary parameters [reffPix, nSersic, axisRatio, posAng]

    Output: a 2-D image array of the galaxy model  OR
            a GalSim object of the model

    Options:
        psfImage:     PSF image for convolution
        trunc:        Flux of Sersic models will truncate at trunc * reffPix
                      radius; trunc=0 means no truncation
        drawMethod:   The method for drawImage: ['auto', 'fft', 'real_space']
        addPoisson:   Add Poisson noise
        plotFake:     Generate a PNG figure of the model
        expAll:       Input model will be seen as nSersic=1
        devAll:       Input model will be seen as nSersic=4
        returnObj:    If TRUE, will return the GSObj
    """
    reff = float(gal["reff"])
    posAng = float(gal["theta"])
    axisRatio = float(gal["b_a"])
    nSersic = float(gal["sersic_n"])

    # Truncate the flux at trunc x reff
    if trunc > 0:
        trunc = trunc * reff

    # Make sure Sersic index is not too large
    if nSersic > 6.0:
        raise ValueError("Sersic index is too large! Should be <= 6.0")
    # Check the axisRatio value
    if axisRatio <= 0.05:
        raise ValueError("Axis Ratio is too small! Should be >= 0.05")

    # Make the Sersic model based on flux, re, and Sersic index
    if nSersic == 1.0 or expAll:
        if scaleRad:
            serObj = galsim.Exponential(scale_radius=reff)
        else:
            serObj = galsim.Exponential(half_light_radius=reff)
        if expAll:
            print " * Treated as a n=1 Exponential disk : %d" % (gal["ID"])
    elif nSersic == 4.0 or devAll:
        serObj = galsim.DeVaucouleurs(half_light_radius=reff, trunc=trunc)
        if devAll:
            print " * Treated as a n=4 De Vaucouleurs model: %d" % (gal["ID"])
    elif nSersic <= 0.9:
        serObj = galsim.Sersic(nSersic, half_light_radius=reff)
    else:
        serObj = galsim.Sersic(nSersic, half_light_radius=reff,
                               trunc=trunc)

    # If necessary, apply the Axis Ratio (q=b/a) using the Shear method
    if axisRatio < 1.0:
        serObj = serObj.shear(q=axisRatio, beta=(0.0 * galsim.degrees))

    # If necessary, apply the Position Angle (theta) using the Rotate method
    #    if posAng != 0.0 or posAng != 180.0:
    serObj = serObj.rotate((90.0 - posAng) * galsim.degrees)

    # If necessary, apply addtion shear (e.g. for weak lensing test)
    if addShear:
        try:
            g1 = float(gal['g1'])
            g2 = float(gal['g2'])
            serObj = serObj.shear(g1=g1, g2=g2)
        except ValueError:
            warnings.warn("Can not find g1 or g2 in the input!\n",
                          " No shear has been added!")

    # Do the transformation from sky to pixel coordinates, if given
    if transform is not None:
        serObj = serObj.transform(*tuple(transform.ravel()))

    # Pass the flux to the object
    serObj = serObj.withFlux(float(flux))

    # Convolve the Sersic model using the provided PSF image
    if psfImage is not None:
        # Convert the PSF Image Array into a GalSim Object
        # Norm=True by default
        psfObj = arrayToGSObj(psfImage, norm=True)
        serFinal = galsim.Convolve([serObj, psfObj])
    else:
        serFinal = serObj

    # Make a PNG figure of the fake galaxy to check if everything is Ok
    if plotFake:
        plotFakeGalaxy(serFinal, galID=gal['ID'])

    # Now, by default, the function will just return the GSObj
    if returnObj:
        return serFinal
    else:
        return galSimDrawImage(serFinal, method=drawMethod, scale=scale,
                               addPoisson=addPoisson)
Exemple #30
0
    def _get_models(self):
        """
        get models for each band
        """
        import galsim
        rng = self.rng

        o = self['objects']
        shift = self._get_shift()

        fracdev = rng.uniform(
            low=o['fracdev_range'][0],
            high=o['fracdev_range'][1],
        )

        disk_hlr = rng.uniform(
            low=o['hlr_range'][0],
            high=o['hlr_range'][1],
        )

        bulge_sizefrac = rng.uniform(
            low=o['bulge_sizefrac_range'][0],
            high=o['bulge_sizefrac_range'][1],
        )
        bulge_hlr = disk_hlr * bulge_sizefrac

        if o['flux_range'] == 'track_hlr':
            flux = disk_hlr**2 * 100
        else:
            flux = rng.uniform(
                low=o['flux_range'][0],
                high=o['flux_range'][1],
            )

        g1disk, g2disk = self.gpdf.sample2d()

        bulge_angle_offset = rng.uniform(
            low=o['bulge_angle_offet_range'][0],
            high=o['bulge_angle_offet_range'][1],
        )
        bulge_angle_offset = np.deg2rad(bulge_angle_offset)
        disk_shape = ngmix.Shape(g1disk, g2disk)
        bulge_shape = disk_shape.get_rotated(bulge_angle_offset)

        disk = galsim.Exponential(
            half_light_radius=disk_hlr,
            flux=(1 - fracdev) * flux,
        ).shear(
            g1=disk_shape.g1,
            g2=disk_shape.g2,
        ).shift(*shift, )

        bulge = galsim.DeVaucouleurs(
            half_light_radius=bulge_hlr,
            flux=fracdev * flux,
        ).shear(
            g1=bulge_shape.g1,
            g2=bulge_shape.g2,
        ).shift(*shift, )

        disk_color = o['disk_color']
        bulge_color = o['bulge_color']

        gdisk = disk * disk_color[0]
        rdisk = disk * disk_color[1]
        idisk = disk * disk_color[2]

        gbulge = bulge * bulge_color[0]
        rbulge = bulge * bulge_color[1]
        ibulge = bulge * bulge_color[2]

        gmodel = galsim.Add(gdisk, gbulge)
        rmodel = galsim.Add(rdisk, rbulge)
        imodel = galsim.Add(idisk, ibulge)

        obj_data = self._get_obj_data_struct()
        obj_data['shift'] = shift
        obj_data['flux'] = flux
        obj_data['hlr'] = disk_hlr
        return (gmodel, rmodel, imodel), obj_data