示例#1
0
def test_fail():
    # Some vv noisy images that result in errors in the fit to check the error reporting.

    scale = 1.3
    g1 = 0.33
    g2 = -0.27
    flux = 15
    noise = 2.
    seed = 1234

    psf = galsim.Moffat(half_light_radius=1.0, beta=2.5, trunc=3.0)
    psf = psf.dilate(scale).shear(g1=g1, g2=g2).withFlux(flux)
    image = psf.drawImage(nx=64, ny=64, scale=0.3)

    weight = image.copy()
    weight.fill(1 / noise**2)
    noisy_image = image.copy()
    rng = galsim.BaseDeviate(seed)
    noisy_image.addNoise(galsim.GaussianNoise(sigma=noise, rng=rng))

    star1 = piff.Star(piff.StarData(image, image.true_center, weight), None)
    star2 = piff.Star(piff.StarData(noisy_image, image.true_center, weight),
                      None)

    model1 = piff.Moffat(fastfit=True, beta=2.5)
    with np.testing.assert_raises(RuntimeError):
        model1.initialize(star2)
    with np.testing.assert_raises(RuntimeError):
        model1.fit(star2)
    star3 = model1.initialize(star1)
    star3 = model1.fit(star3)
    star3 = piff.Star(star2.data, star3.fit)
    with np.testing.assert_raises(RuntimeError):
        model1.fit(star3)

    # This is contrived to hit the fit failure for the reference.
    # I'm not sure what realistic use case would actually hit it, but at least it's
    # theoretically possible to fail there.
    model2 = piff.GSObjectModel(galsim.InterpolatedImage(noisy_image),
                                fastfit=True)
    with np.testing.assert_raises(RuntimeError):
        model2.initialize(star1)

    model3 = piff.Moffat(fastfit=False,
                         beta=2.5,
                         scipy_kwargs={'max_nfev': 10})
    with np.testing.assert_raises(RuntimeError):
        model3.initialize(star2)
    with np.testing.assert_raises(RuntimeError):
        model3.fit(star2).fit
    star3 = model3.initialize(star1)
    star3 = model3.fit(star3)
    star3 = piff.Star(star2.data, star3.fit)
    with np.testing.assert_raises(RuntimeError):
        model3.fit(star3)
示例#2
0
def test_psf():
    """Test PSF base class
    """
    # Need a dummy star for the below calls
    image = galsim.Image(1, 1, scale=1)
    stardata = piff.StarData(image, image.true_center)
    star = piff.Star(stardata, None)

    # Can't do much with a base PSF class
    psf = piff.PSF()
    np.testing.assert_raises(NotImplementedError, psf.parseKwargs, None)
    np.testing.assert_raises(NotImplementedError, psf.interpolateStar, star)
    np.testing.assert_raises(NotImplementedError, psf.interpolateStarList,
                             [star])
    np.testing.assert_raises(NotImplementedError, psf.drawStar, star)
    np.testing.assert_raises(NotImplementedError, psf.drawStarList, [star])
    np.testing.assert_raises(NotImplementedError, psf._drawStar, star)

    # Invalid to read a type that isn't a piff.PSF type.
    # Mock this by pretending that SingleChip is the only subclass of PSF.
    if sys.version_info < (3, ): return  # mock only available on python 3
    from unittest import mock
    filename = os.path.join('input', 'D00240560_r_c01_r2362p01_piff.fits')
    with mock.patch('piff.util.get_all_subclasses',
                    return_value=[piff.SingleChipPSF]):
        np.testing.assert_raises(ValueError, piff.PSF.read, filename)
示例#3
0
def test_Gaussian():
    """This is about the simplest possible model I could think of.  It just uses the
    HSM adaptive moments routine to measure the moments, and then it models the
    PSF as a Gaussian.
    """

    # Here is the true PSF
    sigma = 1.3
    g1 = 0.23
    g2 = -0.17
    psf = galsim.Gaussian(sigma=sigma).shear(g1=g1, g2=g2)

    # Draw the PSF onto an image.  Let's go ahead and give it a non-trivial WCS.
    wcs = galsim.JacobianWCS(0.26, 0.05, -0.08, -0.29)
    image = galsim.Image(64,64, wcs=wcs)
    # This is only going to come out right if we (unphysically) don't convolve by the pixel.
    psf.drawImage(image, method='no_pixel')

    # Make a StarData instance for this image
    stardata = piff.StarData(image, image.true_center)
    star = piff.Star(stardata, None)

    # Fit the model from the image
    model = piff.Gaussian(include_pixel=False)
    star = model.initialize(star)
    fit = model.fit(star).fit

    print('True sigma = ',sigma,', model sigma = ',fit.params[0])
    print('True g1 = ',g1,', model g1 = ',fit.params[1])
    print('True g2 = ',g2,', model g2 = ',fit.params[2])

    # This test is pretty accurate, since we didn't add any noise and didn't convolve by
    # the pixel, so the image is very accurately a sheared Gaussian.
    true_params = [ sigma, g1, g2 ]
    np.testing.assert_almost_equal(fit.params[0], sigma, decimal=7)
    np.testing.assert_almost_equal(fit.params[1], g1, decimal=7)
    np.testing.assert_almost_equal(fit.params[2], g2, decimal=7)
    np.testing.assert_almost_equal(fit.params, true_params, decimal=7)

    # Now test running it via the config parser
    config = {
        'model' : {
            'type' : 'Gaussian',
            'include_pixel': False
        }
    }
    if __name__ == '__main__':
        logger = piff.config.setup_logger(verbose=2)
    else:
        logger = piff.config.setup_logger(log_file='output/test_Gaussian.log')
    model = piff.Model.process(config['model'], logger)
    fit = model.fit(star).fit

    # Same tests.
    np.testing.assert_almost_equal(fit.params[0], sigma, decimal=7)
    np.testing.assert_almost_equal(fit.params[1], g1, decimal=7)
    np.testing.assert_almost_equal(fit.params[2], g2, decimal=7)
    np.testing.assert_almost_equal(fit.params, true_params, decimal=7)
