Example #1
0
def _convertMask(image, weight=None, badpix=None):
    """Convert from input weight and badpix images to a single mask image needed by C++ functions.

    This is used by EstimateShear() and FindAdaptiveMom().
    """
    # if no weight image was supplied, make an int array (same size as gal image) filled with 1's
    if weight is None:
        mask = galsim.ImageI(bounds=image.bounds, init_value=1)

    else:
        # if weight image was supplied, check if it has the right bounds and is non-negative
        if weight.bounds != image.bounds:
            raise ValueError(
                "Weight image does not have same bounds as the input Image!")

        # also make sure there are no negative values
        import numpy as np
        if np.any(weight.array < 0) == True:
            raise ValueError("Weight image cannot contain negative values!")

        # if weight is an ImageI, then we can use it as the mask image:
        import numpy
        if weight.dtype == numpy.int32:
            if not badpix:
                mask = weight
            else:
                # If we need to mask bad pixels, we'll need a copy anyway.
                mask = galsim.ImageI(weight)

        # otherwise, we need to convert it to the right type
        else:
            mask = galsim.ImageI(bounds=image.bounds, init_value=0)
            mask.array[weight.array > 0.] = 1

    # if badpix image was supplied, identify the nonzero (bad) pixels and set them to zero in weight
    # image; also check bounds
    if badpix is not None:
        if badpix.bounds != image.bounds:
            raise ValueError(
                "Badpix image does not have the same bounds as the input Image!"
            )
        import numpy as np
        mask.array[badpix.array != 0] = 0

    # if no pixels are used, raise an exception
    if mask.array.sum() == 0:
        raise RuntimeError("No pixels are being used!")

    # finally, return the Image for the weight map
    return mask.image.view()
Example #2
0
def _convertImage(image):
    """Convert the given image to the correct format needed to pass to the C++ layer.

    This is used by EstimateShear() and FindAdaptiveMom().
    """
    # if weight is an ImageS, then convert to ImageI.
    if image.dtype == np.int16:
        image = galsim.ImageI(image)

    # Return this as an ImageView
    return image.image.view()
Example #3
0
def test_exceptions():
    """Test failure modes for InterpolatedImage class.
    """
    import time
    t1 = time.time()

    try:
        # What if it receives as input something that is not an Image? Give it a GSObject to check.
        g = galsim.Gaussian(sigma=1.)
        np.testing.assert_raises(ValueError, galsim.InterpolatedImage, g)
        # What if Image does not have a scale set, but scale keyword is not specified?
        im = galsim.ImageF(5, 5)
        np.testing.assert_raises(ValueError, galsim.InterpolatedImage, im)
        # Image must have bounds defined
        im = galsim.ImageF()
        im.scale = 1.
        np.testing.assert_raises(ValueError, galsim.InterpolatedImage, im)
        # Weird flux normalization
        im = galsim.ImageF(5, 5, scale=1.)
        np.testing.assert_raises(ValueError, galsim.InterpolatedImage, im, normalization = 'foo')
        # scale and WCS
        np.testing.assert_raises(TypeError, galsim.InterpolatedImage, im,
                                 wcs = galsim.PixelScale(1.), scale=1.)
        # weird WCS
        np.testing.assert_raises(TypeError, galsim.InterpolatedImage, im,
                                 wcs = 1.)
        # Weird interpolant - give it something random like a GSObject
        np.testing.assert_raises(Exception, galsim.InterpolatedImage, im, x_interpolant = g)
        # Image has wrong type
        im = galsim.ImageI(5, 5)
        np.testing.assert_raises(ValueError, galsim.InterpolatedImage, im)
    except ImportError:
        print 'The assert_raises tests require nose'

    t2 = time.time()
    print 'time for %s = %.2f'%(funcname(),t2-t1)
Example #4
0
    def __init__(self,
                 images,
                 weight=None,
                 badpix=None,
                 seg=None,
                 psf=None,
                 wcs=None,
                 id=0):

        # Check that images is valid
        if not isinstance(images, list):
            raise TypeError('images should be a list')
        if len(images) == 0:
            raise ValueError('no cutouts in this object')

        # Check that the box sizes are valid
        for i in range(len(images)):
            s = images[i].array.shape
            if s[0] != s[1]:
                raise ValueError('Array shape %s is invalid.  Must be square' %
                                 (str(s)))
            if s[0] not in BOX_SIZES:
                raise ValueError(
                    'Array shape %s is invalid.  Size must be in %s' %
                    (str(box_size), str(BOX_SIZES)))
            if i > 0 and s != images[0].array.shape:
                raise ValueError('Images must all be the same shape')

        # The others are optional, but if given, make sure they are ok.
        for lst, name, isim in [(weight, 'weight', True),
                                (badpix, 'badpix', True), (seg, 'seg', True),
                                (psf, 'psf', False), (wcs, 'wcs', False)]:
            if lst is not None:
                if not isinstance(lst, list):
                    raise TypeError('%s should be a list' % name)
                if len(lst) != len(images):
                    raise ValueError('%s is the wrong length' % name)
                if isim:
                    for i in range(len(images)):
                        im1 = lst[i]
                        im2 = images[i]
                        if (im1.array.shape != im2.array.shape):
                            raise ValueError("%s[%d] has the wrong shape." %
                                             (name, i))

        # The PSF images don't have to be the same shape as the main images.
        # But make sure all psf images are square and the same shape
        if psf is not None:
            s = psf[i].array.shape
            if s[0] != s[1]:
                raise ValueError(
                    'PSF array shape %s is invalid.  Must be square' %
                    (str(s)))
            if s[0] not in BOX_SIZES:
                raise ValueError(
                    'PSF array shape %s is invalid.  Size must be in %s' %
                    (str(box_size), str(BOX_SIZES)))
            if i > 0 and s != psf[0].array.shape:
                raise ValueError('PSF images must all be the same shape')

        # Check that wcs are Uniform and convert them to AffineTransforms in case they aren't.
        if wcs is not None:
            for i in range(len(wcs)):
                if not isinstance(wcs[i], galsim.wcs.UniformWCS):
                    raise TypeError(
                        'wcs list should contain UniformWCS objects')
                elif not isinstance(wcs[i], galsim.AffineTransform):
                    wcs[i] = wcs[i].affine()

        self.id = id
        self.images = [im.view() for im in images]
        # Convert to 0-based images as preferred by meds.
        for im in self.images:
            # Note: making the list of views above means this won't change the originals.
            im.setOrigin(0, 0)
        self.box_size = self.images[0].array.shape[0]
        self.n_cutouts = len(self.images)
        if psf is not None:
            self.psf_box_size = self.images[0].array.shape[0]
        else:
            self.psf_box_size = 0

        # If weight is not provided, create something sensible.
        if weight is not None:
            self.weight = weight
        else:
            self.weight = [
                galsim.Image(self.box_size, self.box_size, init_value=1)
            ] * self.n_cutouts

        # If badpix is provided, combine it into the weight image.
        if badpix is not None:
            for i in range(len(badpix)):
                mask = [badpix[i] != 0]
                self.weight[i][mask] = 0.

        # If seg is not provided, use all 1's.
        if seg is not None:
            self.seg = seg
        else:
            self.seg = [
                galsim.ImageI(self.box_size, self.box_size, init_value=1)
            ] * self.n_cutouts

        # If wcs is not provided, get it from the images.
        if wcs is not None:
            self.wcs = wcs
        else:
            self.wcs = [
                im.wcs.affine(image_pos=im.trueCenter()) for im in self.images
            ]

        # psf is not required, so leave it as None if not provided.
        self.psf = psf
