Пример #1
0
def test_chipnum():
    """Test the ability to renumber the chipnums
    """
    if __name__ == '__main__':
        logger = piff.config.setup_logger(verbose=2)
    else:
        logger = piff.config.setup_logger(
            log_file=os.path.join('output', 'test_input_chipnum.log'))

    # First, the default is to just use the index in the image list
    dir = 'input'
    image_files = 'test_input_image_*.fits'
    cat_files = 'test_input_cat_*.fits'
    config = {
        'dir': dir,
        'image_file_name': image_files,
        'cat_file_name': cat_files
    }
    input = piff.InputFiles(config, logger=logger)
    assert input.chipnums == list(range(3))

    # Now make the chipnums something else
    config = {
        'dir': dir,
        'image_file_name': image_files,
        'cat_file_name': cat_files,
        'chipnum': [5, 6, 7]
    }
    input = piff.InputFiles(config, logger=logger)
    assert input.chipnums == [i + 5 for i in range(3)]

    # Use the GalSim Eval capability to get the index + 1
    config = {
        'dir': dir,
        'image_file_name': image_files,
        'cat_file_name': cat_files,
        'chipnum': '$image_num + 1'
    }
    input = piff.InputFiles(config, logger=logger)
    assert input.chipnums == [i + 1 for i in range(3)]

    # Or parse it from the image_file_name
    config = {
        'dir': dir,
        'image_file_name': image_files,
        'cat_file_name': cat_files,
        'chipnum': {
            'type': 'Eval',
            'str': "image_file_name.split('_')[-1].split('.')[0]",
            'simage_file_name': '@input.image_file_name'
        }
    }
    input = piff.InputFiles(config, logger=logger)
    assert input.chipnums == list(range(3))
Пример #2
0
def test_boolarray():
    """Test the ability to use a flag_col that is really a boolean array rather than ints.
    """
    if __name__ == '__main__':
        logger = piff.config.setup_logger(verbose=2)
    else:
        logger = piff.config.setup_logger(
            log_file=os.path.join('output', 'test_input_bool.log'))

    cat_file_name = os.path.join('input', 'test_input_cat_00.fits')
    data = fitsio.read(cat_file_name)
    print('flag = ', data['flag'])
    new_flag = np.empty((len(data), 50), dtype=bool)
    for bit in range(50):
        new_flag[:, bit] = data['flag'] & 2**bit != 0
    print('new_flag = ', new_flag)
    # Write out the catalog to a file
    print('dtype = ', new_flag.dtype)
    dtype = [('x', 'f8'), ('y', 'f8'), ('flag', bool, 50)]
    new_data = np.empty(len(data), dtype=dtype)
    new_data['x'] = data['x']
    new_data['y'] = data['y']
    new_data['flag'] = new_flag
    new_cat_file_name = os.path.join('input', 'test_input_boolarray.fits')
    fitsio.write(new_cat_file_name, new_data, clobber=True)

    # Specifiable columns are: x, y, flag, use, sky, gain.  (We'll do flag, use below.)
    config = {
        'dir': 'input',
        'image_file_name': 'test_input_image_00.fits',
        'cat_file_name': 'test_input_boolarray.fits',
        'x_col': 'x',
        'y_col': 'y',
        'flag_col': 'flag',
        'skip_flag': '$2**1 + 2**2 + 2**39'
    }
    input = piff.InputFiles(config, logger=logger)
    assert input.nimages == 1
    _, _, image_pos, _, _, _ = input.getRawImageData(0)
    print('len = ', len(image_pos))
    assert len(image_pos) == 80
Пример #3
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
Пример #4
0
def test_basic():
    """Test the (usual) basic kind of input field without too many bells and whistles.
    """
    if __name__ == '__main__':
        logger = piff.config.setup_logger(verbose=2)
    else:
        logger = piff.config.setup_logger(
            log_file=os.path.join('output', 'test_input_basic.log'))

    dir = 'input'
    image_file = 'test_input_image_00.fits'
    cat_file = 'test_input_cat_00.fits'

    # Simple with one image, cat
    config = {
        'dir': dir,
        'image_file_name': image_file,
        'cat_file_name': cat_file
    }
    input = piff.InputFiles(config, logger=logger)
    assert input.nimages == 1
    _, _, image_pos, _, _, _ = input.getRawImageData(0)
    assert len(image_pos) == 100

    # Can omit the dir and just inlcude it in the file names
    config = {
        'image_file_name': os.path.join(dir, image_file),
        'cat_file_name': os.path.join(dir, cat_file)
    }
    input = piff.InputFiles(config, logger=logger)
    assert input.nimages == 1
    _, _, image_pos, _, _, _ = input.getRawImageData(0)
    assert len(image_pos) == 100

    # 3 images in a list
    image_files = ['test_input_image_%02d.fits' % k for k in range(3)]
    cat_files = ['test_input_cat_%02d.fits' % k for k in range(3)]
    config = {
        'dir': dir,
        'image_file_name': image_files,
        'cat_file_name': cat_files
    }
    input = piff.InputFiles(config, logger=logger)
    assert input.nimages == 3
    for i in range(3):
        _, _, image_pos, _, _, _ = input.getRawImageData(i)
        assert len(image_pos) == 100

    # Again without dir.
    image_files = ['input/test_input_image_%02d.fits' % k for k in range(3)]
    cat_files = ['input/test_input_cat_%02d.fits' % k for k in range(3)]
    config = {'image_file_name': image_files, 'cat_file_name': cat_files}
    input = piff.InputFiles(config, logger=logger)
    assert input.nimages == 3
    for i in range(3):
        _, _, image_pos, _, _, _ = input.getRawImageData(i)
        assert len(image_pos) == 100

    # 3 images using glob
    image_files = 'test_input_image_*.fits'
    cat_files = 'test_input_cat_*.fits'
    config = {
        'dir': dir,
        'image_file_name': image_files,
        'cat_file_name': cat_files
    }
    input = piff.InputFiles(config, logger=logger)
    assert input.nimages == 3
    for i in range(3):
        _, _, image_pos, _, _, _ = input.getRawImageData(i)
        assert len(image_pos) == 100

    # Can limit the number of stars
    config['nstars'] = 37
    input = piff.InputFiles(config, logger=logger)
    assert input.nimages == 3
    for i in range(3):
        _, _, image_pos, _, _, _ = input.getRawImageData(i)
        assert len(image_pos) == 37

    # Can limit stars differently on each chip
    config[
        'nstars'] = '$0 if @image_num == 1 else 20 if @image_num == 2 else 40'
    input = piff.InputFiles(config, logger=logger)
    assert input.nimages == 3
    for i in range(3):
        _, _, image_pos, _, _, _ = input.getRawImageData(i)
        if i == 0:
            assert len(image_pos) == 40
        elif i == 1:
            assert len(image_pos) == 0
        else:
            assert len(image_pos) == 20

    # Semi-gratuitous use of reserve_frac when one image has no stars for coverage
    config['reserve_frac'] = 0.2
    config['use_partial'] = True
    config['ra'] = 6.0
    config['dec'] = -30.0
    input = piff.InputFiles(config, logger=logger)
    assert input.nimages == 3
    stars = input.makeStars(logger=logger)
    print('stars = ', stars)
    print('len stars = ', len(stars))
    assert len(stars) == 60
    assert len([s for s in stars if s.chipnum == 0]) == 40
    assert len([s for s in stars if s.chipnum == 1]) == 0
    assert len([s for s in stars if s.chipnum == 2]) == 20
    reserve_stars = [s for s in stars if s.is_reserve]
    assert len(reserve_stars) == 12
    assert len([s for s in reserve_stars if s['chipnum'] == 0]) == 8
    assert len([s for s in reserve_stars if s['chipnum'] == 1]) == 0
    assert len([s for s in reserve_stars if s['chipnum'] == 2]) == 4

    # If no stars, raise error
    # (normally because all stars have errors, but easier to just limit to 0 to test this.)
    config['nstars'] = 0
    with np.testing.assert_raises(RuntimeError):
        input = piff.Input.process(config, logger=logger)