示例#4
0
def test_decam_wavefront():
    file_name = 'input/Science-20121120s1-v20i2.fits'
    extname = 'Science-20121120s1-v20i2'

    if __name__ == '__main__':
        logger = piff.config.setup_logger(verbose=2)
    else:
        logger = piff.config.setup_logger(log_file='output/test_decam.log')
    knn = piff.des.DECamWavefront(file_name, extname, logger=logger)

    n_samples = 2000
    np_rng = np.random.RandomState(1234)
    ccdnums = np_rng.randint(1, 63, n_samples)

    star_list = []
    for ccdnum in ccdnums:
        # make some basic images, pass Xi as properties
        # Draw the PSF onto an image.  Let's go ahead and give it a non-trivial WCS.
        wcs = galsim.JacobianWCS(0.26, 0.05, -0.08, -0.29)
        image = galsim.Image(64,64, wcs=wcs)
        # set icen and jcen
        icen = np_rng.randint(100, 2048)
        jcen = np_rng.randint(100, 4096)
        image.setCenter(icen, jcen)
        image_pos = image.center

        stardata = piff.StarData(image, image_pos, properties={'chipnum': ccdnum})

        star = piff.Star(stardata, None)
        star_list.append(star)

    # get the focal positions
    star_list = piff.des.DECamInfo().pixel_to_focalList(star_list)

    star_list_predicted = knn.interpolateList(star_list)

    # test misalignment
    misalignment = {'z04d': 10, 'z10x': 10, 'z09y': -10}
    knn.misalign_wavefront(misalignment)
    star_list_misaligned = knn.interpolateList(star_list)

    # test the prediction algorithm
    y_predicted = np.array([s.fit.params for s in star_list_predicted])
    y_misaligned = np.array([s.fit.params for s in star_list_misaligned])
    X = np.array([knn.getProperties(s) for s in star_list])

    # check the misalignments work
    np.testing.assert_array_almost_equal(y_predicted[:,0], y_misaligned[:,0] - misalignment['z04d'])
    np.testing.assert_array_almost_equal(y_predicted[:,5], y_misaligned[:,5] - misalignment['z09y'] * X[:,0])
    np.testing.assert_array_almost_equal(y_predicted[:,6], y_misaligned[:,6] - misalignment['z10x'] * X[:,1])

    # Check shape of misalignment if array
    np.testing.assert_raises(ValueError, knn.misalign_wavefront, knn.misalignment[:,:2])
    np.testing.assert_raises(ValueError, knn.misalign_wavefront, knn.misalignment[:-1,:])

    # empty dict is equivalent to no misalignment
    knn.misalign_wavefront({})
    np.testing.assert_equal(knn.misalignment, 0.)
示例#5
0
def test_extra_interp():
    # Test that specifying extra_interp_properties works properly
    # TODO: This is a very bare bones test of the interface.  There is basically no test of
    #       this functionality at all yet.  TBD!

    sigma = 1.3
    g1 = 0.23
    g2 = -0.17
    psf = galsim.Gaussian(sigma=sigma).shear(g1=g1, g2=g2)
    wcs = galsim.JacobianWCS(0.26, 0.05, -0.08, -0.29)
    image = galsim.Image(64, 64, wcs=wcs)
    psf.drawImage(image, method='no_pixel')

    # use g-i color as an extra property for interpolation.
    props = dict(gi_color=0.3)
    print('props = ', props)
    star = piff.Star(piff.StarData(image, image.true_center, properties=props),
                     None)

    model = piff.Gaussian(fastfit=True, include_pixel=False)
    interp = piff.Mean()
    psf = piff.SimplePSF(model, interp, extra_interp_properties=['gi_color'])
    assert psf.extra_interp_properties == ['gi_color']

    # Note: Mean doesn't actually do anything useful with the extra properties, so this
    #       isn't really testing anything other than that the code doesn't completely break.
    pointing = galsim.CelestialCoord(-5 * galsim.arcmin, -25 * galsim.degrees)
    psf.fit([star], wcs={0: wcs}, pointing=pointing)

    # Not much of a check here.  Just check that it actually draws something with flux ~= 1
    im = psf.draw(x=5, y=7, gi_color=0.3)
    np.testing.assert_allclose(im.array.sum(), 1.0, rtol=1.e-3)

    # Check missing or extra properties
    with np.testing.assert_raises(TypeError):
        psf.draw(x=5, y=7)
    with np.testing.assert_raises(TypeError):
        psf.draw(x=5, y=7, gi_color=0.3, ri_color=3)

    # No stars raises an error.  (This can happen in practice if all stars are excluded on input.)
    with np.testing.assert_raises(RuntimeError):
        psf.fit([], wcs={0: wcs}, pointing=pointing)

    # Also for SingleChipPSf
    psf2 = piff.SingleChipPSF(psf, extra_interp_properties=['gi_color'])
    assert psf2.extra_interp_properties == ['gi_color']

    with np.testing.assert_raises(TypeError):
        psf2.draw(x=5, y=7, chipnum=0)
示例#6
0
def drawProfile(self, star, prof, params, use_fit=True, copy_image=True, interpfunc=None):
    """Generate PSF image for a given star and profile

    :param star:        Star instance holding information needed for
                        interpolation as well as an image/WCS into which
                        PSF will be rendered.
    :param profile:     A galsim profile
    :param params:      Params associated with profile to put in the star.
    :param use_fit:     Bool [default: True] shift the profile by a star's
                        fitted center and multiply by its fitted flux
    :param self:        PSF instance
    :param interpfunc:  The interpolation function

    :returns:           Star instance with its image filled with rendered
                        PSF
    """
    # use flux and center properties
    if use_fit:
        prof = prof.shift(star.fit.center) * star.fit.flux
    image, weight, image_pos = star.data.getImage()
    if copy_image:
        image_model = image.copy()
    else:
        image_model = image
    prof.drawImage(image_model, method='auto', offset=(star.image_pos-image_model.true_center))

    properties = star.data.properties.copy()
    for key in ['x', 'y', 'u', 'v']:
        # Get rid of keys that constructor doesn't want to see:
        properties.pop(key, None)
    data = piff.StarData(image=image_model,
                    image_pos=star.data.image_pos,
                    weight=star.data.weight,
                    pointing=star.data.pointing,
                    field_pos=star.data.field_pos,
                    values_are_sb=star.data.values_are_sb,
                    orig_weight=star.data.orig_weight,
                    properties=properties)
    fit = piff.StarFit(params,
                  flux=star.fit.flux,
                  center=star.fit.center)
    new_s = piff.Star(data, fit)

    # apply radial correction
    if interpfunc is not None:
        new_im = apply_correction(new_s, interpfunc)
        new_s = piff.Star(new_s.data.setData(new_im.flatten(), include_zero_weight=True), new_s.fit)

    return new_s
示例#7
0
def generate_data(n_samples=100):
    # generate as Norm(0, 1) for all parameters
    np_rng = np.random.RandomState(1234)
    X = np_rng.normal(0, 1, size=(n_samples, len(keys)))
    y = np_rng.normal(0, 1, size=(n_samples, ntarget))

    star_list = []
    for Xi, yi in zip(X, y):
        wcs = galsim.JacobianWCS(0.26, 0.05, -0.08, -0.29)
        image = galsim.Image(64,64, wcs=wcs)
        properties = {k:v for k,v in zip(keys, Xi)}
        stardata = piff.StarData(image, image.true_center, properties=properties)

        # params = np.array([yi[ith] for ith in attr_target])
        params = yi
        starfit = piff.StarFit(params)
        star = piff.Star(stardata, starfit)
        star_list.append(star)

    return star_list
示例#8
0
def test_add_poisson():
    """Test the addPoisson() method
    """
    size = 23
    icen = 598
    jcen = 109
    image = galsim.Image(size, size, scale=0.25)
    image.setCenter(icen, jcen)
    image_pos = image.center

    # Make a signal image
    galsim.Gaussian(sigma=1.1, flux=100).drawImage(image)
    stardata1 = piff.StarData(image, image_pos, weight=4)

    # Make another stardata with a blank image
    image2 = galsim.ImageF(image.bounds, init_value=0)
    weight = galsim.ImageF(image.bounds, init_value=0.025)
    stardata2 = piff.StarData(image, image_pos, weight=weight)

    # Add poisson noise with gain=1
    test = stardata2.addPoisson(stardata1, gain=1)
    np.testing.assert_allclose(1. / test.weight.array,
                               1. / weight.array + image.array)

    # Note repeated application always adds to the original weight map, not the current one.
    test = test.addPoisson(stardata1, gain=3)
    np.testing.assert_allclose(1. / test.weight.array,
                               1. / weight.array + image.array / 3)

    test = test.addPoisson(stardata1, gain=2)
    np.testing.assert_allclose(1. / test.weight.array,
                               1. / weight.array + image.array / 2)

    # gain=None means don't change anything
    test = stardata2.addPoisson(stardata1)
    np.testing.assert_allclose(test.weight.array, stardata2.weight.array)

    # signal=None means use self for signal
    test = stardata1.addPoisson(gain=2)
    np.testing.assert_allclose(1. / test.weight.array,
                               1. / stardata1.weight.array + image.array / 2)

    # If gain is in properties, use that
    stardata3 = piff.StarData(image,
                              image_pos,
                              weight=weight,
                              properties=dict(gain=4))
    test = stardata3.addPoisson(stardata1)
    np.testing.assert_allclose(1. / test.weight.array,
                               1. / weight.array + image.array / 4)

    # But explicit gain takes precedence
    test = stardata3.addPoisson(stardata1, gain=0.3)
    np.testing.assert_allclose(1. / test.weight.array,
                               1. / weight.array + image.array / 0.3)

    # After one application with gain, the star remembers that value.
    test = stardata2.addPoisson(stardata2, gain=2)
    test = test.addPoisson(stardata1)
    np.testing.assert_allclose(1. / test.weight.array,
                               1. / weight.array + image.array / 2)

    # Error if signal is different shape
    small_image = galsim.Image(15, 15, scale=0.25)
    stardata4 = piff.StarData(small_image, image_pos)
    with np.testing.assert_raises(ValueError):
        stardata2.addPoisson(stardata4, gain=1)

    # Equivalent to access function from Star class
    star = piff.Star(stardata2, None)
    test = star.addPoisson(stardata1, gain=3)
    np.testing.assert_allclose(1. / test.weight.array,
                               1. / weight.array + image.array / 3)
示例#9
0
    def makeStars(self, logger=None):
        """Process the input images and star data, cutting out stamps for each star along with
        other relevant information.

        The base class implementation expects the derived class to have appropriately set the
        following attributes:

            :stamp_size:    The size of the postage stamp to use for the cutouts
            :x_col:         The name of the column in the catalogs to use for the x position.
            :y_col:         The name of the column in the catalogs to use for the y position.

        :param logger:      A logger object for logging debug info. [default: None]

        :returns: a list of Star instances
        """
        import galsim
        import piff

        stars = []
        if logger:
            if len(self.cats) == 1:
                logger.debug("Making star list from catalog %s", self.cat_files[0])
            else:
                logger.debug("Making star list from %d catalogs", len(self.cats))
        for i in range(len(self.images)):
            image = self.images[i]
            wt = self.weight[i]
            cat = self.cats[i]
            chipnum = self.chipnums[i]
            fname = self.cat_files[i]
            if logger:
                logger.info("Processing catalog %s with %d stars",fname,len(cat))
            nstars_in_image = 0
            for k in range(len(cat)):
                x = cat[self.x_col][k]
                y = cat[self.y_col][k]
                icen = int(x+0.5)
                jcen = int(y+0.5)
                half_size = self.stamp_size // 2
                bounds = galsim.BoundsI(icen+half_size-self.stamp_size+1, icen+half_size,
                                        jcen+half_size-self.stamp_size+1, jcen+half_size)
                if not image.bounds.includes(bounds):
                    bounds = bounds & image.bounds
                    if not bounds.isDefined():
                        if logger:
                            logger.warning("Star at position %f,%f is off the edge of the image."%(x,y))
                            logger.warning("Skipping this star.")
                        continue
                    if logger:
                        logger.info("Star at position %f,%f is near the edge of the image."%(x,y))
                        logger.info("Using smaller than the full stamp size: %s"%bounds)
                stamp = image[bounds]
                props = { 'chipnum' : chipnum }
                sky = None
                if self.sky_col is not None:
                    sky = cat[self.sky_col][k]
                elif self.sky is not None:
                    if type(self.sky) in [float, int]:
                        sky = float(self.sky)
                    elif str(self.sky) != self.sky:
                        raise ValueError("Unable to parse input sky: %s"%self.sky)
                    else:
                        file_name = self.image_files[0]
                        fits = fitsio.FITS(file_name)
                        hdu = 1 if file_name.endswith('.fz') else 0
                        header = fits[hdu].read_header()
                        sky = float(header[self.sky])
                if sky is not None:
                    if logger:
                        logger.debug("Subtracting off sky = %f", sky)
                    stamp = stamp - sky  # Don't change the original!
                    props['sky'] = sky
                wt_stamp = wt[bounds]
                # if a star is totally masked, then don't add it!
                if np.all(wt_stamp.array == 0):
                    if logger:
                        logger.warning("Star at position %f,%f is completely masked."%(x,y))
                        logger.warning("Skipping this star.")
                    continue
                pos = galsim.PositionD(x,y)
                data = piff.StarData(stamp, pos, weight=wt_stamp, pointing=self.pointing,
                                     properties=props)
                stars.append(piff.Star(data, None))

                nstars_in_image += 1
                if self.nstars is not None and nstars_in_image >= self.nstars:
                    if logger:
                        logger.info("Reached limit of %d stars in image %d",self.nstars,i)
                    break
        if logger:
            logger.warning("Read a total of %d stars from %d image%s",len(stars),len(self.images),
                           "s" if len(self.images) > 1 else "")

        return stars
示例#10
0
文件: input.py 项目: emhuff/Piff
    def makeStars(self, logger=None):
        """Process the input images and star data, cutting out stamps for each star along with
        other relevant information.

        The base class implementation expects the derived class to have appropriately set the
        following attributes:

            :stamp_size:    The size of the postage stamp to use for the cutouts
            :x_col:         The name of the column in the catalogs to use for the x position.
            :y_col:         The name of the column in the catalogs to use for the y position.

        :param logger:      A logger object for logging debug info. [default: None]

        :returns: a list of Star instances
        """
        import galsim
        import piff
        logger = galsim.config.LoggerWrapper(logger)

        stars = []
        if len(self.chipnums) == 1:
            logger.debug("Making star list")
        else:
            logger.debug("Making star list from %d catalogs",
                         len(self.chipnums))
        for image_num in range(len(self.chipnums)):
            image = self.images[image_num]
            wt = self.weight[image_num]
            image_pos = self.image_pos[image_num]
            sky = self.sky[image_num]
            gain = self.gain[image_num]
            chipnum = self.chipnums[image_num]
            logger.info("Processing catalog %s with %d stars", chipnum,
                        len(image_pos))
            nstars_in_image = 0
            for k in range(len(image_pos)):
                x = image_pos[k].x
                y = image_pos[k].y
                icen = int(x + 0.5)
                jcen = int(y + 0.5)
                half_size = self.stamp_size // 2
                bounds = galsim.BoundsI(icen + half_size - self.stamp_size + 1,
                                        icen + half_size,
                                        jcen + half_size - self.stamp_size + 1,
                                        jcen + half_size)
                if not image.bounds.includes(bounds):
                    bounds = bounds & image.bounds
                    if not bounds.isDefined():
                        logger.warning(
                            "Star at position %f,%f is off the edge of the image.  "
                            "Skipping this star.", x, y)
                        continue
                    if self.use_partial:
                        logger.info(
                            "Star at position %f,%f overlaps the edge of the image.  "
                            "Using smaller than the full stamp size: %s", x, y,
                            bounds)
                    else:
                        logger.warning(
                            "Star at position %f,%f overlaps the edge of the image.  "
                            "Skipping this star.", x, y)
                        continue
                stamp = image[bounds]
                props = {'chipnum': chipnum, 'gain': gain[k]}
                if sky is not None:
                    logger.debug("Subtracting off sky = %f", sky[k])
                    logger.debug("Median pixel value = %f",
                                 np.median(stamp.array))
                    stamp = stamp - sky[k]  # Don't change the original!
                    props['sky'] = sky[k]
                wt_stamp = wt[bounds]

                # if a star is totally masked, then don't add it!
                if np.all(wt_stamp.array == 0):
                    logger.warning(
                        "Star at position %f,%f is completely masked." %
                        (x, y))
                    logger.warning("Skipping this star.")
                    continue

                # Check the snr and limit it if appropriate
                snr = self.calculateSNR(stamp, wt_stamp)
                logger.debug("SNR = %f", snr)
                if self.min_snr is not None and snr < self.min_snr:
                    logger.info(
                        "Skipping star at position %f,%f with snr=%f." %
                        (x, y, snr))
                    continue
                if self.max_snr > 0 and snr > self.max_snr:
                    factor = (self.max_snr / snr)**2
                    logger.debug(
                        "Scaling noise by factor of %f to achieve snr=%f",
                        factor, self.max_snr)
                    wt_stamp = wt_stamp * factor
                    snr = self.max_snr
                props['snr'] = snr

                pos = galsim.PositionD(x, y)
                data = piff.StarData(stamp,
                                     pos,
                                     weight=wt_stamp,
                                     pointing=self.pointing,
                                     properties=props)
                star = piff.Star(data, None)
                g = gain[k]
                if g is not None:
                    logger.debug(
                        "Adding Poisson noise to weight map according to gain=%f",
                        g)
                    star = star.addPoisson(gain=g)
                stars.append(star)
                nstars_in_image += 1
        logger.warning("Read a total of %d stars from %d image%s", len(stars),
                       len(self.images), "s" if len(self.images) > 1 else "")

        return stars
示例#11
0
def test_simple():
    """Initial simple test of Gaussian, Kolmogorov, and Moffat PSFs.
    """
    # Here is the true PSF
    scale = 1.3
    g1 = 0.23
    g2 = -0.17
    du = 0.1
    dv = 0.4
    for fiducial in [fiducial_gaussian, fiducial_kolmogorov, fiducial_moffat]:
        print()
        print("fiducial = ", fiducial)
        print()
        psf = fiducial.dilate(scale).shear(g1=g1, g2=g2).shift(du, dv)

        # Draw the PSF onto an image.  Let's go ahead and give it a non-trivial WCS.
        wcs = galsim.JacobianWCS(0.26, 0.05, -0.08, -0.29)
        image = galsim.Image(64, 64, wcs=wcs)

        # This is only going to come out right if we (unphysically) don't convolve by the pixel.
        psf.drawImage(image, method='no_pixel')

        # Make a StarData instance for this image
        stardata = piff.StarData(image, image.true_center)
        fiducial_star = piff.Star(stardata, None)

        # First try fastfit.
        print('Fast fit')
        model = piff.GSObjectModel(fiducial, fastfit=True, include_pixel=False)
        fit = model.fit(model.initialize(fiducial_star)).fit

        print('True scale = ', scale, ', model scale = ', fit.params[0])
        print('True g1 = ', g1, ', model g1 = ', fit.params[1])
        print('True g2 = ', g2, ', model g2 = ', fit.params[2])
        print('True du = ', du, ', model du = ', fit.center[0])
        print('True dv = ', dv, ', model dv = ', fit.center[1])

        # This test is fairly accurate, since we didn't add any noise and didn't convolve by
        # the pixel, so the image is very accurately a sheared GSObject.
        np.testing.assert_allclose(fit.params[0], scale, rtol=1e-4)
        np.testing.assert_allclose(fit.params[1], g1, rtol=0, atol=1e-7)
        np.testing.assert_allclose(fit.params[2], g2, rtol=0, atol=1e-7)
        np.testing.assert_allclose(fit.center[0], du, rtol=0, atol=1e-7)
        np.testing.assert_allclose(fit.center[1], dv, rtol=0, atol=1e-7)

        # Now try fastfit=False.
        print('Slow fit')
        model = piff.GSObjectModel(fiducial,
                                   fastfit=False,
                                   include_pixel=False)
        fit = model.fit(model.initialize(fiducial_star)).fit

        print('True scale = ', scale, ', model scale = ', fit.params[0])
        print('True g1 = ', g1, ', model g1 = ', fit.params[1])
        print('True g2 = ', g2, ', model g2 = ', fit.params[2])
        print('True du = ', du, ', model du = ', fit.center[0])
        print('True dv = ', dv, ', model dv = ', fit.center[1])

        np.testing.assert_allclose(fit.params[0], scale, rtol=1e-6)
        np.testing.assert_allclose(fit.params[1], g1, rtol=0, atol=1e-6)
        np.testing.assert_allclose(fit.params[2], g2, rtol=0, atol=1e-6)
        np.testing.assert_allclose(fit.center[0], du, rtol=0, atol=1e-6)
        np.testing.assert_allclose(fit.center[1], dv, rtol=0, atol=1e-6)

        # Now test running it via the config parser
        config = {
            'model': {
                'type': 'GSObjectModel',
                'gsobj': repr(fiducial),
                'include_pixel': False
            }
        }
        if __name__ == '__main__':
            logger = piff.config.setup_logger(verbose=3)
        else:
            logger = piff.config.setup_logger(verbose=1)
        model = piff.Model.process(config['model'], logger)
        fit = model.fit(model.initialize(fiducial_star)).fit

        # Same tests.
        np.testing.assert_allclose(fit.params[0], scale, rtol=1e-6)
        np.testing.assert_allclose(fit.params[1], g1, rtol=0, atol=1e-6)
        np.testing.assert_allclose(fit.params[2], g2, rtol=0, atol=1e-6)
        np.testing.assert_allclose(fit.center[0], du, rtol=0, atol=1e-6)
        np.testing.assert_allclose(fit.center[1], dv, rtol=0, atol=1e-6)

        # Also need to test ability to serialize
        outfile = os.path.join('output', 'gsobject_test.fits')
        with fitsio.FITS(outfile, 'rw', clobber=True) as f:
            model.write(f, 'psf_model')
        with fitsio.FITS(outfile, 'r') as f:
            roundtrip_model = piff.GSObjectModel.read(f, 'psf_model')
        assert model.__dict__ == roundtrip_model.__dict__

        # Finally, we should also test with pixel convolution included.  This really only makes
        # sense for fastfit=False, since HSM FindAdaptiveMom doesn't account for the pixel shape
        # in its measurements.

        # Draw the PSF onto an image.  Let's go ahead and give it a non-trivial WCS.
        wcs = galsim.JacobianWCS(0.26, 0.05, -0.08, -0.29)
        image = galsim.Image(64, 64, wcs=wcs)

        psf.drawImage(image, method='auto')

        # Make a StarData instance for this image
        stardata = piff.StarData(image, image.true_center)
        fiducial_star = piff.Star(stardata, None)

        print('Slow fit, pixel convolution included.')
        model = piff.GSObjectModel(fiducial, fastfit=False, include_pixel=True)
        star = model.initialize(fiducial_star)
        star = model.fit(
            star,
            fastfit=True)  # Get better results with one round of fastfit.
        # Use a no op convert_func, just to touch that branch in the code.
        convert_func = lambda prof: prof
        fit = model.fit(star, convert_func=convert_func).fit

        print('True scale = ', scale, ', model scale = ', fit.params[0])
        print('True g1 = ', g1, ', model g1 = ', fit.params[1])
        print('True g2 = ', g2, ', model g2 = ', fit.params[2])
        print('True du = ', du, ', model du = ', fit.center[0])
        print('True dv = ', dv, ', model dv = ', fit.center[1])

        # Accuracy goals are a bit looser here since it's harder to fit with the pixel involved.
        np.testing.assert_allclose(fit.params[0], scale, rtol=1e-6)
        np.testing.assert_allclose(fit.params[1], g1, rtol=0, atol=1e-6)
        np.testing.assert_allclose(fit.params[2], g2, rtol=0, atol=1e-6)
        np.testing.assert_allclose(fit.center[0], du, rtol=0, atol=1e-5)
        np.testing.assert_allclose(fit.center[1], dv, rtol=0, atol=1e-5)
示例#12
0
def test_var():
    """Check that the variance estimate in params_var is sane.
    """
    # Here is the true PSF
    scale = 1.3
    g1 = 0.23
    g2 = -0.17
    du = 0.1
    dv = 0.4
    flux = 500
    wcs = galsim.JacobianWCS(0.26, 0.05, -0.08, -0.29)
    noise = 0.2

    gsobjs = [
        galsim.Gaussian(sigma=1.0),
        galsim.Kolmogorov(half_light_radius=1.0),
        galsim.Moffat(half_light_radius=1.0, beta=3.0),
        galsim.Moffat(half_light_radius=1.0, beta=2.5, trunc=3.0)
    ]

    # Mix of centered = True/False,
    #        fastfit = True/False,
    #        include_pixel = True/False
    models = [
        piff.Gaussian(fastfit=False, include_pixel=False, centered=False),
        piff.Kolmogorov(fastfit=True, include_pixel=True, centered=False),
        piff.Moffat(fastfit=False, beta=4.8, include_pixel=True,
                    centered=True),
        piff.Moffat(fastfit=True,
                    beta=2.5,
                    trunc=3.0,
                    include_pixel=False,
                    centered=True)
    ]

    names = ['Gaussian', 'Kolmogorov', 'Moffat3', 'Moffat2.5']

    for gsobj, model, name in zip(gsobjs, models, names):
        print()
        print("gsobj = ", gsobj)
        print()
        psf = gsobj.dilate(scale).shear(g1=g1, g2=g2).shift(du,
                                                            dv).withFlux(flux)
        image = psf.drawImage(nx=64, ny=64, wcs=wcs, method='no_pixel')
        weight = image.copy()
        weight.fill(1 / noise**2)
        # Save this one without noise.

        image1 = image.copy()
        image1.addNoise(galsim.GaussianNoise(sigma=noise))

        # Make a StarData instance for this image
        stardata = piff.StarData(image, image.true_center, weight)
        star = piff.Star(stardata, None)
        star = model.initialize(star)
        fit = model.fit(star).fit

        file_name = 'input/test_%s_var.npz' % name
        print(file_name)

        if not os.path.isfile(file_name):
            num_runs = 1000
            all_params = []
            for i in range(num_runs):
                image1 = image.copy()
                image1.addNoise(galsim.GaussianNoise(sigma=noise))
                sd = piff.StarData(image1, image1.true_center, weight)
                s = piff.Star(sd, None)
                try:
                    s = model.initialize(s)
                    s = model.fit(s)
                except RuntimeError as e:  # Occasionally hsm fails.
                    print('Caught ', e)
                    continue
                print(s.fit.params)
                all_params.append(s.fit.params)
            var = np.var(all_params, axis=0)
            np.savez(file_name, var=var)
        var = np.load(file_name)['var']
        print('params = ', fit.params)
        print('empirical var = ', var)
        print('piff estimate = ', fit.params_var)
        print('ratio = ', fit.params_var / var)
        print('max ratio = ', np.max(fit.params_var / var))
        print('min ratio = ', np.min(fit.params_var / var))
        print('mean ratio = ', np.mean(fit.params_var / var))
        # Note: The fastfit=False estimates are better -- typically better than 10%
        #       The fastfit=True estimates are much rougher.  Especially size.  Need rtol=0.3.
        np.testing.assert_allclose(fit.params_var, var, rtol=0.3)
示例#13
0
def test_direct():
    """ Simple test for directly instantiated Gaussian, Kolmogorov, and Moffat without going through
    GSObjectModel explicitly.
    """
    # Here is the true PSF
    scale = 1.3
    g1 = 0.23
    g2 = -0.17
    du = 0.1
    dv = 0.4

    gsobjs = [
        galsim.Gaussian(sigma=1.0),
        galsim.Kolmogorov(half_light_radius=1.0),
        galsim.Moffat(half_light_radius=1.0, beta=3.0),
        galsim.Moffat(half_light_radius=1.0, beta=2.5, trunc=3.0)
    ]

    models = [
        piff.Gaussian(fastfit=True, include_pixel=False),
        piff.Kolmogorov(fastfit=True, include_pixel=False),
        piff.Moffat(fastfit=True, beta=3.0, include_pixel=False),
        piff.Moffat(fastfit=True, beta=2.5, trunc=3.0, include_pixel=False)
    ]

    for gsobj, model in zip(gsobjs, models):
        print()
        print("gsobj = ", gsobj)
        print()
        psf = gsobj.dilate(scale).shear(g1=g1, g2=g2).shift(du, dv)

        # Draw the PSF onto an image.  Let's go ahead and give it a non-trivial WCS.
        wcs = galsim.JacobianWCS(0.26, 0.05, -0.08, -0.29)
        image = galsim.Image(64, 64, wcs=wcs)

        # This is only going to come out right if we (unphysically) don't convolve by the pixel.
        psf.drawImage(image, method='no_pixel')

        # Make a StarData instance for this image
        stardata = piff.StarData(image, image.true_center)
        star = piff.Star(stardata, None)
        star = model.initialize(star)

        # First try fastfit.
        print('Fast fit')
        fit = model.fit(star).fit

        print('True scale = ', scale, ', model scale = ', fit.params[0])
        print('True g1 = ', g1, ', model g1 = ', fit.params[1])
        print('True g2 = ', g2, ', model g2 = ', fit.params[2])
        print('True du = ', du, ', model du = ', fit.center[0])
        print('True dv = ', dv, ', model dv = ', fit.center[1])

        # This test is fairly accurate, since we didn't add any noise and didn't convolve by
        # the pixel, so the image is very accurately a sheared GSObject.
        # These tests are more strict above.  The truncated Moffat included here but not there
        # doesn't work quite as well.
        np.testing.assert_allclose(fit.params[0], scale, rtol=1e-4)
        np.testing.assert_allclose(fit.params[1], g1, rtol=0, atol=1e-5)
        np.testing.assert_allclose(fit.params[2], g2, rtol=0, atol=1e-5)
        np.testing.assert_allclose(fit.center[0], du, rtol=0, atol=1e-5)
        np.testing.assert_allclose(fit.center[1], dv, rtol=0, atol=1e-5)

        # Also need to test ability to serialize
        outfile = os.path.join('output', 'gsobject_direct_test.fits')
        with fitsio.FITS(outfile, 'rw', clobber=True) as f:
            model.write(f, 'psf_model')
        with fitsio.FITS(outfile, 'r') as f:
            roundtrip_model = piff.GSObjectModel.read(f, 'psf_model')
        assert model.__dict__ == roundtrip_model.__dict__

    # repeat with fastfit=False

    models = [
        piff.Gaussian(fastfit=False, include_pixel=False),
        piff.Kolmogorov(fastfit=False, include_pixel=False),
        piff.Moffat(fastfit=False, beta=3.0, include_pixel=False),
        piff.Moffat(fastfit=False, beta=2.5, trunc=3.0, include_pixel=False)
    ]

    for gsobj, model in zip(gsobjs, models):
        print()
        print("gsobj = ", gsobj)
        print()
        psf = gsobj.dilate(scale).shear(g1=g1, g2=g2).shift(du, dv)

        # Draw the PSF onto an image.  Let's go ahead and give it a non-trivial WCS.
        wcs = galsim.JacobianWCS(0.26, 0.05, -0.08, -0.29)
        image = galsim.Image(64, 64, wcs=wcs)

        # This is only going to come out right if we (unphysically) don't convolve by the pixel.
        psf.drawImage(image, method='no_pixel')

        # Make a StarData instance for this image
        stardata = piff.StarData(image, image.true_center)
        star = piff.Star(stardata, None)
        star = model.initialize(star)

        print('Slow fit')
        fit = model.fit(star).fit

        print('True scale = ', scale, ', model scale = ', fit.params[0])
        print('True g1 = ', g1, ', model g1 = ', fit.params[1])
        print('True g2 = ', g2, ', model g2 = ', fit.params[2])
        print('True du = ', du, ', model du = ', fit.center[0])
        print('True dv = ', dv, ', model dv = ', fit.center[1])

        # This test is fairly accurate, since we didn't add any noise and didn't convolve by
        # the pixel, so the image is very accurately a sheared GSObject.
        np.testing.assert_allclose(fit.params[0], scale, rtol=1e-5)
        np.testing.assert_allclose(fit.params[1], g1, rtol=0, atol=1e-5)
        np.testing.assert_allclose(fit.params[2], g2, rtol=0, atol=1e-5)
        np.testing.assert_allclose(fit.center[0], du, rtol=0, atol=1e-5)
        np.testing.assert_allclose(fit.center[1], dv, rtol=0, atol=1e-5)

        # Also need to test ability to serialize
        outfile = os.path.join('output', 'gsobject_direct_test.fits')
        with fitsio.FITS(outfile, 'rw', clobber=True) as f:
            model.write(f, 'psf_model')
        with fitsio.FITS(outfile, 'r') as f:
            roundtrip_model = piff.GSObjectModel.read(f, 'psf_model')
        assert model.__dict__ == roundtrip_model.__dict__
示例#14
0
    def determinePsf(self,
                     exposure,
                     psfCandidateList,
                     metadata=None,
                     flagKey=None):
        """Determine a Piff PSF model for an exposure given a list of PSF
        candidates.

        Parameters
        ----------
        exposure : `lsst.afw.image.Exposure`
           Exposure containing the PSF candidates.
        psfCandidateList : `list` of `lsst.meas.algorithms.PsfCandidate`
           A sequence of PSF candidates typically obtained by detecting sources
           and then running them through a star selector.
        metadata : `lsst.daf.base import PropertyList` or `None`, optional
           A home for interesting tidbits of information.
        flagKey : `str` or `None`, optional
           Schema key used to mark sources actually used in PSF determination.

        Returns
        -------
        psf : `lsst.meas.extensions.piff.PiffPsf`
           The measured PSF model.
        psfCellSet : `None`
           Unused by this PsfDeterminer.
        """
        stars = []
        for candidate in psfCandidateList:
            cmi = candidate.getMaskedImage()
            weight = computeWeight(cmi, self.config.maxSNR)

            bbox = cmi.getBBox()
            bds = galsim.BoundsI(galsim.PositionI(*bbox.getMin()),
                                 galsim.PositionI(*bbox.getMax()))
            gsImage = galsim.Image(bds, scale=1.0, dtype=float)
            gsImage.array[:] = cmi.image.array
            gsWeight = galsim.Image(bds, scale=1.0, dtype=float)
            gsWeight.array[:] = weight

            source = candidate.getSource()
            image_pos = galsim.PositionD(source.getX(), source.getY())

            data = piff.StarData(gsImage, image_pos, weight=gsWeight)
            stars.append(piff.Star(data, None))

        kernelSize = int(
            np.clip(self.config.kernelSize, self.config.kernelSizeMin,
                    self.config.kernelSizeMax))

        piffConfig = {
            'type': "Simple",
            'model': {
                'type': 'PixelGrid',
                'scale': self.config.samplingSize,
                'size': kernelSize
            },
            'interp': {
                'type': 'BasisPolynomial',
                'order': self.config.spatialOrder
            },
            'outliers': {
                'type': 'Chisq',
                'nsigma': self.config.outlierNSigma,
                'max_remove': self.config.outlierMaxRemove
            }
        }

        piffResult = piff.PSF.process(piffConfig)
        # Run on a single CCD, and in image coords rather than sky coords.
        wcs = {0: galsim.PixelScale(1.0)}
        pointing = None

        logger = logging.getLogger(self.log.getName() + ".Piff")
        logger.addHandler(lsst.log.LogHandler())

        piffResult.fit(stars, wcs, pointing, logger=logger)
        psf = PiffPsf(kernelSize, kernelSize, piffResult)

        used_image_pos = [s.image_pos for s in piffResult.stars]
        if flagKey:
            for candidate in psfCandidateList:
                source = candidate.getSource()
                posd = galsim.PositionD(source.getX(), source.getY())
                if posd in used_image_pos:
                    source.set(flagKey, True)

        if metadata is not None:
            metadata.set("spatialFitChi2", piffResult.chisq)
            metadata.set("numAvailStars", len(stars))
            metadata.set("numGoodStars", len(piffResult.stars))
            metadata.set("avgX", np.mean([p.x for p in piffResult.stars]))
            metadata.set("avgY", np.mean([p.y for p in piffResult.stars]))

        return psf, None
示例#15
0
def test_star():
    # Star class is a pretty thin wrapper of StarData and StarFit classes.

    # Same setup as for test_euclidean
    wcs = galsim.AffineTransform(0.26,
                                 -0.02,
                                 0.03,
                                 0.28,
                                 world_origin=galsim.PositionD(912.4, -833.1))
    size = 64
    image_pos = galsim.PositionD(1083.9, 617.3)
    field_pos = wcs.toWorld(image_pos)
    icen = int(image_pos.x + 0.5)
    jcen = int(image_pos.y + 0.5)
    bounds = galsim.BoundsI(icen - size // 2 - 1, icen + size // 2,
                            jcen - size // 2 - 1, jcen + size // 2)
    image = galsim.Image(bounds, wcs=wcs)
    weight = galsim.ImageS(bounds, wcs=wcs, init_value=1)
    galsim.Gaussian(sigma=5).drawImage(image)
    weight += image

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

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

    # Check access via star class
    star = piff.Star(stardata,
                     None)  # fit is optional, but must be explicitly None
    for key, value in stardata.properties.items():
        np.testing.assert_equal(star[key], value)
    np.testing.assert_equal(star.image.array, image.array)
    np.testing.assert_equal(star.weight.array, weight.array)
    assert star.image_pos == image_pos
    print('field_pos = ', field_pos)
    print('star.field_pos = ', star.field_pos)
    assert star.field_pos == field_pos
    assert star.x == image_pos.x
    assert star.y == image_pos.y
    assert star.u == field_pos.x
    assert star.v == field_pos.y
    assert star.chipnum == 3
    assert star.flux == 1.
    assert star.center == (0, 0)
    assert star.is_reserve == False

    star = star.withFlux(7)
    assert star.flux == 7.
    assert star.center == (0, 0)

    star = star.withFlux(17, center=(102, 22))
    assert star.flux == 17.
    assert star.center == (102, 22)

    star = star.withFlux(center=(12, 20))
    assert star.flux == 17.
    assert star.center == (12, 20)

    star = star.withFlux(flux=2)
    assert star.flux == 2.
    assert star.center == (12, 20)

    # Test using makeTarget
    star = piff.Star.makeTarget(properties=stardata.properties,
                                image=image,
                                weight=weight)
    np.testing.assert_equal(star.data['x'], image_pos.x)
    np.testing.assert_equal(star.data['y'], image_pos.y)
    np.testing.assert_equal(star.data['u'], field_pos.x)
    np.testing.assert_equal(star.data['v'], field_pos.y)
    # Shouldn't matter whether we use the original wcs or the one in the postage stamp.
    print('image.wcs = ', image.wcs)
    print('image_pos = ', image_pos)
    print('field_pos = ', field_pos)
    print('image.wcs.toWorld(image_pos) = ', image.wcs.toWorld(image_pos))
    print('in star.data: ', star.data['u'])
    print('in star.data: ', star.data['v'])
    np.testing.assert_equal(star.data['u'], image.wcs.toWorld(image_pos).x)
    np.testing.assert_equal(star.data['v'], image.wcs.toWorld(image_pos).y)
    im, wt, pos = star.data.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)

    # Some invalid parameter checks
    np.testing.assert_raises(TypeError,
                             piff.Star.makeTarget,
                             x=1,
                             properties=stardata.properties,
                             image=image,
                             weight=weight)
    np.testing.assert_raises(TypeError,
                             piff.Star.makeTarget,
                             y=1,
                             properties=stardata.properties,
                             image=image,
                             weight=weight)
    np.testing.assert_raises(TypeError,
                             piff.Star.makeTarget,
                             u=1,
                             properties=stardata.properties,
                             image=image,
                             weight=weight)
    np.testing.assert_raises(TypeError,
                             piff.Star.makeTarget,
                             v=1,
                             properties=stardata.properties,
                             image=image,
                             weight=weight)
    np.testing.assert_raises(TypeError,
                             piff.Star.makeTarget,
                             x=1,
                             image=image,
                             weight=weight)
    np.testing.assert_raises(TypeError,
                             piff.Star.makeTarget,
                             y=1,
                             image=image,
                             weight=weight)
    np.testing.assert_raises(TypeError,
                             piff.Star.makeTarget,
                             u=1,
                             image=image,
                             weight=weight)
    np.testing.assert_raises(TypeError,
                             piff.Star.makeTarget,
                             image=image,
                             weight=weight)
    np.testing.assert_raises(TypeError,
                             piff.Star.makeTarget,
                             x=1,
                             y=2,
                             scale=4,
                             wcs=image.wcs,
                             image=image,
                             weight=weight)
示例#16
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")
示例#17
0
def test_celestial():
    """Test using a (realistic) CelestialWCS for the main image.
    """

    # Make a CelestialWCS.  The simplest kind to make from scratch is a TanWCS.
    affine = galsim.AffineTransform(0.26, -0.02, 0.03, 0.28,
                                    world_origin=galsim.PositionD(912.4, -833.1))
    ra = 13.2343 * galsim.hours
    dec = -39.8484 * galsim.degrees
    pointing = galsim.CelestialCoord(ra,dec)
    wcs = galsim.TanWCS(affine, world_origin=pointing)
    print('wcs = ',wcs)

    # Start with a larger image from which we will cut out the postage stamp
    full_image = galsim.Image(2048,2048, wcs=wcs)
    full_weight = galsim.ImageS(2048,2048, wcs=wcs, init_value=1)

    # Make a postage stamp cutout
    # This next bit is the same as we did for the EuclideanWCS
    size = 64
    image_pos = galsim.PositionD(1083.9, 617.3)
    sky_pos = wcs.toWorld(image_pos)
    if galsim.__version__ >= '2.0':
        u,v = pointing.project(sky_pos)
        field_pos = galsim.PositionD(u/galsim.arcsec, v/galsim.arcsec)
    else:
        field_pos = pointing.project(sky_pos)
    icen = int(image_pos.x)
    jcen = int(image_pos.y)

    bounds = galsim.BoundsI(icen-size//2+1, icen+size//2, jcen-size//2+1, jcen+size//2)
    image = full_image[bounds]
    weight = full_weight[bounds]

    galsim.Gaussian(sigma=5).drawImage(image)
    weight += image

    # With a CelestialWCS, we need to supply a pointing
    stardata = piff.StarData(image, image_pos, weight=weight, pointing=pointing)

    # Test properties
    print('props = ',stardata.properties)
    np.testing.assert_equal(stardata['x'], image_pos.x)
    np.testing.assert_equal(stardata['y'], image_pos.y)
    np.testing.assert_equal(stardata['u'], field_pos.x)
    np.testing.assert_equal(stardata['v'], field_pos.y)
    np.testing.assert_equal(stardata['ra'], sky_pos.ra/galsim.hours)
    np.testing.assert_equal(stardata['dec'], sky_pos.dec/galsim.degrees)

    # 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:
    for data, wt, u, v in np.array(stardata.getDataVector()).T:
        # u,v values should correspond to image coordinates via wcs
        uv = galsim.PositionD(u,v) + field_pos
        if galsim.__version__ >= '2.0':
            radec = pointing.deproject(uv.x * galsim.arcsec, uv.y * galsim.arcsec)
        else:
            radec = pointing.deproject(uv)
        xy = wcs.toImage(radec)
        # These should now be integers, but round in case of numerical inaccuracy.
        ix = int(round(xy.x))
        jy = int(round(xy.y))
        np.testing.assert_equal(data, image(ix,jy))
        np.testing.assert_equal(wt, weight(ix,jy))

    print("Passed tests of StarData with CelestialWCS")
示例#18
0
def test_euclidean():
    """Test a slightly more complicated WCS and an object not centered at the center of the image.
    """

    # Make a non-trivial WCS
    wcs = galsim.AffineTransform(0.26, -0.02, 0.03, 0.28,
                                 world_origin=galsim.PositionD(912.4, -833.1))
    print('wcs = ',wcs)

    # Start with a larger image from which we will cut out the postage stamp
    full_image = galsim.Image(2048,2048, wcs=wcs)
    full_weight = galsim.ImageS(2048,2048, wcs=wcs, init_value=1)
    print('origin of full image is at u,v = ',full_image.wcs.toWorld(full_image.origin))
    print('center of full image is at u,v = ',full_image.wcs.toWorld(full_image.center))

    # Make a postage stamp cutout
    size = 64   # This time, use an even size.
    image_pos = galsim.PositionD(1083.9, 617.3)
    field_pos = wcs.toWorld(image_pos)
    icen = int(image_pos.x)
    jcen = int(image_pos.y)

    bounds = galsim.BoundsI(icen-size//2+1, icen+size//2, jcen-size//2+1, jcen+size//2)
    image = full_image[bounds]
    weight = full_weight[bounds]

    print('image_pos = ',image_pos)
    print('field pos (u,v) = ',field_pos)
    print('origin of ps image is at u,v = ',image.wcs.toWorld(image.origin))
    print('center of ps image is at u,v = ',image.wcs.toWorld(image.center))

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

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

    # Test properties
    print('props = ',stardata.properties)
    np.testing.assert_equal(stardata['x'], image_pos.x)
    np.testing.assert_equal(stardata['y'], image_pos.y)
    np.testing.assert_equal(stardata['u'], field_pos.x)
    np.testing.assert_equal(stardata['v'], field_pos.y)
    # Shouldn't matter whether we use the original wcs or the one in the postage stamp.
    np.testing.assert_equal(stardata['u'], image.wcs.toWorld(image_pos).x)
    np.testing.assert_equal(stardata['v'], image.wcs.toWorld(image_pos).y)

    # 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:
    for data, wt, u, v in np.array(stardata.getDataVector()).T:
        # u,v values should correspond to image coordinates via wcs
        uv = galsim.PositionD(u,v) + field_pos
        xy = wcs.toImage(uv)
        # These should now be integers, but round in case of numerical inaccuracy.
        ix = int(round(xy.x))
        jy = int(round(xy.y))
        np.testing.assert_equal(data, image(ix,jy))
        np.testing.assert_equal(wt, weight(ix,jy))

    print("Passed tests of StarData with EuclideanWCS")