Example #1
0
def test_knots_transform():
    """Test that overridden transformations give equivalent results as the normal methods.
    """
    def test_op(rw, op):
        print(op)
        rw1 = eval('rw.' + op)
        rw2 = eval('super(galsim.RandomKnots,rw).' + op)

        # Need to convolve by a psf to get reasonable results for fft drawing.
        psf = galsim.Moffat(beta=1.5, fwhm=0.9)
        conv1 = galsim.Convolve(rw1, psf)
        conv2 = galsim.Convolve(rw2, psf)
        im1 = conv1.drawImage(nx=16, ny=16, scale=0.3)
        im2 = conv2.drawImage(nx=16, ny=16, scale=0.3)
        np.testing.assert_almost_equal(im1.array,
                                       im2.array,
                                       decimal=3,
                                       err_msg='RandomKnots with op ' + op)

    if __name__ == '__main__':
        npoints = 20
    else:
        npoints = 3  # Not too many, so this test doesn't take forever.
    hlr = 1.7
    flux = 1000
    rng = galsim.BaseDeviate(1234)
    rw = galsim.RandomKnots(npoints,
                            profile=galsim.Exponential(half_light_radius=hlr,
                                                       flux=flux),
                            rng=rng)

    if __name__ == '__main__':
        # First relatively trivial tests of no ops
        test_op(rw, 'withScaledFlux(1.0)')
        test_op(rw, 'expand(1.0)')
        test_op(rw, 'dilate(1.0)')
        test_op(rw, 'shear(g1=0, g2=0)')
        test_op(rw, 'rotate(0 * galsim.degrees)')
        test_op(rw, 'transform(1., 0., 0., 1.)')
        test_op(rw, 'shift(0., 0.)')
        test_op(rw, 'rotate(23 * galsim.degrees)'
                )  # no op, since original is isotropic

    # These are fundamental, since these are the methods we override.  Always test these.
    test_op(rw, 'withFlux(23)')
    test_op(rw, 'withScaledFlux(23)')
    test_op(rw, 'expand(1.2)')
    test_op(rw, 'dilate(1.2)')
    test_op(rw, 'shear(g1=0.1, g2=-0.03)')
    test_op(rw, '_shear(galsim.Shear(0.03 + 1j*0.09))')
    test_op(rw.shear(g1=0.05, g2=0), 'rotate(23 * galsim.degrees)')
    test_op(rw, 'transform(1.2, 0.1, -0.2, 1.1)')
    test_op(rw, 'shift(0.3, 0.9)')
    test_op(rw, '_shift(galsim.PositionD(-0.3, 0.2))')

    if __name__ == '__main__':
        # A couple more that are currently not overridden, but call out to the above functions.
        test_op(rw, 'magnify(1.2)')
        test_op(rw, 'lens(0.03, 0.07, 1.12)')
Example #2
0
def _generate_bdk(
    hlr,
    flux,
    vary=False,
    rng=None,
    gsrng=None,
    knots_hlr_frac=0.25,
    max_knots_disk_frac=0.1,  # fraction of disk light
    max_bulge_shift_frac=0.1,  # fraction of hlr
    max_bulge_rot=np.pi / 4,
):

    if vary:
        bulge_frac = _generate_bulge_frac(rng)
    else:
        bulge_frac = 0.5

    all_disk_frac = (1.0 - bulge_frac)

    knots_hlr = knots_hlr_frac * hlr
    if vary:
        knots_sub_frac = _generate_knots_sub_frac(rng, max_knots_disk_frac)
    else:
        knots_sub_frac = max_knots_disk_frac

    disk_frac = (1 - knots_sub_frac) * all_disk_frac
    knots_frac = knots_sub_frac * all_disk_frac

    bulge = DeVaucouleurs(half_light_radius=hlr, flux=flux * bulge_frac)
    disk = Exponential(half_light_radius=hlr, flux=flux * disk_frac)

    if gsrng is None:
        # fixed galaxy, so fix the rng
        gsrng = galsim.BaseDeviate(123)

    knots = galsim.RandomKnots(
        npoints=10,
        half_light_radius=knots_hlr,
        flux=flux * knots_frac,
        rng=gsrng,
    )

    if vary:
        bulge = _shift_bulge(rng, bulge, hlr, max_bulge_shift_frac)

    if vary:
        g1disk, g2disk = _generate_g1g2(rng)

        g1bulge, g2bulge = g1disk, g2disk
        if vary:
            g1bulge, g2bulge = _rotate_bulge(rng, max_bulge_rot, g1bulge,
                                             g2bulge)

        bulge = bulge.shear(g1=g1bulge, g2=g2bulge)
        disk = disk.shear(g1=g1disk, g2=g2disk)
        knots = knots.shear(g1=g1disk, g2=g2disk)

    return galsim.Add(bulge, disk, knots)