Пример #5
0
def test_stars():
    """Test the input.makeStars function
    """
    if __name__ == '__main__':
        logger = piff.config.setup_logger(verbose=2)
    else:
        logger = piff.config.setup_logger(
            log_file=os.path.join('output', 'test_input_stars.log'))

    dir = 'input'
    image_file = 'test_input_image_00.fits'
    cat_file = 'test_input_cat_00.fits'

    # Turn off two defaults for now (max_snr=100 and use_partial=False)
    config = {
        'dir': dir,
        'image_file_name': image_file,
        'cat_file_name': cat_file,
        'weight_hdu': 1,
        'sky_col': 'sky',
        'gain_col': 'gain',
        'max_snr': 0,
        'use_partial': True,
    }
    input = piff.InputFiles(config, logger=logger)
    stars = input.makeStars(logger=logger)
    assert len(stars) == 100
    chipnum_list = [star['chipnum'] for star in stars]
    gain_list = [star['gain'] for star in stars]
    snr_list = [star['snr'] for star in stars]
    snr_list2 = [
        piff.util.calculateSNR(star.data.image, star.data.orig_weight)
        for star in stars
    ]
    print('snr = ', np.min(snr_list), np.max(snr_list))
    np.testing.assert_array_equal(chipnum_list, 0)
    np.testing.assert_array_equal(gain_list, gain_list[0])
    np.testing.assert_almost_equal(snr_list, snr_list2, decimal=5)
    print('min_snr = ', np.min(snr_list))
    print('max_snr = ', np.max(snr_list))
    assert np.min(snr_list) < 20.
    assert np.max(snr_list) > 600.

    # max_snr increases the noise to achieve a maximum snr
    config['max_snr'] = 120
    input = piff.InputFiles(config, logger=logger)
    stars = input.makeStars(logger=logger)
    assert len(stars) == 100
    snr_list = [star['snr'] for star in stars]
    print('snr = ', np.min(snr_list), np.max(snr_list))
    assert np.min(snr_list) < 20.
    assert np.max(snr_list) == 120.
    snr_list2 = [
        piff.util.calculateSNR(star.data.image, star.data.orig_weight)
        for star in stars
    ]
    snr_list = np.array(snr_list)
    snr_list2 = np.array(snr_list2)
    lo = np.where(snr_list < 120)
    hi = np.where(snr_list == 120)
    # Uncorrected stars still have the same snr
    np.testing.assert_almost_equal(snr_list[lo], snr_list2[lo], decimal=5)
    # Corrected ones come out a little lower than the target.
    assert np.all(snr_list2[hi] <= 120.)
    assert np.all(snr_list2[hi] > 110.)

    # The default is max_snr == 100
    del config['max_snr']
    input = piff.InputFiles(config, logger=logger)
    stars = input.makeStars(logger=logger)
    assert len(stars) == 100
    snr_list = np.array([star['snr'] for star in stars])
    print('snr = ', np.min(snr_list), np.max(snr_list))
    assert np.min(snr_list) < 20.
    assert np.max(snr_list) == 100.
    snr_list2 = [
        piff.util.calculateSNR(star.data.image, star.data.orig_weight)
        for star in stars
    ]
    snr_list = np.array(snr_list)
    snr_list2 = np.array(snr_list2)
    lo = np.where(snr_list < 100)
    hi = np.where(snr_list == 100)
    np.testing.assert_almost_equal(snr_list[lo], snr_list2[lo], decimal=5)
    assert np.all(snr_list2[hi] <= 100.)

    # min_snr removes stars with a snr < min_snr
    config['min_snr'] = 50
    input = piff.InputFiles(config, logger=logger)
    stars = input.makeStars(logger=logger)
    print('len should be ', len(snr_list[snr_list >= 50]))
    print('actual len is ', len(stars))
    assert len(stars) == len(snr_list[snr_list >= 50])
    assert len(stars) == 93  # hard-coded for this case, just to make sure
    snr_list = np.array([star['snr'] for star in stars])
    print('snr = ', np.min(snr_list), np.max(snr_list))
    assert np.min(snr_list) >= 50.
    assert np.max(snr_list) == 100.
    snr_list2 = [
        piff.util.calculateSNR(star.data.image, star.data.orig_weight)
        for star in stars
    ]
    snr_list = np.array(snr_list)
    snr_list2 = np.array(snr_list2)
    lo = np.where(snr_list < 100)
    hi = np.where(snr_list == 100)
    np.testing.assert_almost_equal(snr_list[lo], snr_list2[lo], decimal=5)
    assert np.all(snr_list2[hi] <= 100.)

    # use_partial=False will skip any stars that are partially off the edge of the image
    config['use_partial'] = False
    input = piff.InputFiles(config, logger=logger)
    stars = input.makeStars(logger=logger)
    print('new len is ', len(stars))
    assert len(stars) == 91  # skipped 2 additional stars

    # use_partial=False is the default
    del config['use_partial']
    input = piff.InputFiles(config, logger=logger)
    stars = input.makeStars(logger=logger)
    assert len(stars) == 91

    # Setting satur will skip any stars with a pixel above that value.
    # Here there is 1 star with a pixel > 2000.
    config['satur'] = 'SATURAT'
    input = piff.InputFiles(config, logger=logger)
    stars = input.makeStars(logger=logger)
    assert len(stars) == 90
    # 7 stars have pixels > 1900
    config['satur'] = 1900
    input = piff.InputFiles(config, logger=logger)
    stars = input.makeStars(logger=logger)
    assert len(stars) == 84
    del config['satur']

    # hsm_size_reject=True rejects a few of these.
    config['hsm_size_reject'] = True
    input = piff.InputFiles(config, logger=logger)
    stars = input.makeStars(logger=logger)
    assert len(stars) == 88

    # hsm_size_reject can also be a float.  (True is equivalent to 10.)
    config['hsm_size_reject'] = 100.
    input = piff.InputFiles(config, logger=logger)
    stars = input.makeStars(logger=logger)
    assert len(stars) == 90
    config['hsm_size_reject'] = 3.
    input = piff.InputFiles(config, logger=logger)
    stars = input.makeStars(logger=logger)
    assert len(stars) == 84
    config['hsm_size_reject'] = 10.
    input = piff.InputFiles(config, logger=logger)
    stars = input.makeStars(logger=logger)
    assert len(stars) == 88
    del config['hsm_size_reject']

    # alt_x and alt_y also include some object completely off the image, which are always skipped.
    # (Don't do the min_snr anymore, since most of these stamps don't actually have any signal.)
    config['x_col'] = 'alt_x'
    config['y_col'] = 'alt_y'
    del config['min_snr']
    input = piff.InputFiles(config, logger=logger)
    stars = input.makeStars(logger=logger)
    print('new len is ', len(stars))
    assert len(stars) == 37

    # Also skip objects which are all weight=0
    config['weight_hdu'] = 3
    input = piff.InputFiles(config, logger=logger)
    stars = input.makeStars(logger=logger)
    print('new len is ', len(stars))
    assert len(stars) == 0

    # But not ones that are only partially weight=0
    config['weight_hdu'] = 8
    input = piff.InputFiles(config, logger=logger)
    stars = input.makeStars(logger=logger)
    print('new len is ', len(stars))
    assert len(stars) == 37

    # Check the masked pixel cut
    # This is a bit artificial, b/c 512 / 1024 of the pixels are masked in the test case
    del config['x_col']
    del config['y_col']
    config['weight_hdu'] = 8
    config['max_mask_pixels'] = 513
    input = piff.InputFiles(config, logger=logger)
    stars = input.makeStars(logger=logger)
    print('new len is ', len(stars))
    assert len(stars) == 98

    config['max_mask_pixels'] = 500
    input = piff.InputFiles(config, logger=logger)
    stars = input.makeStars(logger=logger)
    print('new len is ', len(stars))
    assert len(stars) == 0

    # Check the edge fraction cut
    # with use_partial=True to make sure it catch edge case
    del config['max_mask_pixels']
    config['max_edge_frac'] = 0.25
    config['use_partial'] = True
    input = piff.InputFiles(config, logger=logger)
    stars = input.makeStars(logger=logger)
    print('new len is ', len(stars))
    assert len(stars) == 94

    # Check that negative snr flux yields 0, not an error (from sqrt(neg))
    # Negative flux is actually ok, since it gets squared, but if an image has negative weights
    # (which would be weird of course), then it could get to negative flux = wI^2.
    star0 = stars[0]
    star0.data.orig_weight *= -1.
    snr0 = piff.util.calculateSNR(star0.data.image, star0.data.orig_weight)
    assert snr0 == 0.
Пример #6
0
def test_lsst_weight():
    """Test the way LSSTDM stores the weight (as a variance including signal)
    """
    if __name__ == '__main__':
        logger = piff.config.setup_logger(verbose=2)
    else:
        logger = piff.config.setup_logger(
            log_file=os.path.join('output', 'test_input_lsst.log'))

    # First with a sky level.  This isn't actually how LSST calexps are made (they are sky
    # subtracted), but it is how the input images are made.
    config = {
        'image_file_name': 'input/test_input_image_00.fits',
        'cat_file_name': 'input/test_input_cat_00.fits',
        'weight_hdu': 10,
        'sky': 'SKYLEVEL',
        'gain': 'GAIN_A',
        'invert_weight': True,
        'remove_signal_from_weight': True,
    }
    input = piff.InputFiles(config, logger=logger)
    assert input.nimages == 1
    image, weight, image_pos, sky, gain, _ = input.getRawImageData(0)
    assert len(image_pos) == 100
    assert image.array.shape == (1024, 1024)
    assert weight.array.shape == (1024, 1024)
    gain = gain[0]
    sky = sky[0]
    read_noise = 10
    expected_noise = sky / gain + read_noise**2 / gain**2
    print('expected noise = ', expected_noise)
    print('var = ', weight.array**-1)
    np.testing.assert_allclose(weight.array, expected_noise**-1, rtol=1.e-6)

    # If the gain is not given, it can determine it automatically.
    config = {
        'image_file_name': 'input/test_input_image_00.fits',
        'cat_file_name': 'input/test_input_cat_00.fits',
        'weight_hdu': 10,
        'sky': 'SKYLEVEL',
        'invert_weight': True,
        'remove_signal_from_weight': True,
    }
    input = piff.InputFiles(config, logger=logger)
    assert input.nimages == 1
    image, weight, image_pos, sky, gain1, _ = input.getRawImageData(0)
    np.testing.assert_allclose(gain1, gain, rtol=1.e-6)
    np.testing.assert_allclose(weight.array, expected_noise**-1, rtol=1.e-6)

    # Now pretend that the sky is part of the signal, so the input can match how we would
    # do this when running on calexps.
    config = {
        'image_file_name': 'input/test_input_image_00.fits',
        'cat_file_name': 'input/test_input_cat_00.fits',
        'weight_hdu': 10,
        'gain': 'GAIN_A',
        'invert_weight': True,
        'remove_signal_from_weight': True,
    }
    input = piff.InputFiles(config, logger=logger)
    assert input.nimages == 1
    image, weight, image_pos, _, gain, _ = input.getRawImageData(0)
    assert len(image_pos) == 100
    assert image.array.shape == (1024, 1024)
    assert weight.array.shape == (1024, 1024)
    gain = gain[0]
    read_noise = 10
    expected_noise = read_noise**2 / gain**2
    print('expected noise = ', expected_noise)
    print('var = ', weight.array**-1)
    np.testing.assert_allclose(weight.array, expected_noise**-1, rtol=1.e-5)
Пример #7
0
def test_weight():
    """Test the weight map and bad pixel masks
    """
    if __name__ == '__main__':
        logger = piff.config.setup_logger(verbose=2)
    else:
        logger = piff.config.setup_logger(
            log_file=os.path.join('output', 'test_input_weight.log'))

    # If no weight or badpix is specified, the weights are all equal.
    config = {
        'image_file_name': 'input/test_input_image_00.fits',
        'cat_file_name': 'input/test_input_cat_00.fits',
    }
    input = piff.InputFiles(config, logger=logger)
    assert input.nimages == 1
    image, weight, image_pos, _, _, _ = input.getRawImageData(0)
    assert len(image_pos) == 100
    assert image.array.shape == (1024, 1024)
    assert weight.array.shape == (1024, 1024)
    np.testing.assert_array_equal(weight.array, 1.0)

    # The default weight and badpix masks that GalSim makes don't do any masking, so this
    # is the almost the same as above, but the weight value is 1/sky.
    config = {
        'image_file_name': 'input/test_input_image_00.fits',
        'cat_file_name': 'input/test_input_cat_00.fits',
        'weight_hdu': 1,
        'badpix_hdu': 2,
        'sky_col':
        'sky',  # Used to determine what the value of weight should be
        'gain_col': 'gain',
    }
    input = piff.InputFiles(config, logger=logger)
    assert input.nimages == 1
    image, weight, image_pos, sky, gain, _ = input.getRawImageData(0)
    assert len(image_pos) == 100
    assert image.array.shape == (1024, 1024)
    assert weight.array.shape == (1024, 1024)
    sky = sky[0]
    gain = gain[0]
    read_noise = 10
    expected_noise = sky / gain + read_noise**2 / gain**2
    np.testing.assert_almost_equal(weight.array, expected_noise**-1)

    # Can set the noise by hand
    config = {
        'image_file_name': 'input/test_input_image_00.fits',
        'cat_file_name': 'input/test_input_cat_00.fits',
        'noise': 32,
    }
    input = piff.InputFiles(config, logger=logger)
    assert input.nimages == 1
    _, weight, _, _, _, _ = input.getRawImageData(0)
    assert weight.array.shape == (1024, 1024)
    np.testing.assert_almost_equal(weight.array, 32.**-1)

    # Some old versions of fitsio had a bug where the badpix mask could be offset by 32768.
    # We move them back to 0
    config = {
        'image_file_name': 'input/test_input_image_00.fits',
        'cat_file_name': 'input/test_input_cat_00.fits',
        'weight_hdu': 1,
        'badpix_hdu': 5,
    }
    input = piff.InputFiles(config, logger=logger)
    assert input.nimages == 1
    _, weight, _, _, _, _ = input.getRawImageData(0)
    assert weight.array.shape == (1024, 1024)
    np.testing.assert_almost_equal(weight.array, expected_noise**-1)

    config['badpix_hdu'] = 6
    input = piff.InputFiles(config, logger=logger)
    assert input.nimages == 1
    _, weight, _, _, _, _ = input.getRawImageData(0)
    assert weight.array.shape == (1024, 1024)
    np.testing.assert_almost_equal(weight.array, expected_noise**-1)

    # Various ways to get all weight values == 0 (which will emit a logger message, but isn't
    # an error).
    config['weight_hdu'] = 1
    config['badpix_hdu'] = 7  # badpix > 0
    input = piff.InputFiles(config, logger=logger)
    assert input.nimages == 1
    _, weight, _, _, _, _ = input.getRawImageData(0)
    assert weight.array.shape == (1024, 1024)
    np.testing.assert_almost_equal(weight.array, 0.)

    config['weight_hdu'] = 3  # wt = 0
    config['badpix_hdu'] = 2
    input = piff.InputFiles(config, logger=logger)
    assert input.nimages == 1
    _, weight, _, _, _, _ = input.getRawImageData(0)
    assert weight.array.shape == (1024, 1024)
    np.testing.assert_almost_equal(weight.array, 0.)

    config['weight_hdu'] = 8  # Even cols are = 0
    config['badpix_hdu'] = 9  # Odd cols are > 0
    input = piff.InputFiles(config, logger=logger)
    assert input.nimages == 1
    _, weight, _, _, _, _ = input.getRawImageData(0)
    assert weight.array.shape == (1024, 1024)
    np.testing.assert_almost_equal(weight.array, 0.)

    # Negative valued weights are invalid
    config['weight_hdu'] = 4
    input = piff.InputFiles(config)
    with CaptureLog() as cl:
        _, weight, _, _, _, _ = input.getRawImageData(0, logger=cl.logger)
    assert 'Warning: weight map has invalid negative-valued pixels.' in cl.output
Пример #8
0
def test_cols():
    """Test the various allowed column specifications
    """
    if __name__ == '__main__':
        logger = piff.config.setup_logger(verbose=2)
    else:
        logger = piff.config.setup_logger(
            log_file=os.path.join('output', 'test_input_cols.log'))

    # Specifiable columns are: x, y, flag, use, sky, gain.  (We'll do flag, use below.)
    config = {
        'dir': 'input',
        'image_file_name': 'test_input_image_02.fits',
        'cat_file_name': 'test_input_cat_02.fits',
        'x_col': 'x',
        'y_col': 'y',
    }
    input = piff.InputFiles(config, logger=logger)
    assert input.nimages == 1
    _, _, image_pos, _, _, _ = input.getRawImageData(0)
    assert len(image_pos) == 100

    # Can do ra, dec instead of x, y
    config = {
        'dir': 'input',
        'image_file_name': 'test_input_image_02.fits',
        'cat_file_name': 'test_input_cat_02.fits',
        'ra_col': 'ra',
        'dec_col': 'dec',
        'ra_units': 'hours',
        'dec_units': 'degrees',
    }
    input2 = piff.InputFiles(config, logger=logger)
    assert input2.nimages == 1
    _, _, image_pos2, _, _, _ = input2.getRawImageData(0)
    print('input.image_pos = ', image_pos)
    print('input2.image_pos = ', image_pos2)
    assert len(image_pos2) == 100
    x1 = [pos.x for pos in image_pos]
    x2 = [pos.x for pos in image_pos2]
    y1 = [pos.y for pos in image_pos]
    y2 = [pos.y for pos in image_pos2]
    np.testing.assert_allclose(x2, x1)
    np.testing.assert_allclose(y2, y1)

    # Back to first file, where we also have header values for things.
    cat_file_name = os.path.join('input', 'test_input_cat_00.fits')
    data = fitsio.read(cat_file_name)
    sky = np.mean(data['sky'])
    gain = np.mean(data['gain'])
    config = {
        'dir': 'input',
        'image_file_name': 'test_input_image_00.fits',
        'cat_file_name': 'test_input_cat_00.fits',
        'x_col': 'x',
        'y_col': 'y',
        'sky_col': 'sky',
        'gain_col': 'gain',
    }
    input = piff.InputFiles(config, logger=logger)
    assert input.nimages == 1
    _, _, image_pos, sky_list, gain_list, _ = input.getRawImageData(0)
    assert len(image_pos) == 100
    assert len(sky_list) == 100
    assert len(gain_list) == 100
    # sky and gain are constant (although they don't have to be of course)
    np.testing.assert_array_equal(sky_list, sky)
    np.testing.assert_array_equal(gain_list, gain)

    # sky and gain can also be given as float values for the whole catalog
    config = {
        'dir': 'input',
        'image_file_name': 'test_input_image_00.fits',
        'cat_file_name': 'test_input_cat_00.fits',
        'sky': sky,
        'gain': gain,
    }
    input = piff.InputFiles(config, logger=logger)
    _, _, image_pos, sky_list, gain_list, _ = input.getRawImageData(0)
    assert len(image_pos) == 100
    assert len(sky_list) == 100
    assert len(gain_list) == 100
    # These aren't precisely equal because we go through a str value, which truncates it.
    # We could hack this to keep it exact, but it's probably not worth it and it's easier to
    # enable both str and float by reading it as str and then trying the float conversion to see
    # it if works.  Anyway, that's why this is only decimal=9.
    np.testing.assert_almost_equal(sky_list, sky, decimal=9)
    np.testing.assert_almost_equal(gain_list, gain, decimal=9)

    # sky and gain can also be given as str values, which mean look in the FITS header.
    config = {
        'dir': 'input',
        'image_file_name': 'test_input_image_00.fits',
        'cat_file_name': 'test_input_cat_00.fits',
        'sky': 'SKYLEVEL',
        'gain': 'GAIN_A',
    }
    input = piff.InputFiles(config, logger=logger)
    _, _, image_pos, sky_list, gain_list, _ = input.getRawImageData(0)
    assert len(image_pos) == 100
    assert len(sky_list) == 100
    assert len(gain_list) == 100
    np.testing.assert_almost_equal(sky_list, sky)
    np.testing.assert_almost_equal(gain_list, gain)

    # including satur will skip stars that are over the given saturation value.
    # (It won't skip them here, just when building the stars list.)
    config = {
        'dir': 'input',
        'image_file_name': 'test_input_image_00.fits',
        'cat_file_name': 'test_input_cat_00.fits',
        'sky': 'SKYLEVEL',
        'gain': 'GAIN_A',
        'satur': 2000,
    }
    input = piff.InputFiles(config, logger=logger)
    _, _, image_pos, _, _, satur = input.getRawImageData(0)
    assert satur == 2000
    assert len(image_pos) == 100

    config = {
        'dir': 'input',
        'image_file_name': 'test_input_image_00.fits',
        'cat_file_name': 'test_input_cat_00.fits',
        'sky': 'SKYLEVEL',
        'gain': 'GAIN_A',
        'satur': 'SATURAT',
    }
    input = piff.InputFiles(config, logger=logger)
    _, _, image_pos, _, _, satur = input.getRawImageData(0)
    assert satur == 2000
    assert len(image_pos) == 100

    # Using flag will skip flagged columns.  Here every 5th item is flagged.
    config = {
        'dir': 'input',
        'image_file_name': 'test_input_image_00.fits',
        'cat_file_name': 'test_input_cat_00.fits',
        'flag_col': 'flag',
        'skip_flag': 4
    }
    input = piff.InputFiles(config, logger=logger)
    _, _, image_pos, _, _, _ = input.getRawImageData(0)
    assert input.nimages == 1
    print('len = ', len(image_pos))
    assert len(image_pos) == 80

    # Similarly the use columns will skip anything with use == 0 (every 7th item here)
    config = {
        'dir': 'input',
        'image_file_name': 'test_input_image_00.fits',
        'cat_file_name': 'test_input_cat_00.fits',
        'flag_col': 'flag',
        'use_flag': 1
    }
    input = piff.InputFiles(config, logger=logger)
    _, _, image_pos, _, _, _ = input.getRawImageData(0)
    print('len = ', len(image_pos))
    assert len(image_pos) == 85

    # Can do both
    config = {
        'dir': 'input',
        'image_file_name': 'test_input_image_00.fits',
        'cat_file_name': 'test_input_cat_00.fits',
        'flag_col': 'flag',
        'skip_flag': '$2**2',
        'use_flag': '$2**0',
    }
    input = piff.InputFiles(config, logger=logger)
    _, _, image_pos, _, _, _ = input.getRawImageData(0)
    print('len = ', len(image_pos))
    assert len(image_pos) == 68

    # If no skip_flag is specified, it skips all != 0.
    config = {
        'dir': 'input',
        'image_file_name': 'test_input_image_00.fits',
        'cat_file_name': 'test_input_cat_00.fits',
        'flag_col': 'flag',
    }
    input = piff.InputFiles(config, logger=logger)
    _, _, image_pos, _, _, _ = input.getRawImageData(0)
    print('len = ', len(image_pos))
    assert len(image_pos) == 12

    # Check invalid column names
    base_config = {
        'dir': 'input',
        'image_file_name': 'test_input_image_00.fits',
        'cat_file_name': 'test_input_cat_00.fits',
    }
    input = piff.InputFiles(dict(x_col='xx', **base_config))
    np.testing.assert_raises(ValueError, input.getRawImageData, 0)
    input = piff.InputFiles(dict(x_col='xx', y_col='y', **base_config))
    np.testing.assert_raises(ValueError, input.getRawImageData, 0)
    input = piff.InputFiles(dict(x_col='x', y_col='xx', **base_config))
    np.testing.assert_raises(ValueError, input.getRawImageData, 0)
    input = piff.InputFiles(dict(ra_col='xx', **base_config))
    np.testing.assert_raises(ValueError, input.getRawImageData, 0)
    input = piff.InputFiles(dict(ra_col='xx', dec_col='y', **base_config))
    np.testing.assert_raises(ValueError, input.getRawImageData, 0)
    input = piff.InputFiles(dict(ra_col='x', dec_col='xx', **base_config))
    np.testing.assert_raises(ValueError, input.getRawImageData, 0)
    input = piff.InputFiles(dict(sky_col='xx', **base_config))
    np.testing.assert_raises(ValueError, input.getRawImageData, 0)
    input = piff.InputFiles(dict(gain_col='xx', **base_config))
    np.testing.assert_raises(ValueError, input.getRawImageData, 0)
    input = piff.InputFiles(dict(flag_col='xx', **base_config))
    np.testing.assert_raises(ValueError, input.getRawImageData, 0)

    # skip_flag, use_flag need to be integers
    np.testing.assert_raises(
        ValueError, piff.InputFiles,
        dict(flag_col='flag', skip_flag='xx', **base_config))
    np.testing.assert_raises(
        ValueError, piff.InputFiles,
        dict(flag_col='flag', use_flag='xx', **base_config))

    # Can't give duplicate sky, gain
    np.testing.assert_raises(ValueError, piff.InputFiles,
                             dict(sky_col='sky', sky=3, **base_config))
    np.testing.assert_raises(ValueError, piff.InputFiles,
                             dict(gain_col='gain', gain=3, **base_config))

    # Invalid header keys
    input = piff.InputFiles(dict(sky='sky', **base_config))
    np.testing.assert_raises(KeyError, input.getRawImageData, 0)
    input = piff.InputFiles(dict(gain='gain', **base_config))
    np.testing.assert_raises(KeyError, input.getRawImageData, 0)
    input = piff.InputFiles(dict(satur='satur', **base_config))
    np.testing.assert_raises(KeyError, input.getRawImageData, 0)
Пример #9
0
def test_single_image():
    """Test the whole process with a single image.

    Note: This test is based heavily on test_single_image in test_simple.py.
    """
    import os
    import fitsio
    np_rng = np.random.RandomState(1234)

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

    # The (x,y) values will be on a grid 5 x 5 stars with a random sub-pixel offset.
    xvals = np.linspace(50., 1950., 5)
    yvals = np.linspace(50., 1950., 5)
    x_list, y_list = np.meshgrid(xvals, yvals)
    x_list = x_list.flatten()
    y_list = y_list.flatten()
    x_list = x_list + (np_rng.rand(len(x_list)) - 0.5)
    y_list = y_list + (np_rng.rand(len(x_list)) - 0.5)
    print('x_list = ', x_list)
    print('y_list = ', y_list)
    # Range of fluxes from 100 to 15000
    flux_list = 100. * np.exp(5. * np_rng.rand(len(x_list)))
    print('fluxes range from ', np.min(flux_list), np.max(flux_list))

    # Draw a Moffat PSF at each location on the image.
    # Have the truth values vary quadratically across the image.
    beta_fn = lambda x, y: 3.5 - 0.1 * (x / 1000) + 0.08 * (y / 1000)**2
    fwhm_fn = lambda x, y: 0.9 + 0.05 * (x / 1000) - 0.03 * (
        y / 1000) + 0.02 * (x / 1000) * (y / 1000)
    e1_fn = lambda x, y: 0.02 - 0.01 * (x / 1000)
    e2_fn = lambda x, y: -0.03 + 0.02 * (x / 1000)**2 - 0.01 * (y / 1000) * 2

    for x, y, flux in zip(x_list, y_list, flux_list):
        beta = beta_fn(x, y)
        fwhm = fwhm_fn(x, y)
        e1 = e1_fn(x, y)
        e2 = e2_fn(x, y)
        print(x, y, beta, fwhm, e1, e2)
        moffat = galsim.Moffat(fwhm=fwhm, beta=beta, flux=flux).shear(e1=e1,
                                                                      e2=e2)
        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)
        moffat.drawImage(image=image[bounds], offset=offset, method='no_pixel')
    print('drew image')

    # Write out the image to a file
    image_file = os.path.join('data', 'pixel_moffat_image.fits')
    image.write(image_file)
    print('wrote image')

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

    # Use InputFiles to read these back in
    input = piff.InputFiles(image_file, cat_file, stamp_size=32)
    assert input.image_files == [image_file]
    assert input.cat_files == [cat_file]
    assert input.x_col == 'x'
    assert input.y_col == 'y'

    # Check image
    input.readImages()
    assert len(input.images) == 1
    np.testing.assert_equal(input.images[0].array, image.array)

    # Check catalog
    input.readStarCatalogs()
    assert len(input.cats) == 1
    np.testing.assert_equal(input.cats[0]['x'], x_list)
    np.testing.assert_equal(input.cats[0]['y'], y_list)

    # Make stars
    orig_stars = input.makeStars()
    assert len(orig_stars) == len(x_list)
    assert orig_stars[0].image.array.shape == (32, 32)

    # Make a test star, not at the location of any of the model stars to use for each of the
    # below tests.
    x0 = 1024  # Some random position, not where a star was originally.
    y0 = 133
    beta = beta_fn(x0, y0)
    fwhm = fwhm_fn(x0, y0)
    e1 = e1_fn(x0, y0)
    e2 = e2_fn(x0, y0)
    moffat = galsim.Moffat(fwhm=fwhm, beta=beta).shear(e1=e1, e2=e2)
    target_star = piff.Star.makeTarget(x=x0, y=y0, scale=image.scale)
    test_im = galsim.ImageD(bounds=target_star.image.bounds, scale=image.scale)
    moffat.drawImage(image=test_im, method='no_pixel', use_true_center=False)
    print('made test star')

    # These tests are slow, and it's really just doing the same thing three times, so
    # only do the first one when running via nosetests.
    if True:
        # Process the star data
        model = piff.PixelGrid(0.2, 16, start_sigma=0.9 / 2.355)
        interp = piff.BasisPolynomial(order=2)
        if __name__ == '__main__':
            logger = piff.config.setup_logger(2)
        else:
            logger = None
        pointing = None  # wcs is not Celestial here, so pointing needs to be None.
        psf = piff.SimplePSF(model, interp)
        psf.fit(orig_stars, {0: input.images[0].wcs}, pointing, logger=logger)

        # Check that the interpolation is what it should be
        print('target.flux = ', target_star.fit.flux)
        test_star = psf.drawStar(target_star)
        #print('test_im center = ',test_im[b].array)
        #print('flux = ',test_im.array.sum())
        #print('interp_im center = ',test_star.image[b].array)
        #print('flux = ',test_star.image.array.sum())
        #print('max diff = ',np.max(np.abs(test_star.image.array-test_im.array)))
        np.testing.assert_almost_equal(test_star.image.array,
                                       test_im.array,
                                       decimal=3)

        # Check the convenience function that an end user would typically use
        image = psf.draw(x=x0, y=y0)
        np.testing.assert_almost_equal(image.array, test_im.array, decimal=3)

        # Round trip through a file
        psf_file = os.path.join('output', 'pixel_psf.fits')
        psf.write(psf_file, logger)
        psf = piff.read(psf_file, logger)
        assert type(psf.model) is piff.PixelGrid
        assert type(psf.interp) is piff.BasisPolynomial
        test_star = psf.drawStar(target_star)
        np.testing.assert_almost_equal(test_star.image.array,
                                       test_im.array,
                                       decimal=3)

        # Check the convenience function that an end user would typically use
        image = psf.draw(x=x0, y=y0)
        np.testing.assert_almost_equal(image.array, test_im.array, decimal=3)

    # Do the whole thing with the config parser
    config = {
        'input': {
            'images': image_file,
            'cats': cat_file,
            'x_col': 'x',
            'y_col': 'y',
            'stamp_size': 48  # Bigger than we drew, but should still work.
        },
        'output': {
            'file_name': psf_file
        },
        'psf': {
            'model': {
                'type': 'PixelGrid',
                'scale': 0.2,
                'size':
                16,  # Much smaller than the input stamps, but this is plenty here.
                'start_sigma': 0.9 / 2.355
            },
            'interp': {
                'type': 'BasisPolynomial',
                'order': 2
            },
        },
    }
    if __name__ == '__main__':
        print("Running piffify function")
        piff.piffify(config)
        psf = piff.read(psf_file)
        test_star = psf.drawStar(target_star)
        np.testing.assert_almost_equal(test_star.image.array,
                                       test_im.array,
                                       decimal=3)

    # Test using the piffify executable
    config['verbose'] = 0
    with open('pixel_moffat.yaml', 'w') as f:
        f.write(yaml.dump(config, default_flow_style=False))
    if __name__ == '__main__':
        print("Running piffify executable")
        if os.path.exists(psf_file):
            os.remove(psf_file)
        piffify_exe = get_script_name('piffify')
        p = subprocess.Popen([piffify_exe, 'pixel_moffat.yaml'])
        p.communicate()
        psf = piff.read(psf_file)
        test_star = psf.drawStar(target_star)
        np.testing.assert_almost_equal(test_star.image.array,
                                       test_im.array,
                                       decimal=3)
Пример #10
0
def test_pointing():
    """Test the input.setPointing function
    """
    if __name__ == '__main__':
        logger = piff.config.setup_logger(verbose=2)
    else:
        logger = piff.config.setup_logger(
            log_file=os.path.join('output', 'test_input_pointing.log'))

    dir = 'input'
    image_file = 'test_input_image_00.fits'
    cat_file = 'test_input_cat_00.fits'

    # First, with no ra, dec, pointing is None
    config = {
        'dir': dir,
        'image_file_name': image_file,
        'cat_file_name': cat_file,
    }
    input = piff.InputFiles(config, logger=logger)
    assert input.pointing is None

    # Explicit ra, dec as floats
    config['ra'] = 6.0
    config['dec'] = -30.0
    input = piff.InputFiles(config, logger=logger)
    np.testing.assert_almost_equal(input.pointing.ra.rad, np.pi / 2.)
    np.testing.assert_almost_equal(input.pointing.dec.rad, -np.pi / 6.)

    # Also ok as ints in this case
    config['ra'] = 6
    config['dec'] = -30
    input = piff.InputFiles(config, logger=logger)
    np.testing.assert_almost_equal(input.pointing.ra.rad, np.pi / 2.)
    np.testing.assert_almost_equal(input.pointing.dec.rad, -np.pi / 6.)

    # Strings as hh:mm:ss or dd:mm:ss
    config['ra'] = '06:00:00'
    config['dec'] = '-30:00:00'
    input = piff.InputFiles(config, logger=logger)
    np.testing.assert_almost_equal(input.pointing.ra.rad, np.pi / 2.)
    np.testing.assert_almost_equal(input.pointing.dec.rad, -np.pi / 6.)

    # Strings as keys into FITS header
    config['ra'] = 'RA'
    config['dec'] = 'DEC'
    input = piff.InputFiles(config, logger=logger)
    np.testing.assert_almost_equal(input.pointing.ra.rad, np.pi / 2.)
    np.testing.assert_almost_equal(input.pointing.dec.rad, -np.pi / 6.)

    # If multiple files, use the first one.
    config['image_file_name'] = 'test_input_image_*.fits'
    config['cat_file_name'] = 'test_input_cat_*.fits'
    input = piff.InputFiles(config, logger=logger)
    np.testing.assert_almost_equal(input.pointing.ra.rad, np.pi / 2.)
    np.testing.assert_almost_equal(input.pointing.dec.rad, -np.pi / 6.)

    # Check invalid ra,dec values
    base_config = {
        'dir': dir,
        'image_file_name': image_file,
        'cat_file_name': cat_file
    }
    np.testing.assert_raises(ValueError, piff.InputFiles,
                             dict(ra=0, dec='00:00:00', **base_config))
    np.testing.assert_raises(ValueError, piff.InputFiles,
                             dict(ra='00:00:00', dec=0, **base_config))
    np.testing.assert_raises(
        ValueError, piff.InputFiles,
        dict(ra=0 * galsim.degrees, dec=0 * galsim.radians, **base_config))
    np.testing.assert_raises(KeyError, piff.InputFiles,
                             dict(ra='bad_ra', dec='DEC', **base_config))
    np.testing.assert_raises(KeyError, piff.InputFiles,
                             dict(ra='RA', dec='bad_dec', **base_config))
    np.testing.assert_raises(ValueError, piff.InputFiles,
                             dict(ra=0, **base_config))
    np.testing.assert_raises(ValueError, piff.InputFiles,
                             dict(dec=0, **base_config))

    # If image has celestial wcs, and no ra, dec specified then it will compute it for you
    config = {
        'dir': dir,
        'image_file_name': 'DECam_00241238_01.fits.fz',
        'cat_file_name': 'DECam_00241238_01_cat.fits',
        'cat_hdu': 2,
        'x_col': 'XWIN_IMAGE',
        'y_col': 'YWIN_IMAGE',
    }
    input = piff.InputFiles(config, logger=logger)
    np.testing.assert_almost_equal(input.pointing.ra / galsim.hours,
                                   4.063,
                                   decimal=3)
    np.testing.assert_almost_equal(input.pointing.dec / galsim.degrees,
                                   -51.471,
                                   decimal=3)

    # Similar, but not quite equal to teh TELRA, TELDEC, which is at center of exposure.
    config['ra'] = 'TELRA'
    config['dec'] = 'TELDEC'
    input = piff.InputFiles(config, logger=logger)
    np.testing.assert_almost_equal(input.pointing.ra / galsim.hours,
                                   4.097,
                                   decimal=3)
    np.testing.assert_almost_equal(input.pointing.dec / galsim.degrees,
                                   -52.375,
                                   decimal=3)

    # We only have the one celestial wcs image in the repo, but with multiple ones, it will
    # average over all images.
    config = {
        'dir':
        dir,
        'image_file_name':
        ['DECam_00241238_01.fits.fz', 'DECam_00241238_01.fits.fz'],
        'cat_file_name':
        ['DECam_00241238_01_cat.fits', 'DECam_00241238_01_cat.fits'],
        'cat_hdu':
        2,
        'x_col':
        'XWIN_IMAGE',
        'y_col':
        'YWIN_IMAGE',
    }
    input = piff.InputFiles(config, logger=logger)
    np.testing.assert_almost_equal(input.pointing.ra / galsim.hours,
                                   4.063,
                                   decimal=3)
    np.testing.assert_almost_equal(input.pointing.dec / galsim.degrees,
                                   -51.471,
                                   decimal=3)
Пример #11
0
def test_single_image():
    """Test the simple case of one image and one catalog.
    """
    # 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 = [0, 0, 12, 0, 0, 1, 0, 0, 0, 0]
    use_list = [1, 1, 1, 1, 1, 0, 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, use in zip(x_list, y_list, flag_list, use_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:
            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('data', 'simple_image.fits')
    image.write(image_file)

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

    # Use InputFiles to read these back in
    input = piff.InputFiles(image_file, cat_file)
    assert input.image_files == [image_file]
    assert input.cat_files == [cat_file]
    assert input.x_col == 'x'
    assert input.y_col == 'y'

    # Check image
    input.readImages()
    assert len(input.images) == 1
    np.testing.assert_equal(input.images[0].array, image.array)

    # Check catalog
    input.readStarCatalogs()
    assert len(input.cats) == 1
    np.testing.assert_equal(input.cats[0]['x'], x_list)
    np.testing.assert_equal(input.cats[0]['y'], y_list)

    # Repeat, using flag and use columns this time.
    input = piff.InputFiles(image_file,
                            cat_file,
                            flag_col='flag',
                            use_col='use',
                            stamp_size=48)
    assert input.flag_col == 'flag'
    assert input.use_col == 'use'
    input.readImages()
    input.readStarCatalogs()
    assert len(input.cats[0]) == 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
    target = piff.Star.makeTarget(x=1024,
                                  y=123)  # Any position would work here.
    true_params = [sigma, g1, g2]
    test_star = interp.interpolate(target)
    np.testing.assert_almost_equal(test_star.fit.params,
                                   true_params,
                                   decimal=4)

    # Now test running it via the config parser
    psf_file = os.path.join('output', 'simple_psf.fits')
    config = {
        'input': {
            'images': image_file,
            'cats': cat_file,
            'flag_col': 'flag',
            'use_col': 'use',
            'stamp_size': 48
        },
        'psf': {
            'model': {
                'type': 'Gaussian',
                'fastfit': True,
                'include_pixel': False
            },
            'interp': {
                'type': 'Mean'
            },
        },
        'output': {
            'file_name': psf_file
        },
    }
    if __name__ == '__main__':
        logger = piff.config.setup_logger(verbose=2)
    else:
        logger = piff.config.setup_logger(verbose=0)
    orig_stars, wcs, pointing = piff.Input.process(config['input'], logger)

    # Use a SimplePSF to process the stars data this time.
    psf = piff.SimplePSF(model, interp)

    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)

    # Round trip to a file
    psf.write(psf_file, logger)
    psf = piff.read(psf_file, logger)
    assert type(psf.model) is piff.Gaussian
    assert type(psf.interp) is piff.Mean
    test_star = psf.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)
    psf = piff.read(psf_file)
    test_star = psf.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)
    config['verbose'] = 0
    with open('simple.yaml', 'w') as f:
        f.write(yaml.dump(config, default_flow_style=False))
    piffify_exe = get_script_name('piffify')
    p = subprocess.Popen([piffify_exe, 'simple.yaml'])
    p.communicate()
    psf = piff.read(psf_file)
    test_star = psf.interp.interpolate(target)
    np.testing.assert_almost_equal(test_star.fit.params,
                                   true_params,
                                   decimal=4)

    # Test that we can make rho statistics
    min_sep = 1
    max_sep = 100
    bin_size = 0.1
    stats = piff.RhoStats(min_sep=min_sep, max_sep=max_sep, bin_size=bin_size)
    stats.compute(psf, orig_stars)

    rhos = [stats.rho1, stats.rho2, stats.rho3, stats.rho4, stats.rho5]
    for rho in rhos:
        # Test the range of separations
        radius = np.exp(rho.logr)
        # last bin can be one bigger than max_sep
        np.testing.assert_array_less(radius,
                                     np.exp(np.log(max_sep) + bin_size))
        np.testing.assert_array_less(min_sep, radius)
        np.testing.assert_array_almost_equal(np.diff(rho.logr),
                                             bin_size,
                                             decimal=5)

        # Test that the max absolute value of each rho isn't crazy
        np.testing.assert_array_less(np.abs(rho.xip), 1)

        # # Check that each rho isn't precisely zero. This means the sum of abs > 0
        np.testing.assert_array_less(0, np.sum(np.abs(rho.xip)))

    # Test the plotting and writing
    rho_psf_file = os.path.join('output', 'simple_psf_rhostats.pdf')
    stats.write(rho_psf_file)

    # Test that we can make summary shape statistics, using HSM
    shapeStats = piff.ShapeHistogramsStats()
    shapeStats.compute(psf, orig_stars)

    # test their characteristics
    np.testing.assert_array_almost_equal(sigma, shapeStats.T, decimal=4)
    np.testing.assert_array_almost_equal(sigma, shapeStats.T_model, decimal=3)
    np.testing.assert_array_almost_equal(g1, shapeStats.g1, decimal=4)
    np.testing.assert_array_almost_equal(g1, shapeStats.g1_model, decimal=3)
    np.testing.assert_array_almost_equal(g2, shapeStats.g2, decimal=4)
    np.testing.assert_array_almost_equal(g2, shapeStats.g2_model, decimal=3)

    shape_psf_file = os.path.join('output', 'simple_psf_shapestats.pdf')
    shapeStats.write(shape_psf_file)

    # Test that we can use the config parser for both RhoStats and ShapeHistogramsStats
    config['output']['stats'] = [
        {
            'type': 'ShapeHistograms',
            'file_name': shape_psf_file
        },
        {
            'type': 'Rho',
            'file_name': rho_psf_file
        },
        {
            'type': 'TwoDHist',
            'file_name': os.path.join('output',
                                      'simple_psf_twodhiststats.pdf'),
            'number_bins_u': 3,
            'number_bins_v': 3,
        },
        {
            'type': 'TwoDHist',
            'file_name': os.path.join('output',
                                      'simple_psf_twodhiststats_std.pdf'),
            'reducing_function': 'np.std',
            'number_bins_u': 3,
            'number_bins_v': 3,
        },
    ]

    os.remove(psf_file)
    os.remove(rho_psf_file)
    os.remove(shape_psf_file)
    piff.piffify(config, logger)

    # Test using the piffify executable
    os.remove(psf_file)
    os.remove(rho_psf_file)
    os.remove(shape_psf_file)
    config['verbose'] = 0
    with open('simple.yaml', 'w') as f:
        f.write(yaml.dump(config, default_flow_style=False))
    p = subprocess.Popen([piffify_exe, 'simple.yaml'])
    p.communicate()
Пример #12
0
def test_chisq():
    """Test the Chisq outlier class
    """
    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(512, 512, scale=0.26)

    nstars = 1000  # enough that there could be some overlaps.  Also, some over the edge.
    rng = np.random.RandomState(1234)
    x = rng.random_sample(nstars) * 512
    y = rng.random_sample(nstars) * 512
    sigma = np.ones_like(x) * 0.4  # Most have this sigma
    g1 = np.ones_like(x) * 0.023  # Most are pretty round.
    g2 = np.ones_like(x) * 0.012
    flux = np.exp(rng.normal(size=nstars))
    print('flux range = ', np.min(flux), np.max(flux), np.median(flux),
          np.mean(flux))

    # Make a few intentionally wrong.
    g1[35] = 0.29
    g1[188] = -0.15
    sigma[239] = 0.2
    g2[347] = -0.15
    sigma[551] = 1.3
    g2[809] = 0.05
    g1[922] = -0.03

    # Draw a Gaussian PSF at each location on the image.
    for i in range(nstars):
        psf = galsim.Gaussian(sigma=sigma[i]).shear(g1=g1[i], g2=g2[i])
        stamp = psf.drawImage(scale=0.26, center=galsim.PositionD(x[i], y[i]))
        b = stamp.bounds & image.bounds
        image[b] += stamp[b]

    noise = 0.02
    image.addNoise(
        galsim.GaussianNoise(rng=galsim.BaseDeviate(1234), sigma=noise))

    image_file = os.path.join('output', 'test_chisq_im.fits')
    image.write(image_file)

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

    # Read the catalog in as stars.
    config = {
        'image_file_name': image_file,
        'cat_file_name': cat_file,
        'noise': noise**2,  # Variance here is sigma^2
        'stamp_size': 15,
        'use_partial': True,
    }
    input = piff.InputFiles(config, logger=logger)
    stars = input.makeStars()

    # Skip the solve step.  Just give it the right answer and see what it finds for outliers
    model = piff.Gaussian()
    interp = piff.Mean()
    interp.mean = np.array([0.4, 0.023, 0.012])
    psf = piff.SimplePSF(model, interp)
    stars = psf.interpolateStarList(stars)
    stars = [psf.model.reflux(s, logger=logger) for s in stars]

    outliers1 = piff.ChisqOutliers(nsigma=5)
    stars1, nremoved1 = outliers1.removeOutliers(stars, logger=logger)
    print('nremoved1 = ', nremoved1)
    assert len(stars1) == len(stars) - nremoved1

    # This is what nsigma=5 means in terms of probability
    outliers2 = piff.ChisqOutliers(prob=5.733e-7)
    stars2, nremoved2 = outliers2.removeOutliers(stars, logger=logger)
    print('nremoved2 = ', nremoved2)
    assert len(stars2) == len(stars) - nremoved2
    assert nremoved1 == nremoved2

    # The following is nearly equivalent for this particular data set.
    # For dof=222 (what most of these have, this probability converts to
    # thresh = 455.40143379
    # or ndof = 2.0513578
    # But note that when using the above prop or nsigma, the code uses a tailored threshold
    # different for each star's particular dof, which varies (since some are off the edge).
    outliers3 = piff.ChisqOutliers(thresh=455.401)
    stars3, nremoved3 = outliers3.removeOutliers(stars, logger=logger)
    print('nremoved3 = ', nremoved3)
    assert len(stars3) == len(stars) - nremoved3

    outliers4 = piff.ChisqOutliers(ndof=2.05136)
    stars4, nremoved4 = outliers4.removeOutliers(stars, logger=logger)
    print('nremoved4 = ', nremoved4)
    assert len(stars4) == len(stars) - nremoved4
    assert nremoved3 == nremoved4

    # Regression tests.  If these change, make sure we understand why.
    assert nremoved1 == nremoved2 == 58
    assert nremoved3 == nremoved4 == 16  # Much less, since edge objects aren't being removed
    # nearly as often as when they have a custom thresh.

    # Can't provide multiple thresh specifications
    np.testing.assert_raises(TypeError,
                             piff.ChisqOutliers,
                             nsigma=5,
                             prob=1.e-3)
    np.testing.assert_raises(TypeError,
                             piff.ChisqOutliers,
                             nsigma=5,
                             thresh=100)
    np.testing.assert_raises(TypeError, piff.ChisqOutliers, nsigma=5, ndof=3)
    np.testing.assert_raises(TypeError,
                             piff.ChisqOutliers,
                             prob=1.e-3,
                             thresh=100)
    np.testing.assert_raises(TypeError, piff.ChisqOutliers, prob=1.e-3, ndof=3)
    np.testing.assert_raises(TypeError, piff.ChisqOutliers, thresh=100, ndof=3)

    # Need to specifiy it somehow.
    np.testing.assert_raises(TypeError, piff.ChisqOutliers)
Пример #13
0
def test_load_images():
    """Test the load_images function
    """
    if __name__ == '__main__':
        logger = piff.config.setup_logger(verbose=2)
    else:
        logger = piff.config.setup_logger(log_file='output/test_load_image2.log')

    # Same setup as test_single_image, but without flags
    image = galsim.Image(2048, 2048, scale=0.26)
    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 ]
    sigma = 1.3
    g1 = 0.23
    g2 = -0.17
    psf = galsim.Gaussian(sigma=sigma).shear(g1=g1, g2=g2)
    for x,y in zip(x_list, y_list):
        bounds = galsim.BoundsI(int(x-31), int(x+32), int(y-31), int(y+32))
        psf.drawImage(image[bounds], center=galsim.PositionD(x,y), method='no_pixel')
    image.addNoise(galsim.GaussianNoise(rng=galsim.BaseDeviate(1234), sigma=1e-6))
    sky = 10.
    image += sky
    image_file = os.path.join('output','test_load_images_im.fits')
    image.write(image_file)

    dtype = [ ('x','f8'), ('y','f8') ]
    data = np.empty(len(x_list), dtype=dtype)
    data['x'] = x_list
    data['y'] = y_list
    cat_file = os.path.join('output','test_load_images_cat.fits')
    fitsio.write(cat_file, data, clobber=True)

    # Make star data
    config = { 'image_file_name' : image_file,
               'cat_file_name': cat_file,
               'sky': 10
             }
    orig_stars, wcs, pointing = piff.Input.process(config, logger)

    # Fit these with a simple Mean, Gaussian
    model = piff.Gaussian()
    interp = piff.Mean()
    psf = piff.SimplePSF(model, interp)
    psf.fit(orig_stars, wcs, pointing, logger=logger)
    psf_file = os.path.join('output','test_load_images_psf.fits')
    psf.write(psf_file, logger)

    # Read this file back in.  It has the star data, but the images are blank.
    psf2 = piff.read(psf_file, logger)
    assert len(psf2.stars) == 10
    for star in psf2.stars:
        np.testing.assert_array_equal(star.image.array, 0.)

    # First the old API:
    with CaptureLog() as cl:
        loaded_stars = piff.Star.load_images(psf2.stars, image_file, logger=cl.logger)
    assert "WARNING: The Star.load_images function is deprecated." in cl.output
    for star, orig in zip(loaded_stars, psf.stars):
        np.testing.assert_array_equal(star.image.array, orig.image.array)

    # Can optionally supply a different sky to subtract
    # (This is not allowed by the new API, but it probably doesn't make much sense.)
    loaded_stars = piff.Star.load_images(psf2.stars, image_file, sky=2*sky)
    for star, orig in zip(loaded_stars, psf.stars):
        np.testing.assert_array_equal(star.image.array, orig.image.array - sky)

    # Now the new API:
    psf2 = piff.read(psf_file, logger)  # Reset stars to not have images in them.
    loaded_stars = piff.InputFiles(config).load_images(psf2.stars)
    for star, orig in zip(loaded_stars, psf.stars):
        np.testing.assert_array_equal(star.image.array, orig.image.array)
Пример #14
0
def test_basic():
    """Test the (usual) basic kind of input field without too many bells and whistles.
    """
    if __name__ == '__main__':
        logger = piff.config.setup_logger(verbose=2)
    else:
        logger = piff.config.setup_logger(
            log_file=os.path.join('output', 'test_input_basic.log'))

    dir = 'input'
    image_file = 'test_input_image_00.fits'
    cat_file = 'test_input_cat_00.fits'

    # Simple with one image, cat
    config = {
        'dir': dir,
        'image_file_name': image_file,
        'cat_file_name': cat_file
    }
    input = piff.InputFiles(config, logger=logger)
    assert len(input.image_pos) == 1
    assert len(input.image_pos[0]) == 100

    # Can omit the dir and just inlcude it in the file names
    config = {
        'image_file_name': os.path.join(dir, image_file),
        'cat_file_name': os.path.join(dir, cat_file)
    }
    input = piff.InputFiles(config, logger=logger)
    assert len(input.image_pos) == 1
    assert len(input.image_pos[0]) == 100

    # 3 images in a list
    image_files = ['test_input_image_%02d.fits' % k for k in range(3)]
    cat_files = ['test_input_cat_%02d.fits' % k for k in range(3)]
    config = {
        'dir': dir,
        'image_file_name': image_files,
        'cat_file_name': cat_files
    }
    input = piff.InputFiles(config, logger=logger)
    assert len(input.image_pos) == 3
    np.testing.assert_array_equal([len(p) for p in input.image_pos], 100)

    # Again without dir.
    image_files = ['input/test_input_image_%02d.fits' % k for k in range(3)]
    cat_files = ['input/test_input_cat_%02d.fits' % k for k in range(3)]
    config = {'image_file_name': image_files, 'cat_file_name': cat_files}
    input = piff.InputFiles(config, logger=logger)
    assert len(input.image_pos) == 3
    np.testing.assert_array_equal([len(p) for p in input.image_pos], 100)

    # 3 images using glob
    image_files = 'test_input_image_*.fits'
    cat_files = 'test_input_cat_*.fits'
    config = {
        'dir': dir,
        'image_file_name': image_files,
        'cat_file_name': cat_files
    }
    input = piff.InputFiles(config, logger=logger)
    assert len(input.image_pos) == 3
    np.testing.assert_array_equal([len(p) for p in input.image_pos], 100)

    # Can limit the number of stars
    config['nstars'] = 37
    input = piff.InputFiles(config, logger=logger)
    assert len(input.image_pos) == 3
    np.testing.assert_array_equal([len(p) for p in input.image_pos], 37)
Пример #15
0
def test_stars():
    """Test the input.makeStars function
    """
    if __name__ == '__main__':
        logger = piff.config.setup_logger(verbose=2)
    else:
        logger = piff.config.setup_logger(
            log_file=os.path.join('output', 'test_input_stars.log'))

    dir = 'input'
    image_file = 'test_input_image_00.fits'
    cat_file = 'test_input_cat_00.fits'

    # Turn off two defaults for now (max_snr=100 and use_partial=False)
    config = {
        'dir': dir,
        'image_file_name': image_file,
        'cat_file_name': cat_file,
        'weight_hdu': 1,
        'sky_col': 'sky',
        'gain_col': 'gain',
        'max_snr': 0,
        'use_partial': True,
    }
    input = piff.InputFiles(config, logger=logger)
    stars = input.makeStars(logger=logger)
    assert len(stars) == 100
    chipnum_list = [star['chipnum'] for star in stars]
    gain_list = [star['gain'] for star in stars]
    snr_list = [star['snr'] for star in stars]
    snr_list2 = [
        input.calculateSNR(star.data.image, star.data.orig_weight)
        for star in stars
    ]
    print('snr = ', np.min(snr_list), np.max(snr_list))
    np.testing.assert_array_equal(chipnum_list, 0)
    np.testing.assert_array_equal(gain_list, gain_list[0])
    np.testing.assert_almost_equal(snr_list, snr_list2, decimal=5)
    print('min_snr = ', np.min(snr_list))
    print('max_snr = ', np.max(snr_list))
    assert np.min(snr_list) < 40.
    assert np.max(snr_list) > 600.

    # max_snr increases the noise to achieve a maximum snr
    config['max_snr'] = 120
    input = piff.InputFiles(config, logger=logger)
    stars = input.makeStars(logger=logger)
    assert len(stars) == 100
    snr_list = [star['snr'] for star in stars]
    snr_list2 = [
        input.calculateSNR(star.data.image, star.data.orig_weight)
        for star in stars
    ]
    print('snr = ', np.min(snr_list), np.max(snr_list))
    np.testing.assert_almost_equal(snr_list, snr_list2, decimal=5)
    assert np.min(snr_list) < 40.
    assert np.max(snr_list) == 120.

    # The default is max_snr == 100
    del config['max_snr']
    input = piff.InputFiles(config, logger=logger)
    stars = input.makeStars(logger=logger)
    assert len(stars) == 100
    snr_list = np.array([star['snr'] for star in stars])
    snr_list2 = [
        input.calculateSNR(star.data.image, star.data.orig_weight)
        for star in stars
    ]
    print('snr = ', np.min(snr_list), np.max(snr_list))
    np.testing.assert_almost_equal(snr_list, snr_list2, decimal=5)
    assert np.min(snr_list) < 40.
    assert np.max(snr_list) == 100.

    # min_snr removes stars with a snr < min_snr
    config['min_snr'] = 50
    input = piff.InputFiles(config, logger=logger)
    stars = input.makeStars(logger=logger)
    print('len should be ', len(snr_list[snr_list >= 50]))
    print('actual len is ', len(stars))
    assert len(stars) == len(snr_list[snr_list >= 50])
    assert len(stars) == 96  # hard-coded for this case, just to make sure
    snr_list = np.array([star['snr'] for star in stars])
    snr_list2 = [
        input.calculateSNR(star.data.image, star.data.orig_weight)
        for star in stars
    ]
    print('snr = ', np.min(snr_list), np.max(snr_list))
    np.testing.assert_almost_equal(snr_list, snr_list2, decimal=5)
    assert np.min(snr_list) >= 50.
    assert np.max(snr_list) == 100.

    # use_partial=False will skip any stars that are partially off the edge of the image
    config['use_partial'] = False
    input = piff.InputFiles(config, logger=logger)
    stars = input.makeStars(logger=logger)
    print('new len is ', len(stars))
    assert len(stars) == 94  # skipped 2 additional stars

    # use_partial=False is the default
    del config['use_partial']
    input = piff.InputFiles(config, logger=logger)
    stars = input.makeStars(logger=logger)
    assert len(stars) == 94  # skipped 2 additional stars

    # alt_x and alt_y also include some object completely off the image, which are always skipped.
    # (Don't do the min_snr anymore, since most of these stamps don't actually have any signal.)
    config['x_col'] = 'alt_x'
    config['y_col'] = 'alt_y'
    del config['min_snr']
    input = piff.InputFiles(config, logger=logger)
    stars = input.makeStars(logger=logger)
    print('new len is ', len(stars))
    assert len(stars) == 37

    # Also skip objects which are all weight=0
    config['weight_hdu'] = 3
    input = piff.InputFiles(config, logger=logger)
    stars = input.makeStars(logger=logger)
    print('new len is ', len(stars))
    assert len(stars) == 0

    # But not ones that are only partially weight=0
    config['weight_hdu'] = 8
    input = piff.InputFiles(config, logger=logger)
    stars = input.makeStars(logger=logger)
    print('new len is ', len(stars))
    assert len(stars) == 37

    # Check that negative snr flux yields 0, not an error (from sqrt(neg))
    # Negative flux is actually ok, since it gets squared, but if an image has negative weights
    # (which would be weird of course), then it could get to negative flux = wI^2.
    star0 = stars[0]
    star0.data.orig_weight *= -1.
    snr0 = input.calculateSNR(star0.data.image, star0.data.orig_weight)
    assert snr0 == 0.