Example #5
0
def test_masks():
    """Test that moments and shear estimation routines respond appropriately to masks."""
    # set up some toy galaxy and PSF
    my_sigma = 1.0
    my_pixscale = 0.1
    my_g1 = 0.15
    my_g2 = -0.4
    imsize = 256
    g = galsim.Gaussian(sigma=my_sigma)
    p = galsim.Gaussian(
        sigma=my_sigma
    )  # the ePSF is Gaussian (kind of silly but it means we can
    # predict results exactly)
    g = g.shear(g1=my_g1, g2=my_g2)
    obj = galsim.Convolve(g, p)
    im = galsim.ImageF(imsize, imsize)
    p_im = galsim.ImageF(imsize, imsize)
    obj.drawImage(image=im, scale=my_pixscale, method='no_pixel')
    p.drawImage(image=p_im, scale=my_pixscale, method='no_pixel')

    # make some screwy weight and badpix images that should cause issues, and check that the
    # exception is thrown
    good_weight_im = galsim.ImageI(imsize, imsize, init_value=1)
    try:
        ## different size from image
        weight_im = galsim.ImageI(imsize, 2 * imsize)
        np.testing.assert_raises(ValueError, galsim.hsm.FindAdaptiveMom, im,
                                 weight_im)
        np.testing.assert_raises(ValueError, galsim.hsm.EstimateShear, im,
                                 p_im, weight_im)
        badpix_im = galsim.ImageI(imsize, 2 * imsize)
        np.testing.assert_raises(ValueError, galsim.hsm.FindAdaptiveMom, im,
                                 badpix_im)
        np.testing.assert_raises(ValueError, galsim.hsm.EstimateShear, im,
                                 p_im, good_weight_im, badpix_im)
        ## weird values
        weight_im = galsim.ImageI(imsize, imsize, init_value=-3)
        np.testing.assert_raises(ValueError, galsim.hsm.FindAdaptiveMom, im,
                                 weight_im)
        np.testing.assert_raises(ValueError, galsim.hsm.EstimateShear, im,
                                 p_im, weight_im)
        ## excludes all pixels
        weight_im = galsim.ImageI(imsize, imsize)
        np.testing.assert_raises(RuntimeError, galsim.hsm.FindAdaptiveMom, im,
                                 weight_im)
        np.testing.assert_raises(RuntimeError, galsim.hsm.EstimateShear, im,
                                 p_im, weight_im)
        badpix_im = galsim.ImageI(imsize, imsize, init_value=-1)
        np.testing.assert_raises(RuntimeError, galsim.hsm.FindAdaptiveMom, im,
                                 good_weight_im, badpix_im)
        np.testing.assert_raises(RuntimeError, galsim.hsm.EstimateShear, im,
                                 p_im, good_weight_im, badpix_im)

    except ImportError:
        # assert_raises requires nose, which we don't want to force people to install.
        # So if they are running this without nose, we just skip these tests.
        pass

    # check moments, shear without mask
    resm = im.FindAdaptiveMom()
    ress = galsim.hsm.EstimateShear(im, p_im)

    # check moments, shear with weight image that includes all pixels
    weightall1 = galsim.ImageI(imsize, imsize, init_value=1)
    resm_weightall1 = im.FindAdaptiveMom(weightall1)
    ress_weightall1 = galsim.hsm.EstimateShear(im, p_im, weightall1)

    # We'll do this series of tests a few times, so encapsulate the code here.
    def check_equal(resm, ress, resm_test, ress_test, tag):
        np.testing.assert_equal(resm.observed_shape.e1,
                                resm_test.observed_shape.e1,
                                err_msg="e1 from FindAdaptiveMom changes " +
                                tag)
        np.testing.assert_equal(resm.observed_shape.e2,
                                resm_test.observed_shape.e2,
                                err_msg="e2 from FindAdaptiveMom changes " +
                                tag)
        np.testing.assert_equal(resm.moments_sigma,
                                resm_test.moments_sigma,
                                err_msg="sigma from FindAdaptiveMom changes " +
                                tag)
        np.testing.assert_equal(
            ress.observed_shape.e1,
            ress_test.observed_shape.e1,
            err_msg="observed e1 from EstimateShear changes " + tag)
        np.testing.assert_equal(
            ress.observed_shape.e2,
            ress_test.observed_shape.e2,
            err_msg="observed e2 from EstimateShear changes " + tag)
        np.testing.assert_equal(
            ress.moments_sigma,
            ress_test.moments_sigma,
            err_msg="observed sigma from EstimateShear changes " + tag)
        np.testing.assert_equal(
            ress.corrected_e1,
            ress_test.corrected_e1,
            err_msg="corrected e1 from EstimateShear changes " + tag)
        np.testing.assert_equal(
            ress.corrected_e2,
            ress_test.corrected_e2,
            err_msg="corrected e2 from EstimateShear changes " + tag)
        np.testing.assert_equal(
            ress.resolution_factor,
            ress_test.resolution_factor,
            err_msg="resolution factor from EstimateShear changes " + tag)

    check_equal(resm, ress, resm_weightall1, ress_weightall1,
                "when using inclusive weight")

    # check moments and shears with mask of edges, should be nearly the same
    # (this seems dumb, but it's helpful for keeping track of whether the pointers in the C++ code
    # are being properly updated despite the masks.  If we monkey in that code again, it will be a
    # useful check.)
    maskedge = galsim.ImageI(imsize, imsize, init_value=1)
    xmin = maskedge.xmin
    xmax = maskedge.xmax
    ymin = maskedge.ymin
    ymax = maskedge.ymax
    edgenum = 3
    for ind1 in range(xmin, xmax + 1):
        for ind2 in range(ymin, ymax + 1):
            if (ind1 <= (xmin + edgenum)) or (ind1 >= (xmax - edgenum)) or (
                    ind2 <= (ymin + edgenum)) or (ind2 >= (ymax - edgenum)):
                maskedge.setValue(ind1, ind2, 0)
    resm_maskedge = im.FindAdaptiveMom(maskedge)
    ress_maskedge = galsim.hsm.EstimateShear(im, p_im, maskedge)
    test_decimal = 4
    np.testing.assert_almost_equal(
        resm.observed_shape.e1,
        resm_maskedge.observed_shape.e1,
        decimal=test_decimal,
        err_msg="e1 from FindAdaptiveMom changes when masking edge")
    np.testing.assert_almost_equal(
        resm.observed_shape.e2,
        resm_maskedge.observed_shape.e2,
        decimal=test_decimal,
        err_msg="e2 from FindAdaptiveMom changes when masking edge")
    np.testing.assert_almost_equal(
        resm.moments_sigma,
        resm_maskedge.moments_sigma,
        decimal=test_decimal,
        err_msg="sigma from FindAdaptiveMom changes when masking edge")
    np.testing.assert_almost_equal(
        ress.observed_shape.e1,
        ress_maskedge.observed_shape.e1,
        decimal=test_decimal,
        err_msg="observed e1 from EstimateShear changes when masking edge")
    np.testing.assert_almost_equal(
        ress.observed_shape.e2,
        ress_maskedge.observed_shape.e2,
        decimal=test_decimal,
        err_msg="observed e2 from EstimateShear changes when masking edge")
    np.testing.assert_almost_equal(
        ress.moments_sigma,
        ress_maskedge.moments_sigma,
        decimal=test_decimal,
        err_msg="observed sigma from EstimateShear changes when masking edge")
    np.testing.assert_almost_equal(
        ress.corrected_e1,
        ress_maskedge.corrected_e1,
        decimal=test_decimal,
        err_msg="corrected e1 from EstimateShear changes when masking edge")
    np.testing.assert_almost_equal(
        ress.corrected_e2,
        ress_maskedge.corrected_e2,
        decimal=test_decimal,
        err_msg="corrected e2 from EstimateShear changes when masking edge")
    np.testing.assert_almost_equal(
        ress.resolution_factor,
        ress_maskedge.resolution_factor,
        decimal=test_decimal,
        err_msg="resolution factor from EstimateShear changes when masking edge"
    )

    # check that results don't change *at all* i.e. using assert_equal when we do this edge masking
    # in different ways:
    ## do the same as the previous test, but with weight map that is floats (0.0 or 1.0)
    maskedge = galsim.ImageF(imsize, imsize, init_value=1.)
    for ind1 in range(xmin, xmax + 1):
        for ind2 in range(ymin, ymax + 1):
            if (ind1 <= (xmin + edgenum)) or (ind1 >= (xmax - edgenum)) or (
                    ind2 <= (ymin + edgenum)) or (ind2 >= (ymax - edgenum)):
                maskedge.setValue(ind1, ind2, 0.)
    resm_maskedge1 = im.FindAdaptiveMom(maskedge)
    ress_maskedge1 = galsim.hsm.EstimateShear(im, p_im, maskedge)
    check_equal(resm_maskedge, ress_maskedge, resm_maskedge1, ress_maskedge1,
                "when masking with floats")

    ## make the weight map for allowed pixels a nonzero value that also != 1
    maskedge = galsim.ImageF(imsize, imsize, init_value=2.3)
    for ind1 in range(xmin, xmax + 1):
        for ind2 in range(ymin, ymax + 1):
            if (ind1 <= (xmin + edgenum)) or (ind1 >= (xmax - edgenum)) or (
                    ind2 <= (ymin + edgenum)) or (ind2 >= (ymax - edgenum)):
                maskedge.setValue(ind1, ind2, 0.)
    resm_maskedge1 = im.FindAdaptiveMom(maskedge)
    ress_maskedge1 = galsim.hsm.EstimateShear(im, p_im, maskedge)
    check_equal(resm_maskedge, ress_maskedge, resm_maskedge1, ress_maskedge1,
                "when masking with floats != 1")

    ## make the weight map all equal to 1, and use a badpix map with a range of nonzero values
    maskedge = galsim.ImageI(imsize, imsize, init_value=1)
    badpixedge = galsim.ImageI(imsize, imsize, init_value=0)
    for ind1 in range(xmin, xmax + 1):
        for ind2 in range(ymin, ymax + 1):
            if (ind1 <= (xmin + edgenum)) or (ind1 >= (xmax - edgenum)) or (
                    ind2 <= (ymin + edgenum)) or (ind2 >= (ymax - edgenum)):
                badpixedge.setValue(ind1, ind2, ind1 + 1)
    resm_maskedge1 = im.FindAdaptiveMom(maskedge, badpixedge)
    ress_maskedge1 = galsim.hsm.EstimateShear(im, p_im, maskedge, badpixedge)
    check_equal(resm_maskedge, ress_maskedge, resm_maskedge1, ress_maskedge1,
                "when masking with badpix")

    ## same as previous, but with badpix of floats
    maskedge = galsim.ImageI(imsize, imsize, init_value=1)
    badpixedge = galsim.ImageF(imsize, imsize, init_value=0.)
    for ind1 in range(xmin, xmax + 1):
        for ind2 in range(ymin, ymax + 1):
            if (ind1 <= (xmin + edgenum)) or (ind1 >= (xmax - edgenum)) or (
                    ind2 <= (ymin + edgenum)) or (ind2 >= (ymax - edgenum)):
                badpixedge.setValue(ind1, ind2, float(ind1 + 1))
    resm_maskedge1 = im.FindAdaptiveMom(maskedge, badpixedge)
    ress_maskedge1 = galsim.hsm.EstimateShear(im, p_im, maskedge, badpixedge)
    check_equal(resm_maskedge, ress_maskedge, resm_maskedge1, ress_maskedge1,
                "when masking with badpix (floats)")

    ## do some of the masking using weight map, and the rest using badpix
    maskedge = galsim.ImageI(imsize, imsize, init_value=1)
    badpixedge = galsim.ImageI(imsize, imsize, init_value=0)
    meanval = int(0.5 * (xmin + xmax))
    for ind1 in range(xmin, xmax + 1):
        for ind2 in range(ymin, ymax + 1):
            if (ind1 <= (xmin + edgenum)) or (ind1 >= (xmax - edgenum)) or (
                    ind2 <= (ymin + edgenum)) or (ind2 >= (ymax - edgenum)):
                if ind1 < meanval:
                    badpixedge.setValue(ind1, ind2, 1)
                else:
                    maskedge.setValue(ind1, ind2, 0)
    resm_maskedge1 = im.FindAdaptiveMom(maskedge, badpixedge)
    ress_maskedge1 = galsim.hsm.EstimateShear(im, p_im, maskedge, badpixedge)
    check_equal(resm_maskedge, ress_maskedge, resm_maskedge1, ress_maskedge1,
                "when masking with badpix and weight map")