Example #3
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
Example #4
0
    def get_model(self):
        profile = galsim.Exponential(
            flux=self.flux,
            half_light_radius=self.hlr,
        )

        obj = galsim.RandomKnots(
            self.n_knots,
            profile=profile,
        )
        return obj
Example #5
0
def test_knots_config():
    """
    test we get the same object using a configuration and the
    explicit constructor
    """

    hlr = 2.0
    flux = np.pi
    gal_config1 = {
        'type': 'RandomKnots',
        'npoints': 100,
        'half_light_radius': hlr,
        'flux': flux,
    }
    gal_config2 = {
        'type': 'RandomKnots',
        'npoints': 150,
        'profile': {
            'type': 'Exponential',
            'half_light_radius': hlr,
            'flux': flux,
        }
    }

    for gal_config in (gal_config1, gal_config2):
        config = {
            'gal': gal_config,
            'rng': galsim.BaseDeviate(31415),
        }

        rwc = galsim.config.BuildGSObject(config, 'gal')[0]
        print(repr(rwc._profile))

        rw = galsim.RandomKnots(
            gal_config['npoints'],
            half_light_radius=hlr,
            flux=flux,
        )

        assert rw.npoints==rwc.npoints,\
            "expected npoints==%d, got %d" % (rw.npoints, rwc.npoints)

        assert rw.input_half_light_radius==rwc.input_half_light_radius,\
            "expected hlr==%g, got %g" % (rw.input_half_light_radius, rw.input_half_light_radius)

        nobj = len(rw.points)
        nobjc = len(rwc.points)
        assert nobj == nobjc, "expected %d objects, got %d" % (nobj, nobjc)

        pts = rw.points
        ptsc = rwc.points
        assert (pts.shape == ptsc.shape),\
                "expected %s shape for points, got %s" % (pts.shape,ptsc.shape)
Example #6
0
def test_knots_repr():
    """
    test the repr and str work, and that a new object can be created
    using eval
    """

    npoints=100
    hlr = 8.0
    flux=1
    rw1=galsim.RandomKnots(
        npoints,
        half_light_radius=hlr,
        flux=flux,
    )
    rw2=galsim.RandomKnots(
        npoints,
        profile=galsim.Exponential(half_light_radius=hlr, flux=flux),
    )

    for rw in (rw1, rw2):


        # just make sure str() works, don't require eval to give
        # a consistent object back
        st=str(rw)

        # require eval(repr(rw)) to give a consistent object back

        new_rw = eval(repr(rw))

        assert new_rw.npoints == rw.npoints,\
            "expected npoints=%d got %d" % (rw.npoints,new_rw.npoints)

        mess="expected input_half_light_radius=%.16g got %.16g"
        assert new_rw.input_half_light_radius == rw.input_half_light_radius,\
            mess % (rw.input_half_light_radius,new_rw.input_half_light_radius)
        assert new_rw.flux == rw.flux,\
            "expected flux=%.16g got %.16g" % (rw.flux,new_rw.flux)
Example #7
0
def test_knots_valid_inputs():
    """
    Create a random walk galaxy and test that the getters work for
    valid non-default inputs
    """

    # try constructing with mostly defaults
    npoints = 100
    hlr = 8.0
    flux = 3.5

    seed = 35
    rng = galsim.UniformDeviate(seed)

    args = (npoints, )
    kw1 = {'half_light_radius': hlr, 'flux': flux, 'rng': rng}
    prof = galsim.Exponential(half_light_radius=hlr, flux=flux)
    kw2 = {'profile': prof, 'rng': rng}

    # version of profile with a transformation
    prof = galsim.Exponential(half_light_radius=hlr, flux=flux)
    prof = prof.shear(g1=-0.05, g2=0.025)
    kw3 = {'profile': prof, 'rng': rng}

    for kw in (kw1, kw2, kw3):
        rw = galsim.RandomKnots(*args, **kw)

        assert rw.npoints == npoints, "expected npoints==%d, got %d" % (
            npoints, rw.npoints)

        assert rw.flux==flux,\
            "expected flux==%g, got %g" % (flux, rw.flux)

        if kw is not kw3:
            # only test if not a transformation object
            assert rw.input_half_light_radius==hlr,\
                "expected hlr==%g, got %g" % (hlr, rw.input_half_light_radius)

        pts = rw.points
        nobj = len(pts)
        assert nobj == npoints == npoints, "expected %d objects, got %d" % (
            npoints, nobj)

        pts = rw.points
        assert pts.shape == (npoints,
                             2), "expected (%d,2) shape for points, got %s" % (
                                 npoints, pts.shape)
Example #8
0
def test_knots_sed():
    """Test RandomKnots with an SED

    This test is in response to isse #1064, a bug discovered by Troxel.
    """
    sed = galsim.SED('CWW_E_ext.sed', 'A', 'flambda')
    knots = galsim.RandomKnots(10, half_light_radius=1.3, flux=100)
    gal1 = galsim.ChromaticObject(knots) * sed
    gal2 = knots * sed  # This line used to fail.
    do_pickle(gal1)
    do_pickle(gal2)

    # They don't test as ==, since they are formed differently.  But they are functionally equal:
    bandpass = galsim.Bandpass('LSST_r.dat', 'nm')
    psf = galsim.Gaussian(fwhm=0.7)
    final1 = galsim.Convolve(gal1, psf)
    final2 = galsim.Convolve(gal2, psf)
    im1 = final1.drawImage(bandpass, scale=0.4)
    im2 = final2.drawImage(bandpass, scale=0.4)
    np.testing.assert_array_equal(im1.array, im2.array)
Example #9
0
def RandomWalk(*args, **kwargs):
    from . import depr
    depr('RandomWalk', 2.2, 'RandomKnots')
    return galsim.RandomKnots(*args, **kwargs)
Example #10
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)
Example #11
0
    def getObj(self,
               index,
               gsparams=None,
               rng=None,
               bandpass=None,
               chromatic=False,
               exp_time=30):
        params = self.objinfo[index]

        magnorm = self.getMagNorm(index)
        if magnorm >= 50:
            # Mark of invalid object apparently
            return None

        if gsparams is not None:
            gsparams = galsim.GSParams(**gsparams)

        # Make the object according to the values in the objinfo

        # Note: params here starts at 12, so all indices are 12 less than in previous code.
        if params[0].lower() == 'point':
            obj = galsim.DeltaFunction(gsparams=gsparams)

        elif params[0].lower() == 'sersic2d':
            a = float(params[1])
            b = float(params[2])
            if b > a:
                # Invalid, but existing code just lets it pass.
                return None
            pa = float(params[3])
            if self.flip_g2:
                # Previous code first did PA = 360 - params[3]
                # Then beta = 90 + PA
                beta = float(90 - pa) * galsim.degrees
            else:
                beta = float(90 + pa) * galsim.degrees

            n = float(params[4])
            # GalSim can amortize some calculations for Sersics, but only if n is the same
            # as a previous galaxy.  So quantize the n values at 0.05.  There's no way anyone
            # cares about this at higher resolution than that.
            # For now, this is not actually helpful, since n is always either 1 or 4, but if
            # we ever start having more variable n, this will prevent it from redoing Hankel
            # integrals for every galaxy.
            n = round(n * 20.) / 20.

            hlr = (a * b)**0.5  # geometric mean of a and b is close to right.
            # XXX: Note: Previous code had hlr = a, which is wrong. (?)  Galaxies were too large.
            #      Especially when they were more elliptical.  Oops.
            # TODO: Maybe not?  Check if this should be a.
            obj = galsim.Sersic(n=n, half_light_radius=hlr, gsparams=gsparams)
            shear = galsim.Shear(q=b / a, beta=beta)
            obj = obj._shear(shear)
            g1, g2, mu = self.getLens(index)
            obj = obj._lens(g1, g2, mu)

        elif params[0].lower() == 'knots':
            a = float(params[1])
            b = float(params[2])
            if b > a:
                return None
            pa = float(params[3])
            if self.flip_g2:
                beta = float(90 - pa) * galsim.degrees
            else:
                beta = float(90 + pa) * galsim.degrees
            npoints = int(params[4])
            if npoints <= 0:
                # Again, weird, but previous code just lets this pass without comment.
                return None
            hlr = (a * b)**0.5
            obj = galsim.RandomKnots(npoints=npoints,
                                     half_light_radius=hlr,
                                     rng=rng,
                                     gsparams=gsparams)
            shear = galsim.Shear(q=b / a, beta=beta)
            obj = obj._shear(shear)
            # TODO: These look bad in space images (cf. Troxel's talks about Roman sims.)
            #       Should convolve this by a smallish Gaussian *here*:
            #       I'd guess 0.3 arcsec is a good choice for the fwhm of this Gaussian.
            # obj = galsim.Convolve(obj, galsim.Gaussian(fwhm=0.3))
            g1, g2, mu = self.getLens(index)
            obj = obj._lens(g1, g2, mu)

        elif (params[0].endswith('.fits') or params[0].endswith('.fits.gz')):
            fits_file = find_file_path(params[0], get_image_dirs())
            pixel_scale = float(params[1])
            theta = float(params[2])
            obj = galsim.InterpolatedImage(fits_file,
                                           scale=pixel_scale,
                                           gsparams=gsparams)
            if theta != 0.:
                obj = obj.rotate(-theta * galsim.degrees)
            g1, g2, mu = self.getLens(index)
            obj = obj._lens(g1, g2, mu)

        else:
            raise RuntimeError("Do not know how to handle object type: %s" %
                               params[0])

        # The seds are normalized to correspond to magnorm=0.
        # The flux for the given magnorm is 10**(-0.4*magnorm)
        # The constant here, 0.9210340371976184 = 0.4 * log(10)
        flux = math.exp(-0.9210340371976184 * magnorm)

        # This gives the normalization in photons/cm^2/sec.
        # Multiply by area and exptime to get photons.
        fAt = flux * self._rubin_area * exp_time

        sed = self.getSED(index)
        if chromatic:
            return obj.withFlux(fAt) * sed
        else:
            flux = sed.calculateFlux(bandpass) * fAt
            return obj.withFlux(flux)
Example #12
0
def test_knots_defaults():
    """
    Create a random walk galaxy and test that the getters work for
    default inputs
    """

    # try constructing with mostly defaults
    npoints = 100
    hlr = 8.0
    rng = galsim.BaseDeviate(1234)
    rw = galsim.RandomKnots(npoints, half_light_radius=hlr, rng=rng)

    assert rw.npoints == npoints, "expected npoints==%d, got %d" % (npoints,
                                                                    rw.npoints)
    assert rw.input_half_light_radius==hlr,\
        "expected hlr==%g, got %g" % (hlr, rw.input_half_light_radius)

    nobj = len(rw.points)
    assert nobj == npoints, "expected %d objects, got %d" % (npoints, nobj)

    pts = rw.points
    assert pts.shape == (
        npoints,
        2), "expected (%d,2) shape for points, got %s" % (npoints, pts.shape)
    np.testing.assert_almost_equal(rw.centroid.x, np.mean(pts[:, 0]))
    np.testing.assert_almost_equal(rw.centroid.y, np.mean(pts[:, 1]))

    gsp = galsim.GSParams(xvalue_accuracy=1.e-8, kvalue_accuracy=1.e-8)
    rng2 = galsim.BaseDeviate(1234)
    rw2 = galsim.RandomKnots(npoints,
                             half_light_radius=hlr,
                             rng=rng2,
                             gsparams=gsp)
    assert rw2 != rw
    assert rw2 == rw.withGSParams(gsp)
    assert rw2 == rw.withGSParams(xvalue_accuracy=1.e-8, kvalue_accuracy=1.e-8)

    # Check that they produce identical images.
    psf = galsim.Gaussian(sigma=0.8)
    conv1 = galsim.Convolve(rw.withGSParams(gsp), psf)
    conv2 = galsim.Convolve(rw2, psf)
    im1 = conv1.drawImage()
    im2 = conv2.drawImage()
    assert im1 == im2

    # Check that image is not sensitive to use of rng by other objects.
    rng3 = galsim.BaseDeviate(1234)
    rw3 = galsim.RandomKnots(npoints, half_light_radius=hlr, rng=rng3)
    rng3.discard(523)
    conv1 = galsim.Convolve(rw, psf)
    conv3 = galsim.Convolve(rw3, psf)
    im1 = conv1.drawImage()
    im3 = conv2.drawImage()
    assert im1 == im3

    # Run some basic tests of correctness
    check_basic(conv1, "RandomKnots")
    im = galsim.ImageD(64, 64, scale=0.5)
    do_shoot(conv1, im, "RandomKnots")
    do_kvalue(conv1, im, "RandomKnots")
    do_pickle(rw)
    do_pickle(conv1)
    do_pickle(conv1, lambda x: x.drawImage(scale=1))

    # Check negative flux
    rw3 = rw.withFlux(-2.3)
    assert rw3 == galsim.RandomKnots(npoints,
                                     half_light_radius=hlr,
                                     rng=galsim.BaseDeviate(1234),
                                     flux=-2.3)
    conv = galsim.Convolve(rw3, psf)
    check_basic(conv, "RandomKnots with negative flux")
Example #13
0
def test_knots_invalid_inputs():
    """
    Create a random walk galaxy and test that the the correct exceptions
    are raised for invalid inputs
    """

    npoints = 100
    hlr = 8.0
    flux = 1.0

    # try sending wrong type for npoints
    with assert_raises(GalSimValueError):
        galsim.RandomKnots('blah', half_light_radius=1, flux=3)

    # try sending neither profile or hlr
    with assert_raises(GalSimIncompatibleValuesError):
        galsim.RandomKnots(npoints)

    # try with rng wrong type
    with assert_raises(TypeError):
        galsim.RandomKnots(npoints, half_light_radius=hlr, rng=37)

    # wrong type for profile
    with assert_raises(GalSimIncompatibleValuesError):
        galsim.RandomKnots(npoints, profile=3.5)

    # wrong type for npoints
    npoints_bad = [35]
    with assert_raises(TypeError):
        galsim.RandomKnots(npoints_bad, half_light_radius=hlr)

    # wrong type for hlr
    with assert_raises(GalSimRangeError):
        galsim.RandomKnots(npoints, half_light_radius=-1.5)

    # wrong type for flux
    with assert_raises(TypeError):
        galsim.RandomKnots(npoints, flux=[3.5], half_light_radius=hlr)

    # sending flux with a profile
    prof = galsim.Exponential(half_light_radius=hlr, flux=2.0)
    with assert_raises(GalSimIncompatibleValuesError):
        galsim.RandomKnots(npoints, flux=flux, profile=prof)

    # sending hlr with a profile
    with assert_raises(GalSimIncompatibleValuesError):
        galsim.RandomKnots(npoints, half_light_radius=3, profile=prof)

    # bad value for npoints
    npoints_bad = -35
    with assert_raises(GalSimRangeError):
        galsim.RandomKnots(npoints_bad, half_light_radius=hlr)

    # bad value for hlr
    with assert_raises(GalSimRangeError):
        galsim.RandomKnots(npoints, half_light_radius=-1.5)
Example #14
0
    def gen_mock_lsbg(self,
                      galaxy,
                      zp=HSC_zeropoint,
                      pixel_scale=HSC_pixel_scale,
                      verbose=True):
        '''
        Generate mock low surface brightness galaxies. 
        '''
        import galsim
        from galsim import Angle, Image, InterpolatedImage, degrees
        from galsim.fitswcs import AstropyWCS
        from galsim.interpolant import Lanczos
        big_fft_params = galsim.GSParams(maximum_fft_size=20000)

        if not isinstance(galaxy['comp'], list):
            galaxy['comp'] = list(galaxy['comp'])

        if len(galaxy['comp']) == 1:
            galaxy['flux_fraction'] = [1.0]

        # print some information
        if verbose:
            print('# Generating mock galaxy.')
            print('    - Total components: ', len(galaxy['comp']))
            print('    - Types: ',
                  [c['model'].__name__ for c in galaxy['comp']])
            print('    - Flux fraction: ', galaxy['flux_fraction'])

        # Empty canvas
        field = np.empty_like(self.bkg.images[0])
        model_images = np.empty_like(self.bkg.images)

        # Calculate RA, DEC of the mock galaxy
        y_cen = self.bkg.images.shape[2] / 2
        x_cen = self.bkg.images.shape[1] / 2
        galaxy['ra'], galaxy['dec'] = self.bkg.wcs.wcs_pix2world(
            x_cen, y_cen, 0)

        # Calculate flux based on i-band mag and SED
        i_band_loc = np.argwhere(np.array(list(self.channels)) == 'i')[0][
            0]  # location of i-band in `channels`
        seds = np.array([c['sed'] for c in galaxy['comp']])
        # Normalize SED w.r.t i-band
        seds /= seds[:, i_band_loc][:, np.newaxis]
        tot_sed = np.sum(seds *
                         np.array(galaxy['flux_fraction'])[:, np.newaxis],
                         axis=0)
        for i, band in enumerate(self.channels):
            galaxy[f'{band}mag'] = -2.5 * np.log10(tot_sed[i]) + galaxy['imag']

        if verbose:
            print(f'    - Magnitude in {self.channels}: ',
                  [round(galaxy[f'{band}mag'], 1) for band in self.channels])

        #### Star generating mock galaxy in each band ####
        for i, band in enumerate(self.channels):  # griz
            # Random number seed
            # This random number seed should be fixed across bands!!!
            rng = galsim.BaseDeviate(23333)

            # Sky background level
            sky_SB = 29  # mag/arcsec^2
            sky_level = 10**((zp - sky_SB) / 2.5)  # counts / arcsec^2

            # Define the PSF
            interp_psf = InterpolatedImage(Image(self.bkg.psfs[i] /
                                                 self.bkg.psfs[i].sum(),
                                                 dtype=float),
                                           scale=pixel_scale,
                                           x_interpolant=Lanczos(3))

            # Total flux for all components
            tot_flux = 10**((zp - galaxy[f'{band}mag']) / 2.5)

            gal_list = []
            for k, comp in enumerate(galaxy['comp']):
                # Define the galaxy
                gal = comp['model'](**comp['model_params'],
                                    gsparams=big_fft_params)

                gal_shape = galsim.Shear(
                    **comp['shear_params'])  # Shear the galaxy
                gal = gal.shear(gal_shape)

                if 'shift' in comp.keys():  # Shift the center
                    gal = gal.shift(comp['shift'])

                # Add star forming knots
                if 'n_knots' in comp.keys() and comp['n_knots'] > 0:
                    if not 'knots_frac' in comp.keys():
                        raise KeyError(
                            '`knots_frac` must be provided to generate star forming knots!'
                        )
                    else:
                        if 'knots_sed' in comp.keys():
                            knot_frac = comp['knots_frac'] * \
                                (comp['knots_sed'] /
                                 np.sum(comp['knots_sed']))[i]
                        else:
                            knot_frac = comp['knots_frac'] * 0.25  # flat SED
                        knots = galsim.RandomKnots(
                            comp['n_knots'],
                            half_light_radius=comp['model_params']
                            ['half_light_radius'],
                            flux=knot_frac,
                            rng=rng)
                    gal = galsim.Add([gal, knots])

                gal = gal.withFlux(tot_flux *
                                   galaxy['flux_fraction'][k])  # Get Flux
                gal_list.append(gal)

            # Adding all components together
            gal = galsim.Add(gal_list)

            # Convolve galaxy with PSF
            final = galsim.Convolve([gal, interp_psf])

            # Draw the image with a particular pixel scale.
            gal_image = final.drawImage(scale=pixel_scale,
                                        nx=field.shape[1],
                                        ny=field.shape[0])

            # Add noise
            sky_sigma = hsc_sky[f'{band}'] / 3.631 * \
                10**((zp - 22.5) / 2.5) * pixel_scale**2
            noise = galsim.GaussianNoise(rng, sigma=sky_sigma)
            # gal_image.addNoise(noise)

            # Generate mock image
            model_img = gal_image.array
            model_images[i] = model_img

        # Generate variance map
        mock_model = Data(images=model_images,
                          variances=None,
                          masks=None,
                          channels=self.channels,
                          wcs=None,
                          weights=None,
                          psfs=self.bkg.psfs,
                          info=galaxy)

        # Finished!!!
        self.model = mock_model  # model only has `images`, `channels`, `psfs`, and `info`!
        self.set_mock()  # mock has other things, including modified variances.
Example #15
0
def make_basic_sim(outDir,
                   gname,
                   Id0,
                   ny=100,
                   nx=100,
                   do_write=True,
                   return_array=False):
    """
    Make basic galaxy image simulation (isolated)

    Parameters:
        outDir (str):
            output directory
        gname (str):
            shear distortion setup
        Id0 (int):
            index of the simulation
        ny (int):
            number of galaxies in y direction
        nx (int):
            number of galaxies in x direction
        do_write (bool):
            whether write output [default: True]
        return_array (bool):
            whether return galaxy array [default: False]
    """
    ngrid = 64
    scale = 0.168
    # Get the shear information
    gList = np.array([-0.02, 0., 0.02])
    gList = gList[[eval(i) for i in gname.split('-')[-1]]]
    if gname.split('-')[0] == 'g1':
        g1 = gList[0]
        g2 = 0.
    elif gname.split('-')[0] == 'g2':
        g1 = 0.
        g2 = gList[0]
    else:
        raise ValueError('cannot decide g1 or g2')
    logging.info(
        'Processing for %s, and shears for four redshift bins are %s.' %
        (gname, gList))
    # PSF
    psfFWHM = eval(outDir.split('_psf')[-1]) / 100.
    logging.info('The FWHM for PSF is: %s arcsec' % psfFWHM)
    psfInt = galsim.Moffat(beta=3.5, fwhm=psfFWHM, trunc=psfFWHM * 4.)
    psfInt = psfInt.shear(e1=0.02, e2=-0.02)
    #psfImg =   psfInt.drawImage(nx=45,ny=45,scale=scale)

    gal_image = galsim.ImageF(nx * ngrid, ny * ngrid, scale=scale)
    gal_image.setOrigin(0, 0)
    outFname = os.path.join(outDir, 'image-%d-%s.fits' % (Id0, gname))
    if os.path.exists(outFname):
        logging.info('Already have the outcome.')
        if do_write:
            logging.info('Nothing to write.')
        if return_array:
            return fitsio.read(outFname)
        else:
            return None
    ud = galsim.UniformDeviate(Id0 + 212)
    bigfft = galsim.GSParams(maximum_fft_size=10240)
    if 'basic' in outDir:
        rotArray = make_ringrot_radians(7)
        # 2**7*8=1024 galaxy ID
        # 2**7 different rotations and dilations
        # for each galaxy ID 10000 parametric galaxies
        logging.info('We have %d rotation realizations' % len(rotArray))
        irot = Id0 // 8
        if irot >= len(rotArray):
            logging.info('galaxy image index greater than %d' %
                         len(rotArray * 8))
        ang = rotArray[irot] * galsim.radians
        rescale = 1. + (ud() - 0.5) * 0.1
        logging.info('%s' % rescale)
        # cosmos group ID =0...7
        # we use 80000 galsim galaxies repeatedly
        cgid = int(Id0 % 8)
        logging.info('Making Basic Simulation. ID: %d, cosmos GID: %d.' %
                     (Id0, cgid))
        logging.info('The rotating angle is %.2f radians.' % rotArray[irot])
        # Galsim galaxies
        directory   =   os.path.join(os.environ['homeWrk'],\
                        'COSMOS/galsim_train/COSMOS_25.2_training_sample/')
        assert os.path.isdir(directory), 'cannot find galsim galaxies'
        catName = 'real_galaxy_catalog_25.2.fits'
        cosmos_cat = galsim.COSMOSCatalog(catName, dir=directory)

        # Basic parameters
        flux_scaling = 2.587
        # catalog
        cosmo252 = cosmoHSTGal('252')
        cosmo252.readHSTsample()
        # cgid=0...7
        hscCat = cosmo252.catused[cgid * nx * ny:(cgid + 1) * nx * ny]
        for i, ss in enumerate(hscCat):
            ix = i % nx
            iy = i // nx
            b = galsim.BoundsI(ix * ngrid, (ix + 1) * ngrid - 1, iy * ngrid,
                               (iy + 1) * ngrid - 1)
            # each galaxy
            gal =   cosmos_cat.makeGalaxy(gal_type='parametric',\
                    index=ss['index'],gsparams=bigfft)
            # rescale the radius by 'rescale' and keep surface brightness the same
            gal = gal.expand(rescale)
            # rotate by 'ang'
            gal = gal.rotate(ang)
            # accounting for zeropoint difference between COSMOS HST and HSC
            gal = gal * flux_scaling
            # shear distortion
            gal = gal.shear(g1=g1, g2=g2)
            if 'Shift' in outDir:
                # Galaxies is randomly shifted
                # This shift ensure that the offset to (ngrid//2,ngrid//2) is an isotropic circle
                dx = (ud() + 0.5) * scale
                dy = (ud() + 0.5) * scale
                if i == 0:
                    logging.info('%.2f,%.2f' % (dx, dy))
                gal = gal.shift(dx, dy)
            elif 'Center' in outDir:
                # Galaxies is located at (ngrid//2,ngrid//2)
                dx = 0.5 * scale
                dy = 0.5 * scale
                gal = gal.shift(dx, dy)
            else:
                #Galaxies is located at (ngrid//2-0.5,ngrid//2-0.5))
                pass
            gal = galsim.Convolve([psfInt, gal], gsparams=bigfft)
            # draw galaxy
            sub_img = gal_image[b]
            gal.drawImage(sub_img, add_to_image=True)
            del gal, b, sub_img
        del hscCat, cosmos_cat, cosmo252, psfInt
        gc.collect()
    elif 'small' in outDir:
        # use galaxies with random knots
        # we only support three versions of small galaxies with different radius
        irr = eval(outDir.split('_psf')[0].split('small')[-1])
        if irr == 0:
            radius = 0.07
        elif irr == 1:
            radius = 0.15
        elif irr == 2:
            radius = 0.20
        else:
            raise ValueError('Something wrong with the outDir! we only support'
                             'three versions of small galaxies')
        logging.info('Making Small Simulation with Random Knots.')
        logging.info('Radius: %s, ID: %s.' % (radius, Id0))
        npoints = 20
        gal0    =   galsim.RandomKnots(half_light_radius=radius,\
                    npoints=npoints,flux=10.,rng=ud)
        for ix in range(100):
            for iy in range(100):
                igal = ix * 100 + iy
                b      =    galsim.BoundsI(ix*ngrid,(ix+1)*ngrid-1,\
                            iy*ngrid,(iy+1)*ngrid-1)
                if igal % 4 == 0 and igal != 0:
                    gal0=   galsim.RandomKnots(half_light_radius=radius,\
                            npoints=npoints,flux=10.,rng=ud,gsparams=bigfft)
                sub_img = gal_image[b]
                ang = igal % 4 * np.pi / 4. * galsim.radians
                gal = gal0.rotate(ang)
                # Shear the galaxy
                gal = gal.shear(g1=g1, g2=g2)
                gal = galsim.Convolve([psfInt, gal], gsparams=bigfft)
                # Draw the galaxy image
                gal.drawImage(sub_img, add_to_image=True)
                del gal, b, sub_img
                gc.collect()
        gc.collect()
    else:
        raise ValueError("outDir should cotain 'basic' or 'small'!!")
    del ud
    if do_write:
        gal_image.write(outFname, clobber=True)
    if return_array:
        return gal_image.array