コード例 #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 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
コード例 #3
0
ファイル: test_poly.py プロジェクト: emhuff/Piff
def test_poly_mean():
    # Zero'th order polynomial fitting should be pretty trivial, just
    # the same as the mean fitting. So much of this code is just taken from
    # the mean testing in test_simple
    N = 0
    nparam = 5
    interp = piff.Polynomial(N)
    nstars = 100

    # Choose some random values of star parameters
    np_rng = np.random.RandomState(1234)
    vectors = [np_rng.random_sample(size=nparam) for i in range(nstars)]

    # take the mean of them. Our curve fit should be able to reproduce this.
    mean = np.mean(vectors, axis=0)

    # Choose some random positions in the field.
    data = [
        piff.Star.makeTarget(u=np_rng.random_sample() * 10,
                             v=np_rng.random_sample() * 10).data
        for i in range(nstars)
    ]
    fit = [piff.StarFit(v) for v in vectors]
    stars = [piff.Star(d, f) for d, f in zip(data, fit)]

    # Run our solver.
    interp.solve(stars)

    # we expect one set of coefficients per object
    assert len(interp.coeffs) == 5

    # We should have very close values (not necessarily identical) since
    # we calculate these in numerically different ways.
    for mu, val in zip(mean, interp.coeffs):
        assert np.isclose(mu, val[0, 0])

    # We also expect that if we interpolate to any point we just
    # get the mean as well
    for i in range(30):
        target = piff.Star.makeTarget(u=np_rng.random_sample() * 10,
                                      v=np_rng.random_sample() * 10)
        target = interp.interpolate(target)
        np.testing.assert_almost_equal(target.fit.params, mean)

    # Now test running it via the config parser
    config = {
        'interp': {
            'type': 'Polynomial',
            'order': 0,
        }
    }
    logger = piff.config.setup_logger()
    interp = piff.Interp.process(config['interp'], logger)
    interp.solve(stars)

    # Same tests
    assert len(interp.coeffs) == 5
    for mu, val in zip(mean, interp.coeffs):
        assert np.isclose(mu, val[0, 0])
    np.testing.assert_almost_equal(target.fit.params, mean)
コード例 #4
0
def make_single_star(u, v, size, g1, g2, size_err, g1_err, g2_err):
    """Make a Star instance filled with a Kolmogorov profile

    :param u, v:           Star coordinate.
    :param size:           Star size.
    :param g1, g2:         Shear applied to profile.
    :param size_err:       Size error.
    :param g1_err, g2_err: Shear error. 
    """
    star = piff.Star.makeTarget(x=None,
                                y=None,
                                u=u,
                                v=v,
                                properties={},
                                wcs=None,
                                scale=0.26,
                                stamp_size=24,
                                image=None,
                                pointing=None,
                                flux=1.)

    kolmogorov.drawImage(star.image, method='auto')
    fit = piff.StarFit(np.array([size, g1, g2]),
                       params_var=np.array([size_err**2, g1_err**2,
                                            g2_err**2]),
                       flux=1.)
    final_star = piff.Star(star.data, fit)

    return final_star
コード例 #5
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)
コード例 #6
0
ファイル: test_simple.py プロジェクト: rmjarvis/Piff
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)
コード例 #7
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.)
コード例 #8
0
ファイル: test_poly.py プロジェクト: emhuff/Piff
def sub_poly_linear(type1):
    # Now lets do something more interesting - test a linear model.
    # with no noise this should fit really well, though again not
    # numerically perfectly.
    np_rng = np.random.RandomState(1234)
    nparam = 3
    N = 1
    nstars = 50
    orders = [N for i in range(nparam)]
    interp = piff.Polynomial(orders=orders, poly_type=type1)
    X = 10.0  # size of the field
    Y = 10.0

    pos = [(np_rng.random_sample() * X, np_rng.random_sample() * Y)
           for i in range(nstars)]

    # Let's make a function that is linear just as a function of one parameter
    # These are the linear fit parameters for each parameter in turn
    m1 = np_rng.uniform(size=nparam)
    m2 = np_rng.uniform(size=nparam)
    c = np_rng.uniform(size=nparam)

    def linear_func(pos):
        u = pos[0]
        v = pos[1]
        r = m1 * u + m2 * v + c
        return r

    # Simulate the vectors under this model
    vectors = [linear_func(p) for p in pos]

    # Fit them. Linear fitting is quite easy so this should be okay
    data = [piff.Star.makeTarget(u=p[0], v=p[1]).data for p in pos]
    fit = [piff.StarFit(v) for v in vectors]
    stars = [piff.Star(d, f) for d, f in zip(data, fit)]
    interp.solve(stars)

    # Check that the interpolation recovers the desired function
    for i in range(30):
        p = (np_rng.random_sample() * X, np_rng.random_sample() * Y)
        target = piff.Star.makeTarget(u=p[0], v=p[1])
        target = interp.interpolate(target)
        np.testing.assert_almost_equal(linear_func(p), target.fit.params)

    # Now test running it via the config parser
    config = {
        'interp': {
            'type': 'Polynomial',
            'order': 1,
        }
    }
    logger = piff.config.setup_logger()
    interp = piff.Interp.process(config['interp'], logger)
    interp.solve(stars)
    np.testing.assert_almost_equal(linear_func(p), target.fit.params)
コード例 #9
0
ファイル: test_poly.py プロジェクト: emhuff/Piff
def sub_poly_quadratic(type1):
    # This is basically the same as linear but with
    # quadratic variation
    np_rng = np.random.RandomState(1234)
    nparam = 3
    N = 2
    nstars = 50
    orders = [N for i in range(nparam)]
    interp = piff.Polynomial(N, poly_type=type1)
    X = 10.0  # size of the field
    Y = 10.0

    pos = [(np_rng.random_sample() * X, np_rng.random_sample() * Y)
           for i in range(nstars)]

    # Let's make a function that is linear just as a function of one parameter
    # These are the linear fit parameters for each parameter in turn
    m1 = np_rng.uniform(size=nparam)
    m2 = np_rng.uniform(size=nparam)
    q1 = np_rng.uniform(size=nparam)
    c = np_rng.uniform(size=nparam)

    def quadratic_func(pos):
        u = pos[0]
        v = pos[1]
        r = q1 * u * v + m1 * u + m2 * v + c
        return r

    # Simulate the vectors under this model
    vectors = [quadratic_func(p) for p in pos]

    # Fit them.
    data = [piff.Star.makeTarget(u=p[0], v=p[1]).data for p in pos]
    fit = [piff.StarFit(v) for v in vectors]
    stars = [piff.Star(d, f) for d, f in zip(data, fit)]
    interp.solve(stars)

    # Check that the interpolation recovers the desired function
    for i in range(30):
        p = (np_rng.random_sample() * X, np_rng.random_sample() * Y)
        target = piff.Star.makeTarget(u=p[0], v=p[1])
        target = interp.interpolate(target)
        np.testing.assert_almost_equal(quadratic_func(p), target.fit.params)

    # Now test running it via the config parser
    config = {
        'interp': {
            'type': 'Polynomial',
            'order': 2,
        }
    }
    logger = piff.config.setup_logger()
    interp = piff.Interp.process(config['interp'], logger)
    interp.solve(stars)
    np.testing.assert_almost_equal(quadratic_func(p), target.fit.params)
コード例 #10
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)
コード例 #11
0
def make_empty_star(icen=500, jcen=700, ccdnum=28, params=None,
                    properties={},
                    fit_kwargs={}):

    properties['ccdnum'] = ccdnum
    # setting scale is crucial
    star = piff.Star.makeTarget(x=icen, y=jcen, properties=properties,
                                scale=0.263)

    if params is None:
        starfit = None
    else:
        starfit = piff.StarFit(params, **fit_kwargs)

    star = piff.Star(star.data, starfit)

    return star
コード例 #12
0
def make_star(icen=500, jcen=700, ccdnum=28,
              sigma=1, g1=0, g2=0,
              pixel_to_focal=False,
              properties={},
              fit_kwargs={}):

    properties['ccdnum'] = ccdnum
    # setting scale is crucial
    stardata = piff.Star.makeTarget(x=icen, y=jcen, properties=properties,
                                    scale=0.263)
    # apply Gaussian sigma, g1, g2
    params = np.array([sigma, g1, g2])

    starfit = piff.StarFit(params, **fit_kwargs)

    star = piff.Star(stardata.data, starfit)

    return star
コード例 #13
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
コード例 #14
0
ファイル: test_simple.py プロジェクト: rmjarvis/Piff
def test_Mean():
    """For the interpolation, the simplest possible model is just a mean value, which barely
    even qualifies as doing any kind of interpolating.  But it tests the basic glue software.
    """
    # Make a list of parameter vectors to "interpolate"
    np_rng = np.random.RandomState(1234)
    nstars = 100
    vectors = [ np_rng.random_sample(10) for i in range(nstars) ]
    mean = np.mean(vectors, axis=0)
    print('mean = ',mean)

    # Make some dummy StarData objects to use.  The only thing we really need is the properties,
    # although for the Mean interpolator, even this is ignored.
    target_data = [
            piff.Star.makeTarget(x=np_rng.random_sample()*2048, y=np_rng.random_sample()*2048).data
            for i in range(nstars) ]
    fit = [ piff.StarFit(v) for v in vectors ]
    stars = [ piff.Star(d, f) for d,f in zip(target_data,fit) ]

    # Use the piff.Mean interpolator
    interp = piff.Mean()
    interp.solve(stars)

    print('True mean = ',mean)
    print('Interp mean = ',interp.mean)

    # This should be exactly equal, since we did the same calculation.  But use almost_equal
    # anyway, just in case we decide to do something slightly different, but equivalent.
    np.testing.assert_almost_equal(mean, interp.mean)

    # Now test running it via the config parser
    config = {
        'interp' : {
            'type' : 'Mean'
        }
    }
    logger = piff.config.setup_logger()
    interp = piff.Interp.process(config['interp'], logger)
    interp.solve(stars)
    np.testing.assert_almost_equal(mean, interp.mean)
コード例 #15
0
ファイル: test_poly.py プロジェクト: emhuff/Piff
def test_poly_raise():
    # Test that we can serialize and deserialize a polynomial
    # interpolator correctly.  Copying all this stuff from above:

    np_rng = np.random.RandomState(1234)
    nparam = 3
    nstars = 50

    # Use three different sizes to test everything
    orders = [1, 2, 3]
    interp = piff.Polynomial(orders=orders)
    pos = [(np_rng.random_sample() * 10, np_rng.random_sample() * 10)
           for i in range(nstars)]
    #use the wrong number of parameters here so that we raise an error
    vectors = [np_rng.random_sample(size=nparam + 1) for i in range(nstars)]
    data = [piff.Star.makeTarget(u=p[0], v=p[1]).data for p in pos]
    fit = [piff.StarFit(v) for v in vectors]
    stars = [piff.Star(d, f) for d, f in zip(data, fit)]
    try:
        np.testing.assert_raises(ValueError, interp.solve, stars)
    except ImportError:
        pass
コード例 #16
0
ファイル: test_poly.py プロジェクト: rmjarvis/Piff
def test_poly_raise():
    # Test that we can serialize and deserialize a polynomial
    # interpolator correctly.  Copying all this stuff from above:

    np_rng = np.random.RandomState(1234)
    nparam = 3
    nstars = 50

    # Use three different sizes to test everything
    orders = [1, 2, 3]
    interp = piff.Polynomial(orders=orders)
    pos = [(np_rng.random_sample() * 10, np_rng.random_sample() * 10)
           for i in range(nstars)]
    #use the wrong number of parameters here so that we raise an error
    vectors = [np_rng.random_sample(size=nparam + 1) for i in range(nstars)]
    data = [piff.Star.makeTarget(u=p[0], v=p[1]).data for p in pos]
    fit = [piff.StarFit(v) for v in vectors]
    stars = [piff.Star(d, f) for d, f in zip(data, fit)]
    np.testing.assert_raises(ValueError, interp.solve, stars)

    # Invalid construction
    np.testing.assert_raises(TypeError, piff.Polynomial)
    np.testing.assert_raises(TypeError,
                             piff.Polynomial,
                             order=3,
                             orders=[1, 2, 3])
    np.testing.assert_raises(ValueError,
                             piff.Polynomial,
                             order=3,
                             poly_type='invalid')

    # Cannot write before running fit.
    filename = 'output/test_invalid.fits'
    with fitsio.FITS(filename, 'rw', clobber=True) as f:
        with np.testing.assert_raises(RuntimeError):
            interp.write(f, extname='junk')
コード例 #17
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
コード例 #18
0
def test_single_image():
    """Test the simple case of one image and one catalog.
    """
    if __name__ == '__main__':
        logger = piff.config.setup_logger(verbose=2)
    else:
        logger = piff.config.setup_logger(
            log_file='output/test_single_image.log')

    # Make the image
    image = galsim.Image(2048, 2048, scale=0.26)

    # Where to put the stars.  Include some flagged and not used locations.
    x_list = [
        123.12, 345.98, 567.25, 1094.94, 924.15, 1532.74, 1743.11, 888.39,
        1033.29, 1409.31
    ]
    y_list = [
        345.43, 567.45, 1094.32, 924.29, 1532.92, 1743.83, 888.83, 1033.19,
        1409.20, 123.11
    ]
    flag_list = [1, 1, 13, 1, 1, 4, 1, 1, 0, 1]

    # Draw a Gaussian PSF at each location on the image.
    sigma = 1.3
    g1 = 0.23
    g2 = -0.17
    psf = galsim.Gaussian(sigma=sigma).shear(g1=g1, g2=g2)
    for x, y, flag in zip(x_list, y_list, flag_list):
        bounds = galsim.BoundsI(int(x - 31), int(x + 32), int(y - 31),
                                int(y + 32))
        offset = galsim.PositionD(x - int(x) - 0.5, y - int(y) - 0.5)
        psf.drawImage(image=image[bounds], method='no_pixel', offset=offset)
        # corrupt the ones that are marked as flagged
        if flag & 4:
            print('corrupting star at ', x, y)
            ar = image[bounds].array
            im_max = np.max(ar) * 0.2
            ar[ar > im_max] = im_max
    image.addNoise(
        galsim.GaussianNoise(rng=galsim.BaseDeviate(1234), sigma=1e-6))

    # Write out the image to a file
    image_file = os.path.join('output', 'simple_image.fits')
    image.write(image_file)

    # Write out the catalog to a file
    dtype = [('x', 'f8'), ('y', 'f8'), ('flag', 'i2')]
    data = np.empty(len(x_list), dtype=dtype)
    data['x'] = x_list
    data['y'] = y_list
    data['flag'] = flag_list
    cat_file = os.path.join('output', 'simple_cat.fits')
    fitsio.write(cat_file, data, clobber=True)

    # Use InputFiles to read these back in
    config = {'image_file_name': image_file, 'cat_file_name': cat_file}
    input = piff.InputFiles(config, logger=logger)
    assert input.image_file_name == [image_file]
    assert input.cat_file_name == [cat_file]

    # Check image
    assert input.nimages == 1
    image1, _, image_pos, _, _, _ = input.getRawImageData(0)
    np.testing.assert_equal(image1.array, image.array)

    # Check catalog
    np.testing.assert_equal([pos.x for pos in image_pos], x_list)
    np.testing.assert_equal([pos.y for pos in image_pos], y_list)

    # Repeat, using flag columns this time.
    config = {
        'image_file_name': image_file,
        'cat_file_name': cat_file,
        'flag_col': 'flag',
        'use_flag': '1',
        'skip_flag': '4',
        'stamp_size': 48
    }
    input = piff.InputFiles(config, logger=logger)
    assert input.nimages == 1
    _, _, image_pos, _, _, _ = input.getRawImageData(0)
    assert len(image_pos) == 7

    # Make star data
    orig_stars = input.makeStars()
    assert len(orig_stars) == 7
    assert orig_stars[0].image.array.shape == (48, 48)

    # Process the star data
    # can only compare to truth if include_pixel=False
    model = piff.Gaussian(fastfit=True, include_pixel=False)
    interp = piff.Mean()
    fitted_stars = [model.fit(model.initialize(star)) for star in orig_stars]
    interp.solve(fitted_stars)
    print('mean = ', interp.mean)

    # Check that the interpolation is what it should be
    # Any position would work here.
    chipnum = 0
    x = 1024
    y = 123
    orig_wcs = input.getWCS()[chipnum]
    orig_pointing = input.getPointing()
    image_pos = galsim.PositionD(x, y)
    world_pos = piff.StarData.calculateFieldPos(image_pos, orig_wcs,
                                                orig_pointing)
    u, v = world_pos.x, world_pos.y
    stamp_size = config['stamp_size']

    target = piff.Star.makeTarget(x=x,
                                  y=y,
                                  u=u,
                                  v=v,
                                  wcs=orig_wcs,
                                  stamp_size=stamp_size,
                                  pointing=orig_pointing)
    true_params = [sigma, g1, g2]
    test_star = interp.interpolate(target)
    np.testing.assert_almost_equal(test_star.fit.params,
                                   true_params,
                                   decimal=4)

    # Check default values of options
    psf = piff.SimplePSF(model, interp)
    assert psf.chisq_thresh == 0.1
    assert psf.max_iter == 30
    assert psf.outliers == None
    assert psf.extra_interp_properties == []

    # Now test running it via the config parser
    psf_file = os.path.join('output', 'simple_psf.fits')
    config = {
        'input': {
            'image_file_name': image_file,
            'cat_file_name': cat_file,
            'flag_col': 'flag',
            'use_flag': 1,
            'skip_flag': 4,
            'stamp_size': stamp_size
        },
        'psf': {
            'model': {
                'type': 'Gaussian',
                'fastfit': True,
                'include_pixel': False
            },
            'interp': {
                'type': 'Mean'
            },
            'max_iter': 10,
            'chisq_thresh': 0.2,
        },
        'output': {
            'file_name': psf_file
        },
    }
    orig_stars, wcs, pointing = piff.Input.process(config['input'], logger)

    # Use a SimplePSF to process the stars data this time.
    interp = piff.Mean()
    psf = piff.SimplePSF(model, interp, max_iter=10, chisq_thresh=0.2)
    assert psf.chisq_thresh == 0.2
    assert psf.max_iter == 10

    psf.fit(orig_stars, wcs, pointing, logger=logger)
    test_star = psf.interp.interpolate(target)
    np.testing.assert_almost_equal(test_star.fit.params,
                                   true_params,
                                   decimal=4)

    # test that drawStar and drawStarList work
    test_star = psf.drawStar(target)
    test_star_list = psf.drawStarList([target])[0]
    np.testing.assert_equal(test_star.fit.params, test_star_list.fit.params)
    np.testing.assert_equal(test_star.image.array, test_star_list.image.array)

    # test copy_image property of drawStar and draw
    for draw in [psf.drawStar, psf.model.draw]:
        target_star_copy = psf.interp.interpolate(
            piff.Star(target.data.copy(), target.fit.copy()))
        # interp is so that when we do psf.model.draw we have fit.params to work with

        test_star_copy = draw(target_star_copy, copy_image=True)
        test_star_nocopy = draw(target_star_copy, copy_image=False)
        # if we modify target_star_copy, then test_star_nocopy should be modified,
        # but not test_star_copy
        target_star_copy.image.array[0, 0] = 23456
        assert test_star_nocopy.image.array[
            0, 0] == target_star_copy.image.array[0, 0]
        assert test_star_copy.image.array[0,
                                          0] != target_star_copy.image.array[0,
                                                                             0]
        # however the other pixels SHOULD still be all the same value
        assert test_star_nocopy.image.array[
            1, 1] == target_star_copy.image.array[1, 1]
        assert test_star_copy.image.array[1,
                                          1] == target_star_copy.image.array[1,
                                                                             1]

    # test that draw works
    test_image = psf.draw(x=target['x'],
                          y=target['y'],
                          stamp_size=config['input']['stamp_size'],
                          flux=target.fit.flux,
                          offset=target.fit.center)
    # this image should be the same values as test_star
    assert test_image == test_star.image
    # test that draw does not copy the image
    image_ref = psf.draw(x=target['x'],
                         y=target['y'],
                         stamp_size=config['input']['stamp_size'],
                         flux=target.fit.flux,
                         offset=target.fit.center,
                         image=test_image)
    image_ref.array[0, 0] = 123456789
    assert test_image.array[0, 0] == image_ref.array[0, 0]
    assert test_star.image.array[0, 0] != test_image.array[0, 0]
    assert test_star.image.array[1, 1] == test_image.array[1, 1]

    # Round trip to a file
    psf.write(psf_file, logger)
    psf2 = piff.read(psf_file, logger)
    assert type(psf2.model) is piff.Gaussian
    assert type(psf2.interp) is piff.Mean
    assert psf2.chisq == psf.chisq
    assert psf2.last_delta_chisq == psf.last_delta_chisq
    assert psf2.chisq_thresh == psf.chisq_thresh
    assert psf2.max_iter == psf.max_iter
    assert psf2.dof == psf.dof
    assert psf2.nremoved == psf.nremoved
    test_star = psf2.interp.interpolate(target)
    np.testing.assert_almost_equal(test_star.fit.params,
                                   true_params,
                                   decimal=4)

    # Do the whole thing with the config parser
    os.remove(psf_file)

    piff.piffify(config, logger)
    psf3 = piff.read(psf_file)
    assert type(psf3.model) is piff.Gaussian
    assert type(psf3.interp) is piff.Mean
    assert psf3.chisq == psf.chisq
    assert psf3.last_delta_chisq == psf.last_delta_chisq
    assert psf3.chisq_thresh == psf.chisq_thresh
    assert psf3.max_iter == psf.max_iter
    assert psf3.dof == psf.dof
    assert psf3.nremoved == psf.nremoved
    test_star = psf3.interp.interpolate(target)
    np.testing.assert_almost_equal(test_star.fit.params,
                                   true_params,
                                   decimal=4)

    # Test using the piffify executable
    os.remove(psf_file)
    # This would be simpler as a direct assignment, but this once, test the way you would set
    # this from the command line, which would call parse_variables.
    piff.config.parse_variables(config, ['verbose=0'], logger=logger)
    #config['verbose'] = 0
    with open('simple.yaml', 'w') as f:
        f.write(yaml.dump(config, default_flow_style=False))
    config2 = piff.config.read_config('simple.yaml')
    assert config == config2
    piffify_exe = get_script_name('piffify')
    p = subprocess.Popen([piffify_exe, 'simple.yaml'])
    p.communicate()
    psf4 = piff.read(psf_file)
    assert type(psf4.model) is piff.Gaussian
    assert type(psf4.interp) is piff.Mean
    assert psf4.chisq == psf.chisq
    assert psf4.last_delta_chisq == psf.last_delta_chisq
    assert psf4.chisq_thresh == psf.chisq_thresh
    assert psf4.max_iter == psf.max_iter
    assert psf4.dof == psf.dof
    assert psf4.nremoved == psf.nremoved
    test_star = psf4.interp.interpolate(target)
    np.testing.assert_almost_equal(test_star.fit.params,
                                   true_params,
                                   decimal=4)

    # With very low max_iter, we hit the warning about non-convergence
    config['psf']['max_iter'] = 1
    with CaptureLog(level=1) as cl:
        piff.piffify(config, cl.logger)
    assert 'PSF fit did not converge' in cl.output
コード例 #19
0
def test_yaml():

    if __name__ == '__main__':
        logger = piff.config.setup_logger(verbose=2)
    else:
        logger = piff.config.setup_logger(log_file='output/test_gp.log')

    # Take DES test image, and test doing a psf run with GP interpolator
    # Use config parser:
    psf_file = os.path.join('output', 'gp_psf.fits')
    config = {
        'input': {
            # These can be regular strings
            'image_file_name': 'input/DECam_00241238_01.fits.fz',
            # Or any GalSim str value type.  e.g. FormattedStr
            'cat_file_name': {
                'type': 'FormattedStr',
                'format':
                '%s/DECam_%08d_%02d_psfcat_tb_maxmag_17.0_magcut_3.0_findstars.fits',
                'items': [
                    'input',  # dir
                    241238,  # expnum
                    1  # chipnum
                ]
            },

            # What hdu is everything in?
            'image_hdu': 1,
            'badpix_hdu': 2,
            'weight_hdu': 3,
            'cat_hdu': 2,

            # What columns in the catalog have things we need?
            'x_col': 'XWIN_IMAGE',
            'y_col': 'YWIN_IMAGE',
            'ra': 'TELRA',
            'dec': 'TELDEC',
            'gain': 'GAINA',
            'sky_col': 'BACKGROUND',

            # How large should the postage stamp cutouts of the stars be?
            'stamp_size': 21,
        },
        'psf': {
            'model': {
                'type': 'GSObjectModel',
                'fastfit': True,
                'gsobj': 'galsim.Gaussian(sigma=1.0)'
            },
            'interp': {
                'type': 'GPInterp',
                'keys': ['u', 'v'],
                'optimizer': 'none',
                'kernel': 'RBF(200.0)'
            }
        },
        'output': {
            'file_name': psf_file
        },
    }

    piff.piffify(config, logger)
    psf = piff.read(psf_file)
    assert type(psf.model) is piff.GSObjectModel
    assert type(psf.interp) is piff.GPInterp
    print('nstars = ', len(psf.stars))
    target = psf.stars[17]
    test_star = psf.interp.interpolate(target)
    np.testing.assert_almost_equal(test_star.fit.params,
                                   target.fit.params,
                                   decimal=3)
    # This should also work if the target doesn't have a fit yet.
    print('interpolate ', piff.Star(target.data, None))
    test_star = psf.interp.interpolate(piff.Star(target.data, None))
    np.testing.assert_almost_equal(test_star.fit.params,
                                   target.fit.params,
                                   decimal=3)
コード例 #20
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)
コード例 #21
0
def fit_with_radial(self, star, interpfunc, vary_shape=True, vary_optics=True):

    params = star.fit.params

    flux = star.fit.flux
    if flux == 1.:
        # a pretty reasonable first guess is to just take the sum of the pixels
        flux = star.image.array.sum()
    du, dv = star.fit.center
    lmparams = lmfit.Parameters()
    # Order of params is important!
    lmparams.add('flux', value=flux, vary=True, min=0.0)
    lmparams.add('du', value=du, vary=True, min=-1, max=1)
    lmparams.add('dv', value=dv, vary=True, min=-1, max=1)
    # we must also cut the min and max based on opt_params to avoid things
    # like large ellipticities or small sizes
    min_size = self.optatmo_psf_kwargs['min_size']
    max_size = self.optatmo_psf_kwargs['max_size']
    max_g = self.optatmo_psf_kwargs['max_g1']
    # getParams puts in atmosphere terms

    fit_size = params[0]
    fit_g1 = params[1]
    fit_g2 = params[2]
    opt_size = params[3]
    opt_g1 = params[4]
    opt_g2 = params[5]
    lmparams.add('atmo_size', value=fit_size, vary=vary_shape, min=min_size - opt_size, max=max_size - opt_size)
    lmparams.add('atmo_g1', value=fit_g1,   vary=vary_shape, min=-max_g - opt_g1, max=max_g - opt_g1)
    lmparams.add('atmo_g2', value=fit_g2,   vary=vary_shape, min=-max_g - opt_g2, max=max_g - opt_g2)
    # add other params to the params model
    # we do NOT vary the optics size, g1, g2
    lmparams.add('optics_size', value=opt_size, vary=False)
    lmparams.add('optics_g1', value=opt_g1, vary=False)
    lmparams.add('optics_g2', value=opt_g2, vary=False)
    for i, pi in enumerate(params[6:]):
        # we do allow zernikes to vary
        lmparams.add('optics_zernike_{0}'.format(i + 4), value=pi, vary=vary_optics, min=-5, max=5)

    results = lmfit.minimize(_fit_model_residual_with_radial, lmparams, args=(star, self, interpfunc),
                             epsfcn=1e-5, method='leastsq')

    # subtract 3 for the flux, du, dv
    fit_params = np.zeros(len(results.params) - 3)
    params_var = np.zeros(len(fit_params))
    for i, key in enumerate(results.params):
        indx = i - 3
        if key in ['flux', 'du', 'dv']:
            continue
        param = results.params[key]
        fit_params[indx] = param.value
        if hasattr(param, 'stderr'):
            params_var[indx] = param.stderr ** 2

    flux = results.params['flux'].value
    du = results.params['du'].value
    dv = results.params['dv'].value
    center = (du, dv)
    chisq = results.chisqr
    dof = results.nfree

    fit = piff.StarFit(fit_params, params_var=params_var, flux=flux, center=center, chisq=chisq, dof=dof)
    star_fit = piff.Star(star.data.copy(), fit)

    return star_fit, results
コード例 #22
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__
コード例 #23
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
コード例 #24
0
ファイル: test_wcs.py プロジェクト: rmjarvis/Piff
def test_single():
    """Same as test_focal, but using the SingleCCD PSF type, which does a separate fit on each CCD.
    """
    wcs1 = galsim.TanWCS(
        galsim.AffineTransform(0.26, 0.05, -0.08, -0.24,
                               galsim.PositionD(1024, 1024)),
        galsim.CelestialCoord(-5 * galsim.arcmin, -25 * galsim.degrees))
    wcs2 = galsim.TanWCS(
        galsim.AffineTransform(0.25, -0.02, 0.01, 0.24,
                               galsim.PositionD(1024, 1024)),
        galsim.CelestialCoord(5 * galsim.arcmin, -25 * galsim.degrees))
    field_center = galsim.CelestialCoord(0 * galsim.degrees,
                                         -25 * galsim.degrees)

    if __name__ == '__main__':
        nstars = 20  # per ccd
        logger = piff.config.setup_logger(verbose=2)
    else:
        nstars = 6  # per ccd
        logger = piff.config.setup_logger(log_file='output/test_single.log')
    rng = np.random.RandomState(1234)
    x = rng.random_sample(nstars) * 2000 + 24
    y = rng.random_sample(nstars) * 2000 + 24
    ra1, dec1 = wcs1.toWorld(x, y, units='rad')
    u, v = field_center.project_rad(ra1, dec1, projection='gnomonic')
    e1 = 0.02 + 2.e-5 * u - 3.e-9 * u**2 + 2.e-9 * v**2
    e2 = -0.04 - 3.e-5 * v + 1.e-9 * u * v + 3.e-9 * v**2
    s = 0.3 + 8.e-9 * (u**2 + v**2) - 1.e-9 * u * v

    data1 = np.array(list(zip(x, y, e1, e2, s)),
                     dtype=[('x', float), ('y', float), ('e1', float),
                            ('e2', float), ('s', float)])
    im1 = drawImage(2048, 2048, wcs1, x, y, e1, e2, s)
    im1.write('output/test_single_im1.fits')
    fitsio.write('output/test_single_cat1.fits', data1, clobber=True)

    x = rng.random_sample(nstars) * 2000 + 24
    y = rng.random_sample(nstars) * 2000 + 24
    ra2, dec2 = wcs2.toWorld(x, y, units='rad')
    u, v = field_center.project_rad(ra1, dec1, projection='gnomonic')
    # Same functions of u,v, but using the positions on chip 2
    e1 = 0.02 + 2.e-5 * u - 3.e-9 * u**2 + 2.e-9 * v**2
    e2 = -0.04 - 3.e-5 * v + 1.e-9 * u * v + 3.e-9 * v**2
    s = 0.3 + 8.e-9 * (u**2 + v**2) - 1.e-9 * u * v

    data2 = np.array(list(zip(x, y, e1, e2, s)),
                     dtype=[('x', float), ('y', float), ('e1', float),
                            ('e2', float), ('s', float)])
    im2 = drawImage(2048, 2048, wcs2, x, y, e1, e2, s)
    im2.write('output/test_single_im2.fits')
    fitsio.write('output/test_single_cat2.fits', data2, clobber=True)

    ra12 = np.concatenate([ra1, ra2])
    dec12 = np.concatenate([dec1, dec2])
    data12 = np.array(list(zip(ra12, dec12)),
                      dtype=[('ra', float), ('dec', float)])
    fitsio.write('output/test_single_cat12.fits', data12, clobber=True)

    # Try to fit with the right model (Moffat) and interpolant (2nd order polyomial)
    # Should work very well, since no noise.
    config = {
        'input': {
            # A third way to input these same file names.  Use GalSim config values and
            # explicitly specify the number of images to read
            'nimages': 2,
            'image_file_name': {
                'type': 'FormattedStr',
                'format': '%s/test_single_im%d.fits',
                'items': ['output', '$image_num+1']
            },
            'cat_file_name': {
                'type': 'FormattedStr',
                'format': '%s/test_single_cat%d.fits',
                'items': ['output', '$image_num+1']
            },
            # Use chipnum = 1,2 rather than the default 0,1.
            'chipnum': '$image_num+1',
            'x_col': 'x',
            'y_col': 'y',
            'ra': 0.,
            'dec': -25.,
        },
        'psf': {
            'type': 'SingleChip',
            'model': {
                'type': 'Moffat',
                'beta': 2.5
            },
            'interp': {
                'type': 'Polynomial',
                'order': 2
            }
        },
    }
    if __name__ != '__main__':
        config['verbose'] = 0
    with CaptureLog(level=2) as cl:
        psf = piff.process(config, cl.logger)
    #print('without nproc, log = ',cl.output)
    assert "Building solution for chip 1" in cl.output
    assert "Building solution for chip 2" in cl.output

    for chipnum, data, wcs in [(1, data1, wcs1), (2, data2, wcs2)]:
        for k in range(nstars):
            x = data['x'][k]
            y = data['y'][k]
            e1 = data['e1'][k]
            e2 = data['e2'][k]
            s = data['s'][k]
            #print('k,x,y = ',k,x,y)
            #print('  true s,e1,e2 = ',s,e1,e2)
            image_pos = galsim.PositionD(x, y)
            star = piff.Star.makeTarget(x=x,
                                        y=y,
                                        wcs=wcs,
                                        stamp_size=48,
                                        pointing=field_center,
                                        chipnum=chipnum)
            star = psf.drawStar(star)
            #print('  fitted s,e1,e2 = ',star.fit.params)
            np.testing.assert_almost_equal(star.fit.params, [s, e1, e2],
                                           decimal=6)

    # Chipnum is required as a property to use SingleCCDPSF
    star1 = piff.Star.makeTarget(x=x,
                                 y=y,
                                 wcs=wcs,
                                 stamp_size=48,
                                 pointing=field_center)
    with np.testing.assert_raises(ValueError):
        psf.drawStar(star1)
    star2 = piff.Star(star1.data,
                      star.fit)  # If has a fit, it hits a different error
    with np.testing.assert_raises(ValueError):
        psf.drawStar(star2)
コード例 #25
0
ファイル: test_poly.py プロジェクト: emhuff/Piff
def poly_load_save_sub(type1, type2, fname):
    # Test that we can serialize and deserialize a polynomial
    # interpolator correctly.  Copying all this stuff from above:

    np_rng = np.random.RandomState(1234)
    nparam = 3
    nstars = 50
    # Use three different sizes to test everything
    orders = [1, 2, 3]
    interp = piff.Polynomial(orders=orders, poly_type=type1)
    X = 10.0  # size of the field
    Y = 10.0

    pos = [(np_rng.random_sample() * X, np_rng.random_sample() * Y)
           for i in range(nstars)]

    # Let's make a function that is linear just as a function of one parameter
    # These are the linear fit parameters for each parameter in turn
    m1 = np_rng.uniform(size=nparam)
    m2 = np_rng.uniform(size=nparam)
    q1 = np_rng.uniform(size=nparam)
    c = np_rng.uniform(size=nparam)

    def quadratic_func(pos):
        u = pos[0]
        v = pos[1]
        r = q1 * u * v + m1 * u + m2 * v + c
        return r

    # Simulate the vectors under this model
    vectors = [quadratic_func(p) for p in pos]

    # Fit them!
    data = [piff.Star.makeTarget(u=p[0], v=p[1]).data for p in pos]
    fit = [piff.StarFit(v) for v in vectors]
    stars = [piff.Star(d, f) for d, f in zip(data, fit)]
    interp.solve(stars)

    import tempfile
    import os
    import fitsio
    extname = "interp"
    dirname = 'output'
    filename = os.path.join(dirname, fname)
    with fitsio.FITS(filename, 'rw', clobber=True) as f:
        interp.write(f, extname=extname)
    with fitsio.FITS(filename, "r") as f2:
        interp2 = piff.Polynomial.read(f2, extname=extname)

    # The type and other parameters should now have been overwritten and updated
    assert interp2.poly_type == interp.poly_type
    assert interp2.order == interp.order
    np.testing.assert_array_equal(interp2.orders, interp.orders)
    assert interp2.nvariables == interp.nvariables
    np.testing.assert_array_equal(interp2.indices, interp.indices)

    # Check that the old and new interpolators generate the same
    # value
    for i in range(30):
        p = (np_rng.random_sample() * X, np_rng.random_sample() * Y)
        target = piff.Star.makeTarget(u=p[0], v=p[1])
        target1 = interp.interpolate(target)
        target2 = interp.interpolate(target)
        np.testing.assert_almost_equal(target1.fit.params, target2.fit.params)
コード例 #26
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)
コード例 #27
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
コード例 #28
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)
コード例 #29
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)