Example #6
0
    def __init__(self,
                 images,
                 weights=None,
                 badpix=None,
                 segs=None,
                 wcstrans=None,
                 id=0):

        # assign the ID
        self.id = id

        # check if images is a list
        if not isinstance(images, list):
            raise TypeError('images should be a list')

        # get number of cutouts from image list
        self.images = images
        # get box size from the first image
        self.box_size = self.images[0].array.shape[0]
        self.n_cutouts = len(self.images)

        # see if there are cutouts
        if self.n_cutouts < 1:
            raise ValueError('no cutouts in this object')

        # check if the box size is correct
        if self.box_size not in BOX_SIZES:
            # raise ValueError('box size should be in  [32,48,64,96,128,196,256], is %d' % box_size)
            raise ValueError('box size should be in ' + str(BOX_SIZES) +
                             ', is ' + str(self.box_size))

        # check if weights, segs and wcstrans were supplied. If not, create sensible values.
        if weights != None:
            self.weights = weights
        else:
            self.weights = [
                galsim.ImageF(self.box_size, self.box_size, init_value=1)
            ] * self.n_cutouts

        # check segmaps
        if segs != None:
            self.segs = segs
            # I think eventually, the meds files will have some more sophisticated pixel map
            # where the segmentation info and bad pixel info are separately coded.
            # However, for now, we just set to 0 any bad pixels.
            # (Not that GalSim has any mechanism yet for generating bad pixels, so this is
            # usually a null op, but it's in place for when there is something to do.)
            if badpix != None:
                if len(self.segs) != len(badpix):
                    raise ValueError("segs and badpix are different lengths")
                for i in range(len(self.segs)):
                    if (self.segs[i].array.shape != badpix[i].array.shape):
                        raise ValueError(
                            "segs[%d] and badpix[%d] have different shapes." %
                            (i, i))
                    self.segs[i].array[:, :] &= (badpix[i].array == 0)
        elif badpix != None:
            self.segs = badpix
            # Flip the sense of the bits 0 -> 1, other -> 0
            # Again, this might need to become more sophisticated at some point...
            for i in range(len(self.segs)):
                self.segs[i].array[:, :] = (badpix[i].array == 0)
        else:
            self.segs = [
                galsim.ImageI(self.box_size, self.box_size, init_value=1)
            ] * self.n_cutouts

        # check wcstrans
        if wcstrans != None:
            self.wcstrans = wcstrans
        else:
            # build jacobians that are just based on the pixel scale, set the centers
            dudrow = 1
            dudcol = 0
            dvdrow = 0
            dvdcol = 1
            # set to the center of the postage stamp
            row0 = float(self.box_size) / 2.
            col0 = float(self.box_size) / 2.
            self.wcstrans = [
                WCSTransform(dudrow * im.scale, dudcol * im.scale,
                             dvdrow * im.scale, dvdcol * im.scale, row0, col0)
                for im in self.images
            ]

        # check if weights,segs,jacks are lists
        if not isinstance(self.weights, list):
            raise TypeError('weights should be a list')
        if not isinstance(self.segs, list):
            raise TypeError('segs should be a list')
        if not isinstance(self.wcstrans, list):
            raise TypeError('wcstrans should be a list')

        # loop through the images and check if they are of the same size
        for extname in ('images', 'weights', 'segs'):

            # get the class field
            ext = eval('self.' + extname)

            # loop through exposures
            for icutout, cutout in enumerate(ext):

                # get the sizes of array
                nx = cutout.array.shape[0]
                ny = cutout.array.shape[1]

                # x and y size should be the same
                if nx != ny:
                    raise ValueError('%s should be square and is %d x %d' %
                                     (extname, nx, ny))

                # check if box size is correct
                if nx != self.box_size:
                    raise ValueError(
                        '%s object %d has size %d and should be %d' %
                        (extname, icutout, nx, self.box_size))

        # see if the number of Jacobians is right
        if len(self.wcstrans) != self.n_cutouts:
            raise ValueError(
                'number of Jacobians is %d is not equal to number of cutouts %d'
                % (len(self.wcstrans), self.n_cutouts))

        # check each Jacobian
        for jac in self.wcstrans:
            # should ba a WCSTransform instance
            if not isinstance(jac, WCSTransform):
                raise TypeError(
                    'wcstrans list should contain WCSTransform objects')
def test_coadd_image_correct(crazy_wcs, crazy_obj):

    rng = np.random.RandomState(seed=42)

    n_coadd = 10
    psf_dim = 51
    coadd_dim = 53

    coadd_cen = (coadd_dim + 1) / 2

    se_dim = int(np.ceil(coadd_dim * np.sqrt(2)))
    if se_dim % 2 == 0:
        se_dim += 1

    se_cen = (se_dim + 1) / 2
    scale = 0.2
    noise_std = 0.1
    world_origin = galsim.CelestialCoord(0 * galsim.degrees,
                                         0 * galsim.degrees)

    aff = galsim.PixelScale(scale).affine()
    aff = aff.withOrigin(galsim.PositionD(coadd_cen, coadd_cen),
                         galsim.PositionD(0, 0))
    coadd_wcs = galsim.TanWCS(
        aff,
        world_origin,
    )

    def _gen_psf_func(wcs, fwhm):
        def _psf_func(*args, **kargs):
            return galsim.Gaussian(fwhm=fwhm).drawImage(
                nx=101, ny=101,
                wcs=wcs.local(world_pos=world_origin)), galsim.PositionD(0, 0)

        return _psf_func

    wgts = []
    objs = []
    psf_objs = []
    exps = []
    for _ in range(n_coadd):
        if crazy_obj:
            _fwhm = 2.9 * (1.0 + rng.normal() * 0.1)
            _g1 = rng.normal() * 0.3
            _g2 = rng.normal() * 0.3
            obj = galsim.Gaussian(fwhm=_fwhm).shear(g1=_g1, g2=_g2)
        else:
            obj = galsim.Gaussian(fwhm=2.9).shear(g1=-0.1, g2=0.3)

        objs.append(obj)

        if crazy_wcs:
            shear = galsim.Shear(g1=rng.normal() * 0.01,
                                 g2=rng.normal() * 0.01)
            aff = galsim.ShearWCS(scale, shear).affine()
            aff = aff.withOrigin(galsim.PositionD(se_cen, se_cen),
                                 galsim.PositionD(0, 0))
            wcs = galsim.TanWCS(
                aff,
                world_origin,
            )
        else:
            aff = galsim.PixelScale(scale).affine()
            aff = aff.withOrigin(galsim.PositionD(se_cen, se_cen),
                                 galsim.PositionD(0, 0))
            wcs = galsim.TanWCS(
                aff,
                world_origin,
            )

        _noise = noise_std * (1 + (rng.uniform() - 0.5) * 2 * 0.05)
        wgts.append(1.0 / _noise**2)

        bmsk = galsim.ImageI(np.zeros((se_dim, se_dim)))

        img = obj.drawImage(
            nx=se_dim,
            ny=se_dim,
            wcs=wcs.local(world_pos=world_origin),
        )

        if crazy_obj:
            _psf_fwhm = 1.0 * (1.0 + rng.normal() * 0.1)
        else:
            _psf_fwhm = 1.0

        psf = galsim.Gaussian(fwhm=_psf_fwhm)
        psf_objs.append(psf)

        exp = make_exp(
            gsimage=img,
            bmask=bmsk,
            noise=_noise,
            galsim_wcs=wcs,
            galsim_psf=psf,
            psf_dim=psf_dim,
        )
        exps.append(exp)

    coadd_bbox = geom.Box2I(
        geom.IntervalI(min=0, max=coadd_dim - 1),
        geom.IntervalI(min=0, max=coadd_dim - 1),
    )
    coadd, exp_info = make_coadd_obs(
        exps=exps,
        coadd_wcs=make_dm_wcs(coadd_wcs),
        coadd_bbox=coadd_bbox,
        psf_dims=(psf_dim, ) * 2,
        rng=rng,
        remove_poisson=False,
    )

    coadd_img = coadd.image
    coadd_psf = coadd.psf.image

    wgts = np.array(wgts) / np.sum(wgts)
    true_coadd_img = galsim.Sum([
        obj.withFlux(wgt) for obj, wgt in zip(objs, wgts)
    ]).drawImage(nx=coadd_dim,
                 ny=coadd_dim,
                 wcs=coadd_wcs.local(world_pos=world_origin)).array

    true_coadd_psf = galsim.Sum([
        obj.withFlux(wgt) for obj, wgt in zip(psf_objs, wgts)
    ]).drawImage(nx=psf_dim,
                 ny=psf_dim,
                 wcs=coadd_wcs.local(world_pos=world_origin)).array

    if not crazy_wcs:
        rtol = 0
        atol = 5e-7
    else:
        rtol = 0
        atol = 5e-5

    coadd_img_err = np.max(np.abs(coadd_img - true_coadd_img))
    coadd_psf_err = np.max(np.abs(coadd_psf - true_coadd_psf))
    print("image max abs error:", coadd_img_err)
    print("psf max abs error:", coadd_psf_err)

    if not np.allclose(coadd_img, true_coadd_img, rtol=rtol, atol=atol):
        _plot_cmp(coadd_img, true_coadd_img, rtol, atol, crazy_obj, crazy_wcs,
                  "img")

    if not np.allclose(coadd_psf, true_coadd_psf, rtol=rtol, atol=atol):
        _plot_cmp(coadd_psf, true_coadd_psf, rtol, atol, crazy_obj, crazy_wcs,
                  "psf")

    assert np.allclose(coadd_img, true_coadd_img, rtol=rtol, atol=atol)
    assert np.allclose(coadd_psf, true_coadd_psf, rtol=rtol, atol=atol)
    assert np.all(np.isfinite(coadd.noise))
Example #8
0
def test_poisson_noise():
    """Test Poisson random number generator
    """
    pMean = 17
    p = galsim.PoissonDeviate(testseed, mean=pMean)
    pResult = np.empty((10, 10))
    p.generate(pResult)
    noise = galsim.DeviateNoise(p)

    # Test filling an image
    noise.rng.seed(testseed)
    testimage = galsim.ImageI(10, 10)
    testimage.addNoise(galsim.DeviateNoise(p))
    np.testing.assert_array_equal(
        testimage.array,
        pResult,
        err_msg=
        'Wrong poisson random number sequence generated when applied to image.'
    )

    # The PoissonNoise version also subtracts off the mean value
    pn = galsim.PoissonNoise(galsim.BaseDeviate(testseed), sky_level=pMean)
    testimage.fill(0)
    testimage.addNoise(pn)
    np.testing.assert_array_equal(
        testimage.array,
        pResult - pMean,
        err_msg=
        'Wrong poisson random number sequence generated using PoissonNoise')

    # Test filling a single-precision image
    pn.rng.seed(testseed)
    testimage = galsim.ImageF(10, 10)
    testimage.addNoise(pn)
    np.testing.assert_array_almost_equal(
        testimage.array,
        pResult - pMean,
        precisionF,
        err_msg=
        'Wrong Poisson random number sequence generated when applied to ImageF.'
    )

    # Test filling an image with Fortran ordering
    pn.rng.seed(testseed)
    testimage = galsim.ImageD(10, 10)
    testimage.addNoise(pn)
    np.testing.assert_array_almost_equal(
        testimage.array,
        pResult - pMean,
        err_msg="Wrong Poisson noise generated for Fortran-ordered Image")

    # Check PoissonNoise variance:
    np.testing.assert_almost_equal(
        pn.getVariance(),
        pMean,
        precision,
        err_msg="PoissonNoise getVariance returns wrong variance")
    np.testing.assert_almost_equal(
        pn.sky_level,
        pMean,
        precision,
        err_msg="PoissonNoise sky_level returns wrong value")

    # Check that the noise model really does produce this variance.
    big_im = galsim.Image(2048, 2048, dtype=float)
    big_im.addNoise(pn)
    var = np.var(big_im.array)
    print('variance = ', var)
    print('getVar = ', pn.getVariance())
    np.testing.assert_almost_equal(
        var,
        pn.getVariance(),
        1,
        err_msg='Realized variance for PoissonNoise did not match getVariance()'
    )

    # Check that PoissonNoise adds to the image, not overwrites the image.
    gal = galsim.Exponential(half_light_radius=2.3, flux=0.3)
    # Note: in this case, flux/size^2 needs to be << sky_level or it will mess up the statistics.
    gal.drawImage(image=big_im)
    big_im.addNoise(pn)
    gal.withFlux(-0.3).drawImage(image=big_im, add_to_image=True)
    var = np.var(big_im.array)
    np.testing.assert_almost_equal(
        var,
        pn.getVariance(),
        1,
        err_msg='PoissonNoise wrong when already an object drawn on the image')

    # Check withVariance
    pn = pn.withVariance(9.)
    np.testing.assert_almost_equal(
        pn.getVariance(),
        9.,
        precision,
        err_msg="PoissonNoise withVariance results in wrong variance")
    np.testing.assert_almost_equal(
        pn.sky_level,
        9.,
        precision,
        err_msg="PoissonNoise withVariance results in wrong sky_level")

    # Check withScaledVariance
    pn = pn.withScaledVariance(4.)
    np.testing.assert_almost_equal(
        pn.getVariance(),
        36,
        precision,
        err_msg="PoissonNoise withScaledVariance results in wrong variance")
    np.testing.assert_almost_equal(
        pn.sky_level,
        36.,
        precision,
        err_msg="PoissonNoise withScaledVariance results in wrong sky_level")

    # Check arithmetic
    pn = pn.withVariance(0.5)
    pn2 = pn * 3
    np.testing.assert_almost_equal(
        pn2.getVariance(),
        1.5,
        precision,
        err_msg="PoissonNoise pn*3 results in wrong variance")
    np.testing.assert_almost_equal(
        pn.getVariance(),
        0.5,
        precision,
        err_msg="PoissonNoise pn*3 results in wrong variance for original pn")
    pn2 = 5 * pn
    np.testing.assert_almost_equal(
        pn2.getVariance(),
        2.5,
        precision,
        err_msg="PoissonNoise 5*pn results in wrong variance")
    np.testing.assert_almost_equal(
        pn.getVariance(),
        0.5,
        precision,
        err_msg="PoissonNoise 5*pn results in wrong variance for original pn")
    pn2 = pn / 2
    np.testing.assert_almost_equal(
        pn2.getVariance(),
        0.25,
        precision,
        err_msg="PoissonNoise pn/2 results in wrong variance")
    np.testing.assert_almost_equal(
        pn.getVariance(),
        0.5,
        precision,
        err_msg="PoissonNoise 5*pn results in wrong variance for original pn")
    pn *= 3
    np.testing.assert_almost_equal(
        pn.getVariance(),
        1.5,
        precision,
        err_msg="PoissonNoise pn*=3 results in wrong variance")
    pn /= 2
    np.testing.assert_almost_equal(
        pn.getVariance(),
        0.75,
        precision,
        err_msg="PoissonNoise pn/=2 results in wrong variance")

    # Check starting with PoissonNoise()
    pn = galsim.PoissonNoise()
    pn = pn.withVariance(9.)
    np.testing.assert_almost_equal(
        pn.getVariance(),
        9.,
        precision,
        err_msg="PoissonNoise().withVariance results in wrong variance")
    np.testing.assert_almost_equal(
        pn.sky_level,
        9.,
        precision,
        err_msg="PoissonNoise().withVariance results in wrong sky_level")
    pn = pn.withScaledVariance(4.)
    np.testing.assert_almost_equal(
        pn.getVariance(),
        36,
        precision,
        err_msg="PoissonNoise().withScaledVariance results in wrong variance")
    np.testing.assert_almost_equal(
        pn.sky_level,
        36.,
        precision,
        err_msg="PoissonNoise().withScaledVariance results in wrong sky_level")

    # Check picklability
    do_pickle(pn, lambda x: (x.rng.serialize(), x.sky_level))
    do_pickle(pn, drawNoise)
    do_pickle(pn)

    # Check copy, eq and ne
    pn = pn.withVariance(pMean)
    pn2 = galsim.PoissonNoise(pn.rng.duplicate(), pMean)
    pn3 = pn.copy()
    pn4 = pn.copy(rng=galsim.BaseDeviate(11))
    pn5 = galsim.PoissonNoise(pn.rng, 2 * pMean)
    assert pn == pn2
    assert pn == pn3
    assert pn != pn4
    assert pn != pn5
    assert pn.rng.raw() == pn2.rng.raw()
    assert pn == pn2
    assert pn == pn3
    pn.rng.raw()
    assert pn != pn2
    assert pn == pn3
Example #9
0
def test_init():
    """Test the basic initialization of a StarData object.
    """

    # Use an odd-sized image, so image.true_center and image.center are the same thing.
    # Otherwise, u,v below will be half-integer values.
    size = 63

    # Center the image at a non-trivial location to simulate this being a cutout from a larger
    # image.
    icen = 598
    jcen = 109

    # Use pixel scale = 1, so image_pos and focal pos are the same thing.
    image = galsim.Image(size,size, scale=1)
    field_pos = image.center

    # Update the bounds so the image is centered at icen, jcen.
    # Note: this also updates the wcs, so u,v at the center is still field_pos
    image.setCenter(icen, jcen)

    # Just draw something so it has non-trivial pixel values.
    galsim.Gaussian(sigma=5).drawImage(image)

    weight = galsim.ImageI(image.bounds, init_value=1)  # all weights = 1
    # To make below tests of weight pixel values useful, add the image to weight, so pixel
    # values are not all identical.

    image_pos = image.center

    properties = {
        'ra' : 34.1234,
        'dec' : -15.567,
        'color_ri' : 0.5,
        'color_iz' : -0.2,
        'ccdnum' : 3
    }

    stardata = piff.StarData(image, image_pos, weight=weight, properties=properties)

    # Test attributes
    np.testing.assert_array_equal(stardata.image.array, image.array)
    np.testing.assert_array_equal(stardata.weight.array, weight.array)
    np.testing.assert_equal(stardata.image_pos, image_pos)

    # Test properties access viw properties attribute or directly with []
    for key, value in properties.items():
        np.testing.assert_equal(stardata.properties[key], value)
        np.testing.assert_equal(stardata[key], value)

    # Test the automatically generated properties
    print('image_pos = ',image_pos)
    print('image.wcs = ',image.wcs)
    print('props = ',stardata.properties)
    for key, value in [ ('x',image_pos.x), ('y',image_pos.y),
                        ('u',field_pos.x), ('v',field_pos.y) ]:
        np.testing.assert_equal(stardata.properties[key], value)
        np.testing.assert_equal(stardata[key], value)

    # Test access via getImage method:
    im, wt, pos = stardata.getImage()
    np.testing.assert_array_equal(im.array, image.array)
    np.testing.assert_array_equal(wt.array, weight.array)
    np.testing.assert_equal(pos, image_pos)

    # Test access via getDataVector method:
    # Note: This array() and then .T is like zip for Python lists.
    for data, wt, u, v in np.array(stardata.getDataVector()).T:
        # In this case, these should be integers, but round in case of numerical inaccuracy.
        iu = int(round(u))
        jv = int(round(v))
        # GalSim images access pixels as (x,y)
        np.testing.assert_equal(data, image(iu+icen,jv+jcen))
        np.testing.assert_equal(wt, weight(iu+icen,jv+jcen))
        # Numpy arrays access elements as [y,x]
        np.testing.assert_equal(data, image.array[jv+size//2, iu+size//2])
        np.testing.assert_equal(wt, weight.array[jv+size//2, iu+size//2])

    print("Passed basic initialization of StarData")
Example #10
0
File: star.py Project: emhuff/Piff
    def load_images(stars,
                    file_name,
                    pointing=None,
                    image_hdu=None,
                    weight_hdu=None,
                    badpix_hdu=None,
                    sky=None,
                    logger=None):
        """Load the image data into a list of Stars.

        We don't store the image data for Stars when we write them to a file, since that
        would take up a lot of space and is usually not desired.  However, we do store the
        bounds in the original image where the star was cutout, so if you want to load back in
        the original data from the image file, you can do so with this function.

        :param stars:           A list of Star instances.
        :param file_name:       The file with the image data for these stars.
        :param pointing:        The pointing direction to use. [default: None]
        :param image_hdu:       The hdu to use for the main image. [default: None, which means
                                either 0 or 1 as appropriate according to the compression.]
        :param weight_hdu:      The hdu to use for the weight image. [default: None]
        :param badpix_hdu:      The hdu to use for the bad pixel mask. [default: None]
        :param sky:             Optional sky image or float value to subtract from the main
                                image. [default: None]
        :param logger:          A logger object for logging debug info. [default: None]

        :returns: a new list of Stars with the images information loaded.
        """
        import galsim
        # TODO: This is largely copied from InputHandler.readImages.
        #       This should probably be refactored a bit to avoid the duplicated code.
        logger = galsim.config.LoggerWrapper(logger)
        logger.info("Loading image information from file %s", file_name)
        image = galsim.fits.read(file_name, hdu=image_hdu)

        if sky is not None:
            image = image - sky

        # Either read in the weight image, or build a dummy one
        if weight_hdu is None:
            logger.debug("Making trivial (wt==1) weight image")
            weight = galsim.ImageI(image.bounds, init_value=1)
        else:
            logger.info("Reading weight image from hdu %d.", weight_hdu)
            weight = galsim.fits.read(file_name, hdu=weight_hdu)
            if np.all(weight.array == 0):
                logger.error(
                    "According to the weight mask in %s, all pixels have zero weight!",
                    file_name)

        # If requested, set wt=0 for any bad pixels
        if badpix_hdu is not None:
            logger.info("Reading badpix image from hdu %d.", badpix_hdu)
            badpix = galsim.fits.read(file_name, hdu=badpix_hdu)
            # The badpix image may be offset by 32768 from the true value.
            # If so, subtract it off.
            if np.any(badpix.array > 32767):
                logger.debug('min(badpix) = %s', np.min(badpix.array))
                logger.debug('max(badpix) = %s', np.max(badpix.array))
                logger.debug(
                    "subtracting 32768 from all values in badpix image")
                badpix -= 32768
            if np.any(badpix.array < -32767):
                logger.debug('min(badpix) = %s', np.min(badpix.array))
                logger.debug('max(badpix) = %s', np.max(badpix.array))
                logger.debug("adding 32768 to all values in badpix image")
                badpix += 32768
            # Also, convert to int16, in case it isn't by default.
            badpix = galsim.ImageS(badpix)
            if np.all(badpix.array != 0):
                logger.error(
                    "According to the bad pixel array in %s, all pixels are masked!",
                    file_name)
            weight.array[badpix.array != 0] = 0

        stars = [
            Star(data=StarData(image=image[star.data.image.bounds],
                               image_pos=star.data.image_pos,
                               weight=weight[star.data.image.bounds],
                               pointing=(pointing if pointing is not None else
                                         star.data.pointing),
                               properties=star.data.properties,
                               _xyuv_set=True),
                 fit=star.fit) for star in stars
        ]
        return stars
Example #11
0
import numpy as np

# make a galsim Gaussian image, get moments
imsize = 513
g_sigma = 4.
pix_scale = 0.2
s_hlr = 2.0
g = galsim.Gaussian(sigma=g_sigma)
g_im = galsim.ImageF(imsize, imsize)
g_im = g.draw(image=g_im, dx=pix_scale)
res = g_im.FindAdaptiveMom()
print "Results for Gaussian without masking:"
print "e1, e2, sigma: ",res.observed_shape.e1, res.observed_shape.e2, res.moments_sigma

# now mask center pixel, make sure moments are same
mask_im = galsim.ImageI(g_im.bounds)+1
cent_pix = int(round(0.5*(g_im.xmax+g_im.xmin)))
mask_im.setValue(cent_pix, cent_pix, 0)
res = g_im.FindAdaptiveMom(object_mask_image = mask_im)
print "\nResults after masking central pixel at ",cent_pix
print "e1, e2, sigma: ",res.observed_shape.e1, res.observed_shape.e2, res.moments_sigma

# now mask central 9x9 pixels, make sure moments are same
mask_im.setValue(cent_pix-1, cent_pix-1, 0)
mask_im.setValue(cent_pix-1, cent_pix, 0)
mask_im.setValue(cent_pix-1, cent_pix+1, 0)
mask_im.setValue(cent_pix, cent_pix-1, 0)
mask_im.setValue(cent_pix, cent_pix+1, 0)
mask_im.setValue(cent_pix+1, cent_pix-1, 0)
mask_im.setValue(cent_pix+1, cent_pix, 0)
mask_im.setValue(cent_pix+1, cent_pix+1, 0)