Ejemplo n.º 1
0
def test_yaml():
    # 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': {
            'images': 'y1_test/DECam_00241238_01.fits.fz',
            'cats':
            'y1_test/DECam_00241238_01_psfcat_tb_maxmag_17.0_magcut_3.0_findstars.fits',

            # 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': 31,
        },
        'psf': {
            'model': {
                'type': 'GSObjectModel',
                'fastfit': True,
                'gsobj': 'galsim.Gaussian(sigma=1.0)'
            },
            'interp': {
                'type': 'GPInterp',
                'keys': ['u', 'v'],
                'kernel': 'RBF(200.0)',
                'optimize': False,
            }
        },
        'output': {
            'file_name': psf_file
        },
    }

    # using piffify executable
    config['verbose'] = 0
    with open('gp.yaml', 'w') as f:
        f.write(yaml.dump(config, default_flow_style=False))
    piffify_exe = get_script_name('piffify')
    p = subprocess.Popen([piffify_exe, 'gp.yaml'])
    p.communicate()
    piff.read(psf_file)
Ejemplo n.º 2
0
def test_shapestats_config():
    """Test running stats through a config file.
    """
    if __name__ == '__main__':
        logger = piff.config.setup_logger(verbose=2)
    else:
        logger = piff.config.setup_logger(log_file='output/test_shapestats_config.log')

    image_file = os.path.join('output','test_stats_image.fits')
    cat_file = os.path.join('output','test_stats_cat.fits')
    psf_file = os.path.join('output','test_shapestats.fits')
    shape_file = os.path.join('output','test_shapestats.pdf')
    config = {
        'input' : {
            'image_file_name' : image_file,
            'cat_file_name' : cat_file,
            'stamp_size' : 48
        },
        'psf' : {
            'model' : { 'type' : 'Gaussian',
                        'fastfit': True,
                        'include_pixel': False },
            'interp' : { 'type' : 'Mean' },
        },
        'output' : {
            'file_name' : psf_file,
            'stats' : [
                {
                    'type': 'ShapeHistograms',
                    'file_name': shape_file
                },
            ]
        },
    }
    piff.piffify(config, logger)
    assert os.path.isfile(shape_file)

    # repeat with plotify function
    os.remove(shape_file)
    piff.plotify(config, logger)
    assert os.path.isfile(shape_file)

    # Test ShapeHistogramStats directly
    psf = piff.read(psf_file)
    shapeStats = piff.ShapeHistogramsStats()
    orig_stars, wcs, pointing = piff.Input.process(config['input'], logger)
    shapeStats.compute(psf, orig_stars)

    # test their characteristics
    sigma = 1.3  # (copied from setup())
    g1 = 0.23
    g2 = -0.17
    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)
Ejemplo n.º 3
0
def test_pickle():
    """Test the reading a file written with python 2 pickling is readable with python 2 or 3.
    """
    if __name__ == '__main__':
        logger = piff.config.setup_logger(verbose=2)
    else:
        logger = piff.config.setup_logger(log_file='output/test_pickle.log')

    # First, this is the output file written by the above test_single function on python 2.
    # Shoudl be trivially readable by python 2, but make sure it is also readable by python 3.
    psf = piff.read('input/test_single_py27.piff', logger=logger)

    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)
            )

    data1 = fitsio.read('input/test_single_cat1.fits')
    data2 = fitsio.read('input/test_single_cat2.fits')
    field_center = galsim.CelestialCoord(0 * galsim.degrees, -25 * galsim.degrees)

    for chipnum, data, wcs in [(1,data1,wcs1), (2,data2,wcs2)]:
        for k in range(len(data)):
            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)


    # This is a DES Y3 PSF file that Matt Becker reported hadn't been readable with python 3.
    # The problem was it had been written with python 2's pickle, which isn't directly
    # compatible with python 3.  The code has been fixed to make it readable.  This unit
    # test is just to ensure that it remains so.
    # However, it only works if pixmappy is installed, so if not, just bail out.
    try:
        import pixmappy
    except ImportError:
        return
    fname = os.path.join('input', 'D00240560_r_c01_r2362p01_piff.fits')
    psf = piff.PSF.read(fname, logger=logger)
    image = psf.draw(x=103.3, y=592.0)
Ejemplo n.º 4
0
def test_yaml():
    # Take DES test image, and test doing a psf run with kNN interpolator
    # Now test running it via the config parser
    psf_file = os.path.join('output','knn_psf.fits')
    config = {
        'input' : {
            'images' : 'y1_test/DECam_00241238_01.fits.fz',
            'cats' : 'y1_test/DECam_00241238_01_psfcat_tb_maxmag_17.0_magcut_3.0_findstars.fits',
            # 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': 31,
        },
        'psf' : {
            'model' : { 'type': 'GSObjectModel',
                        'fastfit': True,
                        'gsobj': 'galsim.Gaussian(sigma=1.0)' },
            'interp' : { 'type': 'kNNInterp',
                         'keys': ['u', 'v'],
                         'n_neighbors': 115,}
        },
        'output' : { 'file_name' : psf_file },
    }

    # using piffify executable
    config['verbose'] = 0
    with open('knn.yaml','w') as f:
        f.write(yaml.dump(config, default_flow_style=False))
    piffify_exe = get_script_name('piffify')
    p = subprocess.Popen( [piffify_exe, 'knn.yaml'] )
    p.communicate()
    psf = piff.read(psf_file)

    # by using n_neighbors = 115, when there are only 117 stars in the catalog, we should expect
    # that the standard deviation of the interpolated parameters should be small, since almost the
    # same set of stars are being averaged in every case.
    np.testing.assert_array_less(
            np.std([s.fit.params for s in psf.stars], axis=0),
            0.01*np.mean([s.fit.params for s in psf.stars], axis=0),
            err_msg="Interpolated parameters show too much variation.")
Ejemplo n.º 5
0
def do_residuals(f, verbose=True, number_plot=0):
    c = f.replace('.piff', '.yaml')
    piff_name = f.split('/')[-1].split('.piff')[0]
    label = 'fitted'
    config = piff.read_config(c)
    if verbose:
        print('psf')
    psf = piff.read(f)

    # initialize output
    directory = '/'.join(c.split('/')[:-1])
    config['output']['dir'] = directory
    output = piff.Output.process(config['output'])

    # select nstars based on stars piece of config
    stat = output.stats_list[3]  # TODO: this bit is hardcoded
    if number_plot != 0:
        stat.number_plot = number_plot
    stat.indices = np.random.choice(len(psf.stars),
                                    stat.number_plot,
                                    replace=False)

    # pass params into output
    stat.stars = []
    for i, index in enumerate(stat.indices):
        star = psf.stars[index]
        stat.stars.append(star)
    # load their images
    if verbose:
        print('loading star images')
    stat.stars = load_star_images(stat.stars, config)

    if verbose:
        print('loading model')
    stat.models = []
    for star in stat.stars:

        # draw model star
        params = star.fit.params
        prof = psf.getProfile(params)
        model = psf.drawProfile(star, prof, params, copy_image=True)
        stat.models.append(model)

    if verbose:
        print('writing')

    file_name = '{0}/{1}_{2}_{3}'.format(directory, label, piff_name,
                                         os.path.split(stat.file_name)[1])
    stat.write(file_name=file_name)
    return file_name, stat.stars, stat.models
Ejemplo n.º 6
0
def test_pickle():
    """Test the reading a file written with python 2 pickling is readable with python 2 or 3.
    """
    if __name__ == '__main__':
        logger = piff.config.setup_logger(verbose=2)
    else:
        logger = piff.config.setup_logger(log_file='output/test_pickle.log')

    # First, this is the output file written by the above test_single function on python 2.
    # Shoudl be trivially readable by python 2, but make sure it is also readable by python 3.
    psf = piff.read('input/test_single_py27.piff', logger=logger)

    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))

    data1 = fitsio.read('input/test_single_cat1.fits')
    data2 = fitsio.read('input/test_single_cat2.fits')
    field_center = galsim.CelestialCoord(0 * galsim.degrees,
                                         -25 * galsim.degrees)

    for chipnum, data, wcs in [(1, data1, wcs1), (2, data2, wcs2)]:
        for k in range(len(data)):
            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)
Ejemplo n.º 7
0
def fit_psf(directory, config_file_name, print_log, meanify_file_path='', fit_interp_only=False):
    do_meanify = meanify_file_path != ''
    piff_name = config_file_name
    # load config file
    config = piff.read_config('{0}/{1}.yaml'.format(directory, config_file_name))
    is_optatmo = 'OptAtmo' in config['psf']['type']

    # do galsim modules
    if 'modules' in config:
        galsim.config.ImportModules(config)

    # create logger
    verbose = config.get('verbose', 3)
    if print_log:
        logger = piff.setup_logger(verbose=verbose)
    else:
        if do_meanify:
            logger = piff.setup_logger(verbose=verbose, log_file='{0}/{1}_fit_psf_meanify_logger.log'.format(directory, config_file_name))
        else:
            logger = piff.setup_logger(verbose=verbose, log_file='{0}/{1}_fit_psf_logger.log'.format(directory, config_file_name))

    if (do_meanify or fit_interp_only) and is_optatmo:
        # load base optics psf
        out_path = '{0}/{1}.piff'.format(directory, piff_name)
        logger.info('Loading saved PSF at {0}'.format(out_path))
        psf = piff.read(out_path)

        # load images for train stars
        logger.info('loading train stars')
        psf.stars = load_star_images(psf.stars, config, logger=logger)

        # load test stars and their images
        logger.info('loading test stars')
        test_stars = read_stars(out_path, logger=logger)
        test_stars = load_star_images(test_stars, config, logger=logger)

        # make output
        config['output']['dir'] = directory
        output = piff.Output.process(config['output'], logger=logger)

    elif (do_meanify or fit_interp_only) and not is_optatmo:
        # welp, not much to do here. shouldn't even have gotten here! :(
        logger.warning('Somehow passed the meanify to a non-optatmo argument. This should not happen.')
        return

    else:
        # load stars
        stars, wcs, pointing = piff.Input.process(config['input'], logger=logger)

        # separate stars
        # set seed
        np.random.seed(12345)
        test_fraction = config.get('test_fraction', 0.2)
        test_indx = np.random.choice(len(stars), int(test_fraction * len(stars)), replace=False)
        test_stars = []
        train_stars = []
        # kludgey:
        for star_i, star in enumerate(stars):
            if star_i in test_indx:
                test_stars.append(star)
            else:
                train_stars.append(star)

        # initialize psf
        psf = piff.PSF.process(config['psf'], logger=logger)

        # piffify
        logger.info('Fitting PSF')
        psf.fit(train_stars, wcs, pointing, logger=logger)
        logger.info('Fitted PSF!')

        # fit atmosphere parameters
        if is_optatmo:
            logger.info('Fitting PSF atmosphere parameters')
            logger.info('getting param info for {0} stars'.format(len(psf.stars)))
            params = psf.getParamsList(psf.stars)
            psf._enable_atmosphere = False
            new_stars = []
            for star_i, star in zip(range(len(psf.stars)), psf.stars):
                if star_i % 100 == 0:
                    logger.info('Fitting star {0} of {1}'.format(star_i, len(psf.stars)))
                try:
                    model_fitted_star, results = psf.fit_model(star, params=params[star_i], vary_shape=True, vary_optics=False, logger=logger)
                    new_stars.append(model_fitted_star)
                except (KeyboardInterrupt, SystemExit):
                    raise
                except Exception as e:
                    logger.warning('{0}'.format(str(e)))
                    logger.warning('Warning! Failed to fit atmosphere model for star {0}. Ignoring star in atmosphere fit'.format(star_i))
            psf.stars = new_stars

        # save psf
        # make sure the output is in the right directory
        config['output']['dir'] = directory
        output = piff.Output.process(config['output'], logger=logger)
        logger.info('Saving PSF')
        # save fitted PSF
        psf.write(output.file_name, logger=logger)

        # and write test stars
        write_stars(test_stars, output.file_name, logger=logger)

    shape_keys = ['e0', 'e1', 'e2', 'delta1', 'delta2', 'zeta1', 'zeta2']
    shape_plot_keys = []
    for key in shape_keys:
        shape_plot_keys.append(['data_' + key, 'model_' + key, 'd' + key])
    if is_optatmo:
        interps = config.pop('interps')
        interp_keys = interps.keys()
        if not (do_meanify or fit_interp_only):
            # do noatmo only when we do not have meanify
            interp_keys = ['noatmo'] + interp_keys
        train_stars = psf.stars
        for interp_key in interp_keys:
            piff_name = '{0}_{1}'.format(config_file_name, interp_key)
            logger.info('Fitting optatmo interpolate for {0}'.format(interp_key))
            if interp_key == 'noatmo':
                psf.atmo_interp = None
                psf._enable_atmosphere = False
                passed_test_stars = test_stars
            else:
                # fit interps
                config_interp = interps[interp_key]

                if do_meanify:
                    config_interp['average_fits'] = meanify_file_path
                    piff_name += '_meanified'

                # extract chicut, madcut, snrcut from interp config, if provided
                interp_chicut = config_interp.pop('chicut', 0)
                interp_madcut = config_interp.pop('madcut', 0)
                interp_snrcut = config_interp.pop('snrcut', 0)

                # test stars undergo snr cut, but no other cuts
                used_interp_stars, passed_test_stars = fit_interp(train_stars, test_stars, config_interp, psf, interp_chicut, interp_madcut, interp_snrcut, logger)
                psf.stars = used_interp_stars

            # save
            out_path = '{0}/{1}.piff'.format(directory, piff_name)
            psf.write(out_path, logger=logger)
            write_stars(passed_test_stars, out_path, logger=logger)

            # evaluate
            logger.info('Evaluating {0}'.format(piff_name))

            for stars, label in zip([psf.stars, passed_test_stars], ['train', 'test']):
                # get shapes
                logger.debug('drawing {0} model stars'.format(label))
                model_stars = psf.drawStarList(stars)
                shapes = measure_star_shape(stars, model_stars, logger=logger)

                param_keys = ['atmo_size', 'atmo_g1', 'atmo_g2']
                if psf.atmosphere_model == 'vonkarman':
                    param_keys += ['atmo_L0']
                param_keys += ['optics_size', 'optics_g1', 'optics_g2'] + ['z{0:02d}'.format(zi) for zi in range(4, 45)]
                if label == 'train':
                    # if train, plot fitted params
                    logger.info('Extracting training fit parameters')
                    params = np.array([star.fit.params for star in stars])
                    params_var = np.array([star.fit.params_var for star in stars])
                    for i in range(params.shape[1]):
                        shapes['{0}_fit'.format(param_keys[i])] = params[:, i]
                        shapes['{0}_var'.format(param_keys[i])] = params_var[:, i]
                    logger.info('Getting training fit parameters')
                    params = psf.getParamsList(stars)
                    for i in range(params.shape[1]):
                        shapes[param_keys[i]] = params[:, i]

                elif label == 'test':
                    # if test, plot predicted params
                    logger.info('Getting test parameters')
                    params = psf.getParamsList(stars)
                    for i in range(params.shape[1]):
                        shapes[param_keys[i]] = params[:, i]

                # save shapes
                shapes.to_hdf('{0}/shapes_{1}_{2}.h5'.format(directory, label, piff_name), 'data', mode='w')

                # plot shapes
                fig, axs = plot_2dhist_shapes(shapes, shape_plot_keys, diff_mode=True)
                # save
                fig.savefig('{0}/plot_2dhist_shapes_{1}_{2}.pdf'.format(directory, label, piff_name))

                # plot params
                plot_keys = []
                plot_keys_i = []
                for i in range(params.shape[1]):
                    plot_keys_i.append(param_keys[i])
                    if len(plot_keys_i) == 3:
                        plot_keys.append(plot_keys_i)
                        plot_keys_i = []
                if len(plot_keys_i) > 0:
                    plot_keys_i += [plot_keys_i[0]] * (3 - len(plot_keys_i))
                    plot_keys.append(plot_keys_i)
                fig, axs = plot_2dhist_shapes(shapes, plot_keys, diff_mode=False)
                # save
                fig.savefig('{0}/plot_2dhist_params_{1}_{2}.pdf'.format(directory, label, piff_name))
                # and repeat for the fit params
                if label == 'train':
                    fig, axs = plot_2dhist_shapes(shapes, [[key + '_fit' for key in kp] for kp in plot_keys], diff_mode=False)
                    # save
                    fig.savefig('{0}/plot_2dhist_fit_params_{1}_{2}.pdf'.format(directory, label, piff_name))

                # if test, fit the flux and centering
                if label == 'test':
                    logger.info('Fitting the centers and fluxes of {0} test stars'.format(len(stars)))
                    # fit stars for stats
                    new_stars = []
                    for star, param in zip(stars, params):
                        try:
                            new_star, res = psf.fit_model(star, param, vary_shape=False, vary_optics=False, logger=logger)
                            new_stars.append(new_star) 
                        except (KeyboardInterrupt, SystemExit):
                            raise
                        except Exception as e:
                            logger.warning('{0}'.format(str(e)))
                            logger.warning('Warning! Failed to fit atmosphere model for star {0}. Ignoring star in atmosphere fit'.format(star))
                    stars = new_stars

                # do the output processing
                logger.info('Writing Stats Output of {0} stars'.format(label))
                for stat in output.stats_list:
                    stat.compute(psf, stars, logger=logger)
                    file_name = '{0}/{1}_{2}_{3}'.format(directory, label, piff_name, os.path.split(stat.file_name)[1])
                    stat.write(file_name=file_name, logger=logger)

    else:
        logger.info('Evaluating {0}'.format(piff_name))

        for stars, label in zip([psf.stars, test_stars], ['train', 'test']):
            # get shapes
            model_stars = psf.drawStarList(stars)
            shapes = measure_star_shape(stars, model_stars, logger=logger)
            # save shapes
            shapes.to_hdf('{0}/shapes_{1}_{2}.h5'.format(directory, label, piff_name), 'data', mode='w')

            # plot shapes
            fig, axs = plot_2dhist_shapes(shapes, shape_plot_keys, diff_mode=True)
            # save
            fig.savefig('{0}/plot_2dhist_shapes_{1}_{2}.pdf'.format(directory, label, piff_name))

            logger.info('Writing Stats Output of {0} stars'.format(label))
            for stat in output.stats_list:
                stat.compute(psf, stars, logger=logger)
                file_name = '{0}/{1}_{2}_{3}'.format(directory, label, piff_name, os.path.split(stat.file_name)[1])
                stat.write(file_name=file_name, logger=logger)
Ejemplo n.º 8
0
def test_des_image():
    """Test the whole process with a DES CCD.
    """
    import os
    import fitsio

    image_file = 'input/DECam_00241238_01.fits.fz'
    cat_file = 'input/DECam_00241238_01_psfcat_tb_maxmag_17.0_magcut_3.0_findstars.fits'
    orig_image = galsim.fits.read(image_file)
    psf_file = os.path.join('output','pixel_des_psf.fits')

    if __name__ == '__main__':
        # These match what Gary used in fit_des.py
        nstars = None
        scale = 0.15
        size = 31
        order = 2
        nsigma = 4
    else:
        # These are faster and good enough for the unit tests.
        nstars = 25
        scale = 0.26
        size = 15
        order = 1
        nsigma = 1.  # This needs to be low to make sure we do test outlier rejection here.
    stamp_size = 25

    # The configuration dict with the right input fields for the file we're using.
    start_sigma = 1.0/2.355  # TODO: Need to make this automatic somehow.
    config = {
        'input' : {
            'nstars': nstars,
            'image_file_name' : image_file,
            'image_hdu' : 1,
            'weight_hdu' : 3,
            'badpix_hdu' : 2,
            'cat_file_name' : cat_file,
            'cat_hdu' : 2,
            'x_col' : 'XWIN_IMAGE',
            'y_col' : 'YWIN_IMAGE',
            'sky_col' : 'BACKGROUND',
            'stamp_size' : stamp_size,
            'ra' : 'TELRA',
            'dec' : 'TELDEC',
            'gain' : 'GAINA',
            # Test explicitly specifying the wcs (although it is the same here as what is in the
            # image anyway).
            'wcs' : {
                'type': 'Fits',
                'file_name': image_file
            }
        },
        'output' : {
            'file_name' : psf_file,
        },
        'psf' : {
            'model' : {
                'type' : 'PixelGrid',
                'scale' : scale,
                'size' : size,
                'interp' : 'Lanczos(5)',
                'start_sigma' : start_sigma,
            },
            'interp' : {
                'type' : 'BasisPolynomial',
                'order' : order,
            },
            'outliers' : {
                'type' : 'Chisq',
                'nsigma' : nsigma,
                'max_remove' : 3
            }
        },
    }
    if __name__ == '__main__':
        config['verbose'] = 2
    else:
        config['verbose'] = 0

    # 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 __name__ == '__main__':
        # Start by doing things manually:
        logger = piff.config.setup_logger(2)

        # Largely copied from Gary's fit_des.py, but using the Piff input_handler to
        # read the input files.
        stars, wcs, pointing = piff.Input.process(config['input'], logger=logger)
        if nstars is not None:
            stars = stars[:nstars]

        # Make model, force PSF centering
        model = piff.PixelGrid(scale=scale, size=size, interp=piff.Lanczos(3),
                               force_model_center=True, start_sigma=start_sigma,
                               logger=logger)

        # Interpolator will be zero-order polynomial.
        # Find u, v ranges
        interp = piff.BasisPolynomial(order=order, logger=logger)

        # Make a psf
        psf = piff.SimplePSF(model, interp)
        psf.fit(stars, wcs, pointing, logger=logger)

        # The difference between the images of the fitted stars and the originals should be
        # consistent with noise.  Keep track of how many don't meet that goal.
        n_bad = 0  # chisq/dof > 2
        n_marginal = 0  # chisq/dof > 1.1
        n_good = 0 # chisq/dof <= 1.1
        # Note: The 2 and 1.1 values here are very arbitrary!

        for s in psf.stars:
            fitted = psf.drawStar(s)
            orig_stamp = orig_image[fitted.image.bounds] - s['sky']
            fit_stamp = fitted.image

            x0 = int(s['x']+0.5)
            y0 = int(s['y']+0.5)
            b = galsim.BoundsI(x0-3,x0+3,y0-3,y0+3)
            #print('orig center = ',orig_stamp[b].array)
            #print('flux = ',orig_stamp.array.sum())
            #print('fit center = ',fit_stamp[b].array)
            #print('flux = ',fit_stamp.array.sum())
            flux = fitted.fit.flux
            #print('max diff/flux = ',np.max(np.abs(orig_stamp.array-fit_stamp.array))/flux)
            #np.testing.assert_almost_equal(fit_stamp.array/flux, orig_stamp.array/flux, decimal=2)
            weight = s.weight  # These should be 1/var_pix
            resid = fit_stamp - orig_stamp
            chisq = np.sum(resid.array**2 * weight.array)
            print('chisq = ',chisq)
            print('cf. star.chisq, dof = ',s.fit.chisq, s.fit.dof)
            assert abs(chisq - s.fit.chisq) < 1.e-3 * chisq
            if chisq > 2. * s.fit.dof:
                n_bad += 1
            elif chisq > 1.1 * s.fit.dof:
                n_marginal += 1
            else:
                n_good += 1

            # Check the convenience function that an end user would typically use
            offset = s.center_to_offset(s.fit.center)
            image = psf.draw(x=s['x'], y=s['y'], stamp_size=stamp_size,
                             flux=s.fit.flux, offset=offset)
            np.testing.assert_almost_equal(image.array, fit_stamp.array, decimal=4)

        print('n_good, marginal, bad = ',n_good,n_marginal,n_bad)
        # The real counts are 10 and 2.  So this says make sure any updates to the code don't make
        # things much worse.
        assert n_marginal <= 12
        assert n_bad <= 3

    # Use piffify function
    print('start piffify')
    piff.piffify(config)
    print('read stars')
    stars, wcs, pointing = piff.Input.process(config['input'])
    print('read psf')
    psf = piff.read(psf_file)
    stars = [psf.model.initialize(s) for s in stars]
    flux = stars[0].fit.flux
    offset = stars[0].center_to_offset(stars[0].fit.center)
    fit_stamp = psf.draw(x=stars[0]['x'], y=stars[0]['y'], stamp_size=stamp_size,
                         flux=flux, offset=offset)
    orig_stamp = orig_image[stars[0].image.bounds] - stars[0]['sky']
    # The first star happens to be a good one, so go ahead and test the arrays directly.
    np.testing.assert_almost_equal(fit_stamp.array/flux, orig_stamp.array/flux, decimal=2)

    # Test using the piffify executable
    with open('pixel_des.yaml','w') as f:
        f.write(yaml.dump(config, default_flow_style=False))
    if __name__ == '__main__':
        if os.path.exists(psf_file):
            os.remove(psf_file)
        piffify_exe = get_script_name('piffify')
        print('start piffify executable')
        p = subprocess.Popen( [piffify_exe, 'pixel_des.yaml'] )
        p.communicate()
        print('read stars')
        stars, wcs, pointing = piff.Input.process(config['input'])
        print('read psf')
        psf = piff.read(psf_file)
        stars = [psf.model.initialize(s) for s in stars]
        flux = stars[0].fit.flux
        offset = stars[0].center_to_offset(stars[0].fit.center)
        fit_stamp = psf.draw(x=stars[0]['x'], y=stars[0]['y'], stamp_size=stamp_size,
                             flux=flux, offset=offset)
        orig_stamp = orig_image[stars[0].image.bounds] - stars[0]['sky']
        np.testing.assert_almost_equal(fit_stamp.array/flux, orig_stamp.array/flux, decimal=2)
Ejemplo n.º 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')

    # Add sky level and noise
    sky_level = 1000
    noise_sigma = 0.1  # Not much noise to keep this an easy test.
    image += sky_level
    image.addNoise(galsim.GaussianNoise(sigma=noise_sigma))

    # Write out the image to a file
    image_file = os.path.join('output','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('output','pixel_moffat_cat.fits')
    fitsio.write(cat_file, data, clobber=True)
    print('wrote catalog')

    # Use InputFiles to read these back in
    config = { 'image_file_name': image_file,
               'cat_file_name': cat_file,
               'stamp_size': 32,
               'noise' : noise_sigma**2,
               'sky' : sky_level,
             }
    input = piff.InputFiles(config)
    assert input.image_file_name == [image_file]
    assert input.cat_file_name == [cat_file]

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

    # Check catalog
    assert len(input.image_pos) == 1
    assert len(input.image_pos[0]) == len(x_list)
    np.testing.assert_equal([pos.x for pos in input.image_pos[0]], x_list)
    np.testing.assert_equal([pos.y for pos in input.image_pos[0]], 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')

    if __name__ == '__main__':
        logger = piff.config.setup_logger(2)
        order = 2
    else:
        logger = None
        order = 1

    # 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.
    psf_file = os.path.join('output','pixel_psf.fits')
    if __name__ == '__main__':
        # Process the star data
        model = piff.PixelGrid(0.2, 16, start_sigma=0.9/2.355)
        interp = piff.BasisPolynomial(order=order)
        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('flux = ', test_im.array.sum(), 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/2, test_im.array/2, 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/2, test_im.array/2, decimal=3)

        # Round trip through a file
        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/2, test_im.array/2, 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/2., test_im.array/2., decimal=3)

    # Do the whole thing with the config parser
    config = {
        'input' : {
            'image_file_name' : image_file,
            'cat_file_name' : cat_file,
            'x_col' : 'x',
            'y_col' : 'y',
            'noise' : noise_sigma**2,
            'sky' : sky_level,
            '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' : order
            },
        },
    }
    if __name__ == '__main__':
        config['verbose'] = 2
    else:
        config['verbose'] = 0

    print("Running piffify function")
    piff.piffify(config)
    psf = piff.read(psf_file)
    test_star = psf.drawStar(target_star)
    print("Max abs diff = ",np.max(np.abs(test_star.image.array - test_im.array)))
    np.testing.assert_almost_equal(test_star.image.array/2., test_im.array/2., decimal=3)

    # Test using the piffify executable
    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/2., test_im.array/2., decimal=3)

    # 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_star.data.copy(), target_star.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]

    # check that drawing onto an image does not return a copy
    image = psf.draw(x=x0, y=y0)
    image_reference = psf.draw(x=x0, y=y0, image=image)
    image_reference.array[0,0] = 123456
    assert image.array[0,0] == image_reference.array[0,0]
Ejemplo n.º 10
0
def measure_psf_shapes(xlist, ylist, psf_file_name, file_name, use_piff=False):
    """Given x,y positions, a psf solution file, and the wcs, measure shapes and sizes
    of the PSF model.

    We use the HSM module from GalSim to do this.

    Returns e1, e2, size, flag.
    """
    print 'Read in PSFEx file: ',psf_file_name

    n_psf = len(xlist)
    e1_list = [ 999. ] * n_psf
    e2_list = [ 999. ] * n_psf
    s_list = [ 999. ] * n_psf
    flag_list = [ 0 ] * n_psf

    try:
        if use_piff:
            psf = piff.read(psf_file_name)
        else:
            psf = galsim.des.DES_PSFEx(psf_file_name, file_name)
    except Exception as e:
        if 'CTYPE' in str(e):
            try:
                # Workaround for a bug in DES_PSFEx.  It tries to read the image file using
                # GSFitsWCS, which doesn't work if it's not a normal FITS WCS. 
                # galsim.fits.read should work correctly in those cases.
                psf = galsim.des.DES_PSFEx(psf_file_name)
                im = galsim.fits.read(file_name)
                psf.wcs = im.wcs
                e = None
            except Exception as e:
                pass
        if e is not None:
            print 'Caught ',e
            flag_list = [ PSFEX_FAILURE ] * n_psf
            return e1_list,e2_list,s_list,flag_list

    stamp_size = 64
    pixel_scale = 0.2

    im = galsim.Image(stamp_size, stamp_size, scale=pixel_scale)

    for i in range(n_psf):
        x = xlist[i]
        y = ylist[i]
        print 'Measure PSFEx model shape at ',x,y
        image_pos = galsim.PositionD(x,y)
        #print 'im_pos = ',image_pos
        if use_piff:
            im = psf.draw(x=x, y=y, image=im)
        else:
            psf_i = psf.getPSF(image_pos)
            im = psf_i.drawImage(image=im, method='no_pixel')
        #print 'im = ',im

        try:
            shape_data = im.FindAdaptiveMom(strict=False)
        except:
            print ' *** Bad measurement (caught exception).  Mask this one.'
            flag_list[i] = PSFEX_BAD_MEASUREMENT
            continue
        #print 'shape_date = ',shape_data

        if shape_data.moments_status != 0:
            print 'status = ',shape_data.moments_status
            print ' *** Bad measurement.  Mask this one.'
            flag_list[i] = PSFEX_BAD_MEASUREMENT
            continue

        dx = shape_data.moments_centroid.x - im.trueCenter().x
        dy = shape_data.moments_centroid.y - im.trueCenter().y
        #print 'centroid = ',shape_data.moments_centroid
        #print 'trueCenter = ',im.trueCenter()
        #print 'dcentroid = ',dx,dy
        if dx**2 + dy**2 > MAX_CENTROID_SHIFT**2:
            print ' *** Centroid shifted by ',dx,dy,'.  Mask this one.'
            flag_list[i] = PSFEX_CENTROID_SHIFT
            continue

        g1 = shape_data.observed_shape.g1
        g2 = shape_data.observed_shape.g2
        s = shape_data.moments_sigma * pixel_scale

        #print 'g1,g2,s = ',g1,g2,s

        e1_list[i] = g1
        e2_list[i] = g2
        s_list[i] = s

    return e1_list,e2_list,s_list,flag_list
Ejemplo n.º 11
0
def test_draw():
    """Test the various options of the PSF.draw command.
    """
    if __name__ == '__main__':
        logger = piff.config.setup_logger(verbose=2)
    else:
        logger = piff.config.setup_logger(log_file='output/test_draw.log')

    # Use an existing Piff solution to match as closely as possible how users would actually
    # use this function.
    psf = piff.read('input/test_single_py27.piff', logger=logger)

    # Data that was used to make that file.
    wcs = galsim.TanWCS(
        galsim.AffineTransform(0.26, 0.05, -0.08, -0.24,
                               galsim.PositionD(1024, 1024)),
        galsim.CelestialCoord(-5 * galsim.arcmin, -25 * galsim.degrees))
    data = fitsio.read('input/test_single_cat1.fits')
    field_center = galsim.CelestialCoord(0 * galsim.degrees,
                                         -25 * galsim.degrees)
    chipnum = 1

    for k in range(len(data)):
        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)

        # First, the same test with this file that is in test_wcs.py:test_pickle()
        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)

        # Now use the regular PSF.draw() command.  This version is equivalent to the above.
        # (It's not equal all the way to machine precision, but pretty close.)
        im1 = psf.draw(x, y, chipnum, stamp_size=48)
        np.testing.assert_allclose(im1.array,
                                   star.data.image.array,
                                   rtol=1.e-14,
                                   atol=1.e-14)

        # The wcs in the image is the wcs of the original image
        assert im1.wcs == psf.wcs[1]

        # The image is 48 x 48
        assert im1.array.shape == (48, 48)

        # The bounds are centered close to x,y.  Within 0.5 pixel.
        np.testing.assert_allclose(im1.bounds.true_center.x, x, atol=0.5)
        np.testing.assert_allclose(im1.bounds.true_center.y, y, atol=0.5)

        # This version draws the star centered at (x,y).  Check the hsm centroid.
        hsm = im1.FindAdaptiveMom()
        #print('hsm = ',hsm)
        np.testing.assert_allclose(hsm.moments_centroid.x, x, atol=0.01)
        np.testing.assert_allclose(hsm.moments_centroid.y, y, atol=0.01)

        # The total flux should be close to 1.
        np.testing.assert_allclose(im1.array.sum(), 1.0, rtol=1.e-3)

        # We can center the star at an arbitrary location on the image.
        # The default is equivalent to center=(x,y).  So check that this is equivalent.
        # Also, 48 is the default stamp size, so that can be omitted here.
        im2 = psf.draw(x, y, chipnum, center=(x, y))
        assert im2.bounds == im1.bounds
        np.testing.assert_allclose(im2.array,
                                   im1.array,
                                   rtol=1.e-14,
                                   atol=1.e-14)

        # Moving by an integer number of pixels should be very close to the same image
        # over a different slice of the array.
        im3 = psf.draw(x, y, chipnum, center=(x + 1, y + 3))
        assert im3.bounds == im1.bounds
        # (Remember -- numpy indexing is y,x!)
        # Also, the FFTs will be different in detail, so only match to 1.e-6.
        #print('im1 argmax = ',np.unravel_index(np.argmax(im1.array),im1.array.shape))
        #print('im3 argmax = ',np.unravel_index(np.argmax(im3.array),im3.array.shape))
        np.testing.assert_allclose(im3.array[3:, 1:],
                                   im1.array[:-3, :-1],
                                   rtol=1.e-6,
                                   atol=1.e-6)
        hsm = im3.FindAdaptiveMom()
        np.testing.assert_allclose(hsm.moments_centroid.x, x + 1, atol=0.01)
        np.testing.assert_allclose(hsm.moments_centroid.y, y + 3, atol=0.01)

        # Can center at other locations, and the hsm centroids should come out centered pretty
        # close to that location.
        # (Of course the array will be different here, so can't test that.)
        im4 = psf.draw(x, y, chipnum, center=(x + 1.3, y - 0.8))
        assert im4.bounds == im1.bounds
        hsm = im4.FindAdaptiveMom()
        np.testing.assert_allclose(hsm.moments_centroid.x, x + 1.3, atol=0.01)
        np.testing.assert_allclose(hsm.moments_centroid.y, y - 0.8, atol=0.01)

        # Also allowed is center=True to place in the center of the image.
        im5 = psf.draw(x, y, chipnum, center=True)
        assert im5.bounds == im1.bounds
        assert im5.array.shape == (48, 48)
        np.testing.assert_allclose(im5.bounds.true_center.x, x, atol=0.5)
        np.testing.assert_allclose(im5.bounds.true_center.y, y, atol=0.5)
        np.testing.assert_allclose(im5.array.sum(), 1., rtol=1.e-3)
        hsm = im5.FindAdaptiveMom()
        center = im5.true_center
        np.testing.assert_allclose(hsm.moments_centroid.x, center.x, atol=0.01)
        np.testing.assert_allclose(hsm.moments_centroid.y, center.y, atol=0.01)

        # Some invalid ways to try to do this. (Must be either True or a tuple.)
        np.testing.assert_raises(ValueError,
                                 psf.draw,
                                 x,
                                 y,
                                 chipnum,
                                 center='image')
        np.testing.assert_raises(ValueError,
                                 psf.draw,
                                 x,
                                 y,
                                 chipnum,
                                 center=im5.true_center)

        # If providing your own image with bounds far away from the star (say centered at 0),
        # then center=True works fine to draw in the center of that image.
        im6 = im5.copy()
        im6.setCenter(0, 0)
        psf.draw(x, y, chipnum, center=True, image=im6)
        assert im6.bounds.center == galsim.PositionI(0, 0)
        np.testing.assert_allclose(im6.array.sum(), 1., rtol=1.e-3)
        hsm = im6.FindAdaptiveMom()
        center = im6.true_center
        np.testing.assert_allclose(hsm.moments_centroid.x, center.x, atol=0.01)
        np.testing.assert_allclose(hsm.moments_centroid.y, center.y, atol=0.01)
        np.testing.assert_allclose(im6.array,
                                   im5.array,
                                   rtol=1.e-14,
                                   atol=1.e-14)

        # Check non-even stamp size.  Also, not unit flux while we're at it.
        im7 = psf.draw(x,
                       y,
                       chipnum,
                       center=(x + 1.3, y - 0.8),
                       stamp_size=43,
                       flux=23.7)
        assert im7.array.shape == (43, 43)
        np.testing.assert_allclose(im7.bounds.true_center.x, x, atol=0.5)
        np.testing.assert_allclose(im7.bounds.true_center.y, y, atol=0.5)
        np.testing.assert_allclose(im7.array.sum(), 23.7, rtol=1.e-3)
        hsm = im7.FindAdaptiveMom()
        np.testing.assert_allclose(hsm.moments_centroid.x, x + 1.3, atol=0.01)
        np.testing.assert_allclose(hsm.moments_centroid.y, y - 0.8, atol=0.01)

        # Can't do mixed even/odd shape with stamp_size, but it will respect a provided image.
        im8 = galsim.Image(43, 44)
        im8.setCenter(
            x, y
        )  # It will respect the given bounds, so put it near the right place.
        psf.draw(x,
                 y,
                 chipnum,
                 center=(x + 1.3, y - 0.8),
                 image=im8,
                 flux=23.7)
        assert im8.array.shape == (44, 43)
        np.testing.assert_allclose(im8.array.sum(), 23.7, rtol=1.e-3)
        hsm = im8.FindAdaptiveMom()
        np.testing.assert_allclose(hsm.moments_centroid.x, x + 1.3, atol=0.01)
        np.testing.assert_allclose(hsm.moments_centroid.y, y - 0.8, atol=0.01)

        # The offset parameter can add an additional to whatever center is used.
        # Here center=None, so this is equivalent to im4 above.
        im9 = psf.draw(x, y, chipnum, offset=(1.3, -0.8))
        assert im9.bounds == im1.bounds
        hsm = im9.FindAdaptiveMom()
        np.testing.assert_allclose(im9.array,
                                   im4.array,
                                   rtol=1.e-14,
                                   atol=1.e-14)

        # With both, they are effectively added together.  Not sure if there would be a likely
        # use for this, but it's allowed.  (The above with default center is used in unit
        # tests a number of times, so that version at least is useful if only for us.
        # I'm hard pressed to imaging end users wanting to specify things this way though.)
        im10 = psf.draw(x,
                        y,
                        chipnum,
                        center=(x + 0.8, y - 0.3),
                        offset=(0.5, -0.5))
        assert im10.bounds == im1.bounds
        np.testing.assert_allclose(im10.array,
                                   im4.array,
                                   rtol=1.e-14,
                                   atol=1.e-14)
Ejemplo n.º 12
0
def test_reserve():
    """Test the reserve_frac option.
    """
    if __name__ == '__main__':
        logger = piff.config.setup_logger(verbose=2)
    else:
        logger = piff.config.setup_logger(
            log_file='output/test_single_reserve.log')

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

    # Where to put the stars.
    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
    ]

    # Draw a Gaussian PSF at each location on the image.
    sigma = 1.3
    g1 = 0.23
    g2 = -0.17
    true_params = [sigma, g1, g2]
    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))

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

    # 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('output', 'test_simple_reserve_cat.fits')
    fitsio.write(cat_file, data, clobber=True)

    psf_file = os.path.join('output', 'test_simple_reserve_psf.fits')
    config = {
        'input': {
            'image_file_name': image_file,
            'cat_file_name': cat_file,
            'reserve_frac': 0.2,
            'stamp_size': 32,
        },
        'psf': {
            'model': {
                'type': 'Gaussian',
                'fastfit': True,
                'include_pixel': False
            },
            'interp': {
                'type': 'Mean'
            },
        },
        'output': {
            'file_name': psf_file
        },
    }

    piff.piffify(config, logger)
    psf = piff.read(psf_file)
    assert type(psf.model) is piff.Gaussian
    assert type(psf.interp) is piff.Mean
    print('chisq = ', psf.chisq)
    print('dof = ', psf.dof)
    nreserve = len([s for s in psf.stars if s.is_reserve])
    ntot = len(psf.stars)
    print('reserve = %s/%s' % (nreserve, ntot))
    assert nreserve == 2
    assert ntot == 10
    print('dof =? ', (32 * 32 - 6) * (ntot - nreserve))
    assert psf.dof == (32 * 32 - 6) * (ntot - nreserve)
    for star in psf.stars:
        # Fits should be good for both reserve and non-reserve stars
        np.testing.assert_almost_equal(star.fit.params, true_params, decimal=4)
Ejemplo n.º 13
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)
Ejemplo n.º 14
0
def test_des_image():
    """Test the whole process with a DES CCD.
    """
    import os
    import fitsio

    image_file = 'y1_test/DECam_00241238_01.fits.fz'
    cat_file = 'y1_test/DECam_00241238_01_psfcat_tb_maxmag_17.0_magcut_3.0_findstars.fits'
    orig_image = galsim.fits.read(image_file)
    psf_file = os.path.join('output', 'pixel_des_psf.fits')

    if __name__ == '__main__':
        # These match what Gary used in fit_des.py
        nstars = None
        scale = 0.15
        size = 41
    else:
        # These are faster and good enough for the unit tests.
        nstars = 25
        scale = 0.2
        size = 21
    stamp_size = 51

    # The configuration dict with the right input fields for the file we're using.
    start_sigma = 1.0 / 2.355  # TODO: Need to make this automatic somehow.
    config = {
        'input': {
            'images': image_file,
            'image_hdu': 1,
            'weight_hdu': 3,
            'badpix_hdu': 2,
            'cats': cat_file,
            'cat_hdu': 2,
            'x_col': 'XWIN_IMAGE',
            'y_col': 'YWIN_IMAGE',
            'sky_col': 'BACKGROUND',
            'stamp_size': stamp_size,
            'ra': 'TELRA',
            'dec': 'TELDEC',
            'gain': 'GAINA',
        },
        'output': {
            'file_name': psf_file,
        },
        'psf': {
            'model': {
                'type': 'PixelGrid',
                'scale': scale,
                'size': size,
                'start_sigma': start_sigma,
            },
            'interp': {
                'type': 'BasisPolynomial',
                'order': 2,
            },
        },
    }
    if __name__ == '__main__': config['verbose'] = 3

    # 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:
        # Start by doing things manually:
        if __name__ == '__main__':
            logger = piff.config.setup_logger(2)
        else:
            logger = None

        # Largely copied from Gary's fit_des.py, but using the Piff input_handler to
        # read the input files.
        stars, wcs, pointing = piff.Input.process(config['input'],
                                                  logger=logger)
        if nstars is not None:
            stars = stars[:nstars]

        # Make model, force PSF centering
        model = piff.PixelGrid(scale=scale,
                               size=size,
                               interp=piff.Lanczos(3),
                               force_model_center=True,
                               start_sigma=start_sigma,
                               logger=logger)

        # Interpolator will be zero-order polynomial.
        # Find u, v ranges
        interp = piff.BasisPolynomial(order=2, logger=logger)

        # Make a psf
        psf = piff.SimplePSF(model, interp)
        psf.fit(stars, wcs, pointing, logger=logger)

        # The difference between the images of the fitted stars and the originals should be
        # consistent with noise.  Keep track of how many don't meet that goal.
        n_bad = 0  # chisq/dof > 2
        n_marginal = 0  # chisq/dof > 1.1
        n_good = 0  # chisq/dof <= 1.1
        # Note: The 2 and 1.1 values here are very arbitrary!

        for s in psf.stars:
            fitted = psf.drawStar(s)
            orig_stamp = orig_image[fitted.image.bounds] - s['sky']
            fit_stamp = fitted.image

            x0 = int(s['x'] + 0.5)
            y0 = int(s['y'] + 0.5)
            b = galsim.BoundsI(x0 - 3, x0 + 3, y0 - 3, y0 + 3)
            #print('orig center = ',orig_stamp[b].array)
            #print('flux = ',orig_stamp.array.sum())
            #print('fit center = ',fit_stamp[b].array)
            #print('flux = ',fit_stamp.array.sum())
            flux = fitted.fit.flux
            #print('max diff/flux = ',np.max(np.abs(orig_stamp.array-fit_stamp.array))/flux)
            #np.testing.assert_almost_equal(fit_stamp.array/flux, orig_stamp.array/flux, decimal=2)
            weight = s.weight  # These should be 1/var_pix
            resid = fit_stamp - orig_stamp
            chisq = np.sum(resid.array**2 * weight.array)
            print('chisq = ', chisq)
            print('cf. star.chisq, dof = ', s.fit.chisq, s.fit.dof)
            assert abs(chisq - s.fit.chisq) < 1.e-3 * chisq
            if chisq > 2. * s.fit.dof:
                n_bad += 1
            elif chisq > 1.1 * s.fit.dof:
                n_marginal += 1
            else:
                n_good += 1

            # Check the convenience function that an end user would typically use
            offset = s.center_to_offset(s.fit.center)
            image = psf.draw(x=s['x'],
                             y=s['y'],
                             stamp_size=stamp_size,
                             flux=s.fit.flux,
                             offset=offset)
            np.testing.assert_almost_equal(image.array,
                                           fit_stamp.array,
                                           decimal=4)

        print('n_good, marginal, bad = ', n_good, n_marginal, n_bad)
        # The real counts are 10 and 2.  So this says make sure any updates to the code don't make
        # things much worse.
        assert n_marginal <= 12
        assert n_bad <= 3

    # Use piffify function
    if __name__ == '__main__':
        print('start piffify')
        piff.piffify(config)
        print('read stars')
        stars, wcs, pointing = piff.Input.process(config['input'])
        print('read psf')
        psf = piff.read(psf_file)
        stars = [psf.model.initialize(s) for s in stars]
        flux = stars[0].fit.flux
        offset = stars[0].center_to_offset(stars[0].fit.center)
        fit_stamp = psf.draw(x=stars[0]['x'],
                             y=stars[0]['y'],
                             stamp_size=stamp_size,
                             flux=flux,
                             offset=offset)
        orig_stamp = orig_image[stars[0].image.bounds] - stars[0]['sky']
        # The first star happens to be a good one, so go ahead and test the arrays directly.
        np.testing.assert_almost_equal(fit_stamp.array / flux,
                                       orig_stamp.array / flux,
                                       decimal=2)

    # Test using the piffify executable
    config['verbose'] = 0
    with open('pixel_des.yaml', 'w') as f:
        f.write(yaml.dump(config, default_flow_style=False))
    if __name__ == '__main__':
        if os.path.exists(psf_file):
            os.remove(psf_file)
        piffify_exe = get_script_name('piffify')
        print('start piffify executable')
        p = subprocess.Popen([piffify_exe, 'pixel_des.yaml'])
        p.communicate()
        print('read stars')
        stars, wcs, pointing = piff.Input.process(config['input'])
        print('read psf')
        psf = piff.read(psf_file)
        stars = [psf.model.initialize(s) for s in stars]
        flux = stars[0].fit.flux
        offset = stars[0].center_to_offset(stars[0].fit.center)
        fit_stamp = psf.draw(x=stars[0]['x'],
                             y=stars[0]['y'],
                             stamp_size=stamp_size,
                             flux=flux,
                             offset=offset)
        orig_stamp = orig_image[stars[0].image.bounds] - stars[0]['sky']
        np.testing.assert_almost_equal(fit_stamp.array / flux,
                                       orig_stamp.array / flux,
                                       decimal=2)
Ejemplo n.º 15
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)
Ejemplo n.º 16
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:
    for gp_piff in ['GPInterp', 'GPInterp2pcf']:
        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' : gp_piff,
                             'keys' : ['u', 'v'],
                             'kernel' : 'RBF(200.0)',
                             'optimize' : False,}
            },
            'output' : { 'file_name' : psf_file },
        }

        if __name__ != '__main__':
            config['input']['nstars'] = 25

        piff.piffify(config, logger)
        psf = piff.read(psf_file)
        assert type(psf.model) is piff.GSObjectModel
        assert type(psf.interp) is piff.GPInterp or type(psf.interp) is piff.GPInterp2pcf
        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)
Ejemplo n.º 17
0
def zernike(directory, config_file_name, piff_name, do_interp):
    config = piff.read_config('{0}/{1}.yaml'.format(directory, config_file_name))
    logger = piff.setup_logger(verbose=3)

    # load base optics psf
    out_path = '{0}/{1}.piff'.format(directory, piff_name)
    psf = piff.read(out_path)

    # load images for train stars
    psf.stars = load_star_images(psf.stars, config, logger=logger)
    stars = psf.stars

    params = psf.getParamsList(stars)

    # if do_interp, draw star models and fit radial profile
    if do_interp:
        # draw model stars
        model_stars = psf.drawStarList(stars)

        # fit radial piece
        radial_agg = collect_radial_profiles(stars, model_stars)
        interpfunc = interp1d(radial_agg['r'].values, radial_agg['dI'].values)
        radial_agg.to_hdf('{0}/radial_{1}_{2}.h5'.format(directory, 'train', piff_name), 'data')
        fig = Figure(figsize = (10, 5))
        ax = fig.add_subplot(1, 1, 1)
        ax.plot(radial_agg['r'], radial_agg['dI'])
        ax.set_xlabel('r')
        ax.set_ylabel('Residual radial image')
        canvas = FigureCanvasAgg(fig)
        # Do this after we've set the canvas to use Agg to avoid warning.
        fig.set_tight_layout(True)
        plot_path = '{0}/radial_{1}_{2}.pdf'.format(directory, 'train', piff_name)
        logger.info('saving plot to {0}'.format(plot_path))
        canvas.print_figure(plot_path, dpi=100)

        # do the fits of the stars
        logger.info('Fitting {0} stars'.format(len(stars)))
        model_fitted_stars = []
        for star_i, star in zip(range(len(stars)), stars):
            if (star_i + 1) % int(max([len(stars) * 0.05, 1])) == 0:
                logger.info('doing {0} out of {1}:'.format(star_i + 1, len(stars)))
            try:
                model_fitted_star, results = fit_with_radial(psf, star, interpfunc, vary_shape=True, vary_optics=True)
                model_fitted_stars.append(model_fitted_star)
                if (star_i + 1) % int(max([len(stars) * 0.05, 1])) == 0:
                    logger.debug(lmfit.fit_report(results, min_correl=0.5))
            except (KeyboardInterrupt, SystemExit):
                raise
            except Exception as e:
                logger.warning('{0}'.format(str(e)))
                logger.warning('Warning! Failed to fit atmosphere model for star {0}. Ignoring star in atmosphere fit'.format(star_i))
        stars = model_fitted_stars
        logger.info('Drawing final model stars')
        drawn_stars = [drawProfile(psf, star, psf.getProfile(star.fit.params), star.fit.params, use_fit=True, copy_image=True, interpfunc=interpfunc) for star in stars]
    else:
        # else just do regular zernike fit
        logger.info('Fitting {0} stars'.format(len(stars)))
        model_fitted_stars = []
        for star_i, star in zip(range(len(stars)), stars):
            if (star_i + 1) % int(max([len(stars) * 0.05, 1])) == 0:
                logger.info('doing {0} out of {1}:'.format(star_i + 1, len(stars)))
            try:
                if (star_i + 1) % int(max([len(stars) * 0.05, 1])) == 0:
                    model_fitted_star, results = psf.fit_model(star, params=params[star_i], vary_shape=True, vary_optics=True, mode='pixel', logger=logger)
                else:
                    model_fitted_star, results = psf.fit_model(star, params=params[star_i], vary_shape=True, vary_optics=True, mode='pixel')
                model_fitted_stars.append(model_fitted_star)
            except (KeyboardInterrupt, SystemExit):
                raise
            except Exception as e:
                logger.warning('{0}'.format(str(e)))
                logger.warning('Warning! Failed to fit atmosphere model for star {0}. Ignoring star in atmosphere fit'.format(star_i))
        stars = model_fitted_stars
        logger.info('Drawing final model stars')
        drawn_stars = [psf.drawProfile(star, psf.getProfile(star.fit.params), star.fit.params, copy_image=True, use_fit=True) for star in stars]


    logger.info('Measuring star shapes')
    shapes = measure_star_shape(stars, drawn_stars, logger=logger)

    logger.info('Adding fitted params and params_var')
    shape_keys = ['e0', 'e1', 'e2', 'delta1', 'delta2', 'zeta1', 'zeta2']
    shape_plot_keys = []
    for key in shape_keys:
        shape_plot_keys.append(['data_' + key, 'model_' + key, 'd' + key])
    param_keys = ['atmo_size', 'atmo_g1', 'atmo_g2'] + ['optics_size', 'optics_g1', 'optics_g2'] + ['z{0:02d}'.format(zi) for zi in range(4, 45)]
    logger.info('Extracting training fit parameters')
    params = np.array([star.fit.params for star in stars])
    params_var = np.array([star.fit.params_var for star in stars])
    for i in range(params.shape[1]):
        shapes['{0}_fit'.format(param_keys[i])] = params[:, i]
        shapes['{0}_var'.format(param_keys[i])] = params_var[:, i]

    shapes['chisq'] = np.array([star.fit.chisq for star in stars])
    shapes['dof'] = np.array([star.fit.dof for star in stars])

    logger.info('saving shapes')
    shapes.to_hdf('{0}/zernikeshapes_{1}_{2}_zernike{3}.h5'.format(directory, 'train', piff_name, ['_reg', '_interp'][do_interp]), 'data')

    logger.info('saving stars')
    fits_path = '{0}/zernikestars_{1}_{2}_zernike{3}.fits'.format(directory, 'train', piff_name, ['_reg', '_interp'][do_interp])
    with fitsio.FITS(fits_path, 'rw', clobber=True) as f:
        piff.Star.write(stars, f, extname='zernike_stars')

    logger.info('making 2d plots')
    # plot shapes
    fig, axs = plot_2dhist_shapes(shapes, shape_plot_keys, diff_mode=True)
    # save
    fig.savefig('{0}/zernike{3}_shapes_{1}_{2}.pdf'.format(directory, 'train', piff_name, ['_reg', '_interp'][do_interp]))
    # plot params
    plot_keys = []
    plot_keys_i = []
    for i in range(params.shape[1]):
        plot_keys_i.append(param_keys[i])
        if len(plot_keys_i) == 3:
            plot_keys.append(plot_keys_i)
            plot_keys_i = []
    if len(plot_keys_i) > 0:
        plot_keys_i += [plot_keys_i[0]] * (3 - len(plot_keys_i))
        plot_keys.append(plot_keys_i)
    fig, axs = plot_2dhist_shapes(shapes, [[key + '_fit' for key in kp] for kp in plot_keys], diff_mode=False)
    fig.savefig('{0}/zernike{3}_fit_params_{1}_{2}.pdf'.format(directory, 'train', piff_name, ['_reg', '_interp'][do_interp]))

    nstars = min([20, len(stars)])
    indices = np.random.choice(len(stars), nstars, replace=False)
    logger.info('saving {0} star images'.format(nstars))
    fig = Figure(figsize = (4 * 4, 3 * nstars))
    for i, indx in enumerate(indices):
        axs = [ fig.add_subplot(nstars, 4, i * 4 + j + 1) for j in range(4)]
        # select a star
        star = stars[indx]
        # draw the model star
        params = star.fit.params
        prof = psf.getProfile(params)
        if do_interp:
            star_drawn = drawProfile(psf, star, psf.getProfile(star.fit.params), star.fit.params, use_fit=True, copy_image=True, interpfunc=interpfunc)
        else:
            star_drawn = psf.drawProfile(star, prof, params, use_fit=True, copy_image=True)
        # make plot
        draw_stars(star, star_drawn, fig, axs)

    canvas = FigureCanvasAgg(fig)
    # Do this after we've set the canvas to use Agg to avoid warning.
    fig.set_tight_layout(True)

    # save files based on what is listed
    plot_path = '{0}/zernike{3}_stars_{1}_{2}.pdf'.format(directory, 'train', piff_name, ['_reg', '_interp'][do_interp])
    logger.info('saving plot to {0}'.format(plot_path))
    canvas.print_figure(plot_path, dpi=100)
Ejemplo n.º 18
0
def test_parallel():
    # Run the same test as test_single, but using nproc
    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
    else:
        nstars = 6  # per ccd
    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_parallel_im1.fits')

    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_parallel_im2.fits')

    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_parallel.fits', data12, clobber=True)

    # im3 is blank.  Will give errors trying to measure PSF from it.
    im3 = galsim.Image(2048, 2048, wcs=wcs2)
    im3.write('output/test_parallel_im3.fits')

    psf_file = os.path.join('output', 'test_single.fits')
    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_parallel_im%d.fits',
                'items': ['output', '$image_num+1'],
            },
            'cat_file_name': 'output/test_parallel.fits',
            'chipnum': '$image_num+1',
            'ra_col': 'ra',
            'dec_col': 'dec',
            'ra_units': 'rad',
            'dec_units': 'rad',
            'nproc': -1,
        },
        'psf': {
            'type': 'SingleChip',
            'model': {
                'type': 'Moffat',
                'beta': 2.5,
            },
            'interp': {
                'type': 'Polynomial',
                'order': 2,
            },
            'nproc': 2,
        },
        'output': {
            'file_name': psf_file,
        },
    }
    with CaptureLog(level=2) as cl:
        piff.piffify(config, logger=cl.logger)
    psf = piff.read(psf_file)

    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]
            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)
            np.testing.assert_almost_equal(star.fit.params, [s, e1, e2],
                                           decimal=6)

    # Finally, check that the logger properly captures the subprocess logs
    with CaptureLog(level=2) as cl:
        psf = piff.process(config, cl.logger)
    #print('with nproc=2, log = ',cl.output)
    assert "Processing catalog 1" in cl.output
    assert "Processing catalog 2" in cl.output
    assert "Building solution for chip 1" in cl.output
    assert "Building solution for chip 2" in cl.output

    # Check that errors in the solution get properly reported.
    config['input']['nimages'] = 3
    with CaptureLog(level=2) as cl:
        psf = piff.process(config, cl.logger)
    assert "Removed 6 stars in initialize" in cl.output
    assert "No stars.  Cannot find PSF model." in cl.output
    assert "Solutions failed for chipnums: [3]" in cl.output

    # Check that errors in the multiprocessing input get properly reported.
    config['input']['ra_col'] = 'invalid'
    with CaptureLog(level=2) as cl:
        with np.testing.assert_raises(ValueError):
            psf = piff.process(config, cl.logger)
    assert "ra_col = invalid is not a column" in cl.output

    # With nproc=1, the error is raised directly.
    config['input']['nproc'] = 1
    config['verbose'] = 0
    with np.testing.assert_raises(ValueError):
        psf = piff.process(config)

    # But just the input error.  Not the one in fitting.
    config['psf']['nproc'] = 1
    config['input']['ra_col'] = 'ra'
    config['verbose'] = 1
    with CaptureLog(level=1) as cl:
        psf = piff.process(config, logger=cl.logger)
    assert "No stars.  Cannot find PSF model." in cl.output
    assert "Ignoring this failure and continuing on." in cl.output
Ejemplo n.º 19
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()
Ejemplo n.º 20
0
def test_depr_select():
    # A bunch of keys used to be allowed in input, but now belong in select.
    # Check that the old way still works, but gives a warning.

    # This is the input from test_stars in test_input.py
    dir = 'input'
    image_file = 'test_input_image_00.fits'
    cat_file = 'test_input_cat_00.fits'
    psf_file = os.path.join('output','test_depr_select.fits')

    config = {
        'input' : {
                'dir' : dir,
                'image_file_name' : image_file,
                'cat_file_name' : cat_file,
                'weight_hdu' : 1,
                'sky_col' : 'sky',
                'gain_col' : 'gain',
                'use_partial' : True,
                'nstars': 15,  # Just to make the test faster
             },
        'select': {
                'max_snr' : 200,
                'min_snr' : 20,
                'hsm_size_reject' : 20,
                'max_edge_frac': 0.25,
                'stamp_center_size': 10,
                'max_mask_pixels' : 20,
                'reserve_frac' : 0.1,
                'seed': 1234,
        },
        'psf': {
            'model' : {'type': 'Gaussian'},
            'interp' : {'type': 'Mean'},
        },
        'output' : { 'file_name' : psf_file },
    }

    logger = piff.config.setup_logger(log_file='output/test_depr_select.log')

    # This is the new API
    print('config = ',config)
    piff.piffify(config, logger)
    psf1 = piff.read(psf_file)
    im1 = psf1.draw(x=23, y=34, stamp_size=16)
    print('len1 = ',len(psf1.stars))

    # This is the old API
    config['input'].update(config['select'])
    del config['select']
    config = galsim.config.CleanConfig(config)
    print('config = ',config)
    with CaptureLog(level=1) as cl:
        piff.piffify(config, cl.logger)
    assert "WARNING: Items [" in cl.output
    assert "] should now be in the 'select' field of the config file." in cl.output
    psf2 = piff.read(psf_file)
    print('len2 = ',len(psf2.stars))
    assert len(psf1.stars) == len(psf2.stars)
    im2 = psf2.draw(x=23, y=34, stamp_size=16)
    np.testing.assert_allclose(im2.array, im1.array)

    # Also ok for some items to be in select, but erroneously put some in input.
    config['input']['min_snr'] = config['select'].pop('min_snr')
    config['input']['max_snr'] = config['select'].pop('max_snr')
    config = galsim.config.CleanConfig(config)
    print('config = ',config)
    with CaptureLog(level=1) as cl:
        piff.piffify(config, cl.logger)
    assert "WARNING: Items ['max_snr', 'min_snr'] should now be in the 'select' field of the config file." in cl.output
    psf3 = piff.read(psf_file)
    print('len3 = ',len(psf3.stars))
    assert len(psf1.stars) == len(psf3.stars)
    im3 = psf3.draw(x=23, y=34, stamp_size=16)
    np.testing.assert_allclose(im3.array, im1.array)
Ejemplo n.º 21
0
ncolor = len(colors)
nx = len(xs)
ny = len(ys)

src = info['src_info'][n]

band = src['band']
image_path = src['image_path']
piff_path = src['piff_path']
piff_info = src['piff_info']  # ccdnum, expnum, nstar, desdm_flags, fwhm_cen,
# exp_star_t_mean, exp_star_t_std, star_t_mean, star_t_std
ccdnum = piff_info['ccdnum']

print(n, band, piff_path)
psf = piff.read(piff_path)

print(piff_info)
print('chisq = ', psf.chisq)
print('dof = ', psf.dof)
print('nremoved = ', psf.nremoved)
print('nused = ', len(psf.stars))
print('colors = ', [s['GI_COLOR'] for s in psf.stars])

allT = np.zeros((ncolor, nx, ny), dtype=float)
allg1 = np.zeros((ncolor, nx, ny), dtype=float)
allg2 = np.zeros((ncolor, nx, ny), dtype=float)

for icolor, color in enumerate(colors):
    print('color = ', color)
    for ix, x in enumerate(xs):
Ejemplo n.º 22
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

    # 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
    model = piff.Gaussian()
    interp = piff.Mean()
    fitted_stars = [ model.fit(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=5)

    # 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' },
            'interp' : { 'type' : 'Mean' },
        },
        'output' : { 'file_name' : psf_file },
    }
    if __name__ == '__main__':
        logger = piff.config.setup_logger(verbose=3)
    else:
        logger = piff.config.setup_logger(verbose=1)
    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=5)

    # 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=5)

    # 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=5)

    # Test using the piffify executable
    os.remove(psf_file)
    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=5)

    # 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.png')
    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.png')
    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
        },
    ]

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

    # Test using the piffify executable
    os.remove(psf_file)
    os.remove(rho_psf_file)
    os.remove(shape_psf_file)
    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()
Ejemplo n.º 23
0
def test_bad_hsm():
    """Test that stats don't break when all stars end up being flagged with hsm errors.
    """
    image_file = os.path.join('input','DECam_00241238_01.fits.fz')
    cat_file = os.path.join('input',
                            'DECam_00241238_01_psfcat_tb_maxmag_17.0_magcut_3.0_findstars.fits')
    psf_file = os.path.join('output','bad_hsm.fits')

    twodhist_file = os.path.join('output','bad_hsm_twod.pdf')
    whisker_file = os.path.join('output','bad_hsm_whisk.pdf')
    rho_file = os.path.join('output','bad_hsm_rho.pdf')
    shape_file = os.path.join('output','bad_hsm_shape.pdf')
    star_file = os.path.join('output','bad_hsm_star.pdf')
    hsm_file = os.path.join('output','bad_hsm_hsm.fits')
    sizemag_file = os.path.join('output','bad_hsm_sizemag.png')

    stamp_size = 25

    # The configuration dict with the right input fields for the file we're using.
    config = {
        'input' : {
            'nstars': 8,
            'image_file_name' : image_file,
            'image_hdu' : 1,
            'weight_hdu' : 3,
            'badpix_hdu' : 2,
            'cat_file_name' : cat_file,
            'cat_hdu' : 2,
            # These next two are intentionally backwards.  The PixelGrid will find some kind
            # of solution, but it will be complex garbage, and hsm will fail for them.
            'x_col' : 'YWIN_IMAGE',
            'y_col' : 'XWIN_IMAGE',
            'sky_col' : 'BACKGROUND',
            'stamp_size' : stamp_size,
            'ra' : 'TELRA',
            'dec' : 'TELDEC',
            'gain' : 'GAINA',
        },
        'output' : {
            'file_name' : psf_file,
            'stats' : [
                {
                    'type': 'TwoDHist',
                    'file_name': twodhist_file,
                },
                {
                    'type': 'Whisker',
                    'file_name': whisker_file,
                },
                {  # Note: stats doesn't have to be a list.
                    'type': 'Rho',
                    'file_name': rho_file
                },
                {
                    'type': 'ShapeHist',
                    'file_name': shape_file,
                },
                {
                    'type': 'Star',
                    'file_name': star_file,
                },
                {
                    'type': 'SizeMag',
                    'file_name': sizemag_file,
                },
                {
                    'type': 'HSMCatalog',
                    'file_name': hsm_file,
                },
            ],
        },
        'psf' : {
            'model' : {
                'type' : 'PixelGrid',
                'scale' : 0.3,
                'size' : 10,
            },
            'interp' : { 'type' : 'Mean' },
            'outliers' : {
                'type' : 'Chisq',
                'nsigma' : 0.05   # This will throw out all but 1, which adds an additional
                                  # test of Star stats when nstars < nplot
            }
        },
    }
    if __name__ == '__main__':
        logger = piff.config.setup_logger(1)
    else:
        config['verbose'] = 0
        logger = None

    for f in [twodhist_file, rho_file, shape_file, star_file, hsm_file]:
        if os.path.exists(f):
            os.remove(f)

    piff.piffify(config, logger=logger)

    # Confirm that all but one star was rejected, since that was part of the intent of this test.
    psf = piff.read(psf_file)
    print('stars = ',psf.stars)
    print('nremoved = ',psf.nremoved)
    assert len(psf.stars) == 1
    assert psf.nremoved == 7    # There were 8 to start.

    for f in [twodhist_file, rho_file, shape_file, star_file, sizemag_file, hsm_file]:
        assert os.path.exists(f)

    # Check hsm file with bad measurements
    # The one star that was left still fails hsm measurement here.
    data = fitsio.read(hsm_file)
    for col in ['ra', 'dec', 'x', 'y', 'u', 'v',
                'T_data', 'g1_data', 'g2_data',
                'T_model', 'g1_model', 'g2_model',
                'flux', 'reserve', 'flag_truth', 'flag_model']:
        assert len(data[col]) == 1
    print('flag_truth = ',data['flag_truth'])
    print('flag_model = ',data['flag_model'])
    np.testing.assert_array_equal(data['flag_truth'], 7)
    np.testing.assert_array_equal(data['flag_model'], 7)
Ejemplo n.º 24
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
Ejemplo n.º 25
0
def test_shapestats_config():
    """Test running stats through a config file.
    """
    if __name__ == '__main__':
        logger = piff.config.setup_logger(verbose=2)
    else:
        logger = piff.config.setup_logger(log_file='output/test_shapestats_config.log')

    image_file = os.path.join('output','test_stats_image.fits')
    cat_file = os.path.join('output','test_stats_cat.fits')
    psf_file = os.path.join('output','test_shapestats.fits')
    shape_file = os.path.join('output','test_shapestats.pdf')
    config = {
        'input' : {
            'image_file_name' : image_file,
            'cat_file_name' : cat_file,
            'stamp_size' : 48
        },
        'psf' : {
            'model' : { 'type' : 'Gaussian',
                        'fastfit': True,
                        'include_pixel': False },
            'interp' : { 'type' : 'Mean' },
        },
        'output' : {
            'file_name' : psf_file,
            'stats' : [
                {
                    'type': 'ShapeHist',
                    'file_name': shape_file
                },
            ]
        },
    }
    piff.piffify(config, logger)
    assert os.path.isfile(shape_file)

    # repeat with plotify function
    os.remove(shape_file)
    piff.plotify(config, logger)
    assert os.path.isfile(shape_file)

    # Test ShapeHistStats directly
    psf = piff.read(psf_file)
    shapeStats = piff.ShapeHistStats(nbins=5)  # default is sqrt(nstars)
    orig_stars, wcs, pointing = piff.Input.process(config['input'], logger)
    with np.testing.assert_raises(RuntimeError):
        shapeStats.write()  # Cannot write before compute
    shapeStats.compute(psf, orig_stars)
    shapeStats.plot(histtype='bar', log=True)  # can supply additional args for matplotlib

    # test their characteristics
    sigma = 1.3  # (copied from setup())
    T = 2*sigma**2
    g1 = 0.23
    g2 = -0.17
    np.testing.assert_array_almost_equal(T, shapeStats.T, decimal=4)
    np.testing.assert_array_almost_equal(T, 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)
Ejemplo n.º 26
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))
    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}
    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.)

    loaded_stars = piff.Star.load_images(psf2.stars, image_file)
    for star, orig in zip(loaded_stars, psf.stars):
        np.testing.assert_array_equal(star.image.array, orig.image.array)

    # Can optionally supply sky to subtract
    loaded_stars = piff.Star.load_images(psf2.stars, image_file, sky=10)
    for star, orig in zip(loaded_stars, psf.stars):
        np.testing.assert_array_equal(star.image.array, orig.image.array - 10)
Ejemplo n.º 27
0
from piff.optatmo_psf import poly, poly_full

test_mode = False
out_dir = '/nfs/slac/g/ki/ki18/cpd/Projects/piff_des/analytics'

# In[310]:

config = piff.read_config(
    '/u/ki/cpd/ki19/piff_test/y3/mar_mesh_configs_fix_sph/00233466/Science-20121120s1-v20i2_limited/2018.03.29/config.yaml'
)

# In[311]:

# create an OptAtmoPSF for drawing
psf_fit = piff.read(
    '/u/ki/cpd/ki19/piff_test/y3/mar_mesh_configs_fix_sph/00233466/Science-20121120s1-v20i2_limited/2018.03.29/psf.piff'
)

# In[312]:

# load up some stars
# do import modules so we can import pixmappy wcs
galsim.config.ImportModules(config)
# only load one ccd
config['input']['image_file_name'] = config['input'][
    'image_file_name'].replace('*', '10')
# only load 10 stars in the ccd
config['input']['nstars'] = 10

if test_mode:
    config['input']['stamp_size'] = 15
Ejemplo n.º 28
0
def test_rhostats_config():
    """Test running stats through a config file.
    """
    if __name__ == '__main__':
        logger = piff.config.setup_logger(verbose=2)
    else:
        logger = piff.config.setup_logger(log_file='output/test_rhostats_config.log')

    image_file = os.path.join('output','test_stats_image.fits')
    cat_file = os.path.join('output','test_stats_cat.fits')
    psf_file = os.path.join('output','test_rhostats.fits')
    rho_file = os.path.join('output','test_rhostats.pdf')
    config = {
        'input' : {
            'image_file_name' : image_file,
            'cat_file_name' : cat_file,
            'stamp_size' : 48
        },
        'psf' : {
            'model' : { 'type' : 'Gaussian',
                        'fastfit': True,
                        'include_pixel': False },
            'interp' : { 'type' : 'Mean' },
        },
        'output' : {
            'file_name' : psf_file,
            'stats' : {  # Note: stats doesn't have to be a list.
                'type': 'Rho',
                'file_name': rho_file
            }
        },
    }
    piff.piffify(config, logger)
    assert os.path.isfile(rho_file)

    # repeat with plotify function
    os.remove(rho_file)
    piff.plotify(config, logger)
    assert os.path.isfile(rho_file)

    # Test rho statistics directly.
    min_sep = 1
    max_sep = 100
    bin_size = 0.1
    psf = piff.read(psf_file)
    orig_stars, wcs, pointing = piff.Input.process(config['input'], logger)
    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)
        np.testing.assert_array_less(radius, max_sep)
        np.testing.assert_array_less(min_sep, radius)
        # bin_size is reduced slightly to get integer number of bins
        assert rho.bin_size < bin_size
        assert np.isclose(rho.bin_size, bin_size, rtol=0.1)
        np.testing.assert_array_almost_equal(np.diff(rho.logr), rho.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 using the piffify executable
    os.remove(rho_file)
    config['verbose'] = 0
    with open('rho.yaml','w') as f:
        f.write(yaml.dump(config, default_flow_style=False))
    piffify_exe = get_script_name('piffify')
    p = subprocess.Popen( [piffify_exe, 'rho.yaml'] )
    p.communicate()
    assert os.path.isfile(rho_file)

    # Test using the plotify executable
    os.remove(rho_file)
    plotify_exe = get_script_name('plotify')
    p = subprocess.Popen( [plotify_exe, 'rho.yaml'] )
    p.communicate()
    assert os.path.isfile(rho_file)

    # test running plotify with dir in config, with no logger, and with a modules specification.
    # (all to improve test coverage)
    config['output']['dir'] = '.'
    config['modules'] = [ 'custom_wcs' ]
    os.remove(rho_file)
    piff.plotify(config)
    assert os.path.isfile(rho_file)
Ejemplo n.º 29
0
 def __init__(self, file_name):
     self.file_name = file_name
     self._piff = piff.read(
         os.path.expanduser(os.path.expandvars(file_name)))
     self._did_fit = False
Ejemplo n.º 30
0
def test_starstats_config():
    """Test running stats through a config file.
    """
    if __name__ == '__main__':
        logger = piff.config.setup_logger(verbose=2)
    else:
        logger = piff.config.setup_logger(log_file='output/test_starstats_config.log')

    image_file = os.path.join('output','test_stats_image.fits')
    cat_file = os.path.join('output','test_stats_cat.fits')
    psf_file = os.path.join('output','test_starstats.fits')
    star_file = os.path.join('output', 'test_starstats.pdf')
    star_noadjust_file = os.path.join('output', 'test_starstats_noadjust.pdf')
    config = {
        'input' : {
            'image_file_name' : image_file,
            'cat_file_name' : cat_file,
            'stamp_size' : 48
        },
        'psf' : {
            'model' : { 'type' : 'Gaussian',
                        'fastfit': True,
                        'include_pixel': False },
            'interp' : { 'type' : 'Mean' },
        },
        'output' : {
            'file_name' : psf_file,
            'stats' : [
                {
                    'type': 'Star',
                    'file_name': star_file,
                    'number_plot': 5,
                    'adjust_stars': True,
                }
            ]
        }
    }
    piff.piffify(config, logger)
    assert os.path.isfile(star_file)

    # repeat with plotify function
    os.remove(star_file)
    piff.plotify(config, logger)
    assert os.path.isfile(star_file)

    # check default number_plot
    psf = piff.read(psf_file)
    starStats = piff.StarStats()
    orig_stars, wcs, pointing = piff.Input.process(config['input'], logger)
    starStats.compute(psf, orig_stars)
    assert starStats.number_plot == len(starStats.stars)
    assert starStats.number_plot == len(starStats.models)
    assert starStats.number_plot == len(starStats.indices)
    np.testing.assert_array_equal(starStats.stars[2].image.array,
                                  orig_stars[starStats.indices[2]].image.array)

    # check number_plot = 6
    starStats = piff.StarStats(number_plot=6)
    starStats.compute(psf, orig_stars)
    assert len(starStats.stars) == 6

    # check number_plot >> len(stars)
    starStats = piff.StarStats(number_plot=1000000)
    starStats.compute(psf, orig_stars)
    assert len(starStats.stars) == len(orig_stars)
    # if use all stars, no randomness
    np.testing.assert_array_equal(starStats.stars[3].image.array, orig_stars[3].image.array)
    np.testing.assert_array_equal(starStats.indices, np.arange(len(orig_stars)))

    # check number_plot = 0
    starStats = piff.StarStats(number_plot=0)
    starStats.compute(psf, orig_stars)
    assert len(starStats.stars) == len(orig_stars)
    # if use all stars, no randomness
    np.testing.assert_array_equal(starStats.stars[3].image.array, orig_stars[3].image.array)
    np.testing.assert_array_equal(starStats.indices, np.arange(len(orig_stars)))

    # rerun with adjust stars and see if it did the right thing
    # first with starstats == False
    starStats = piff.StarStats(number_plot=0, adjust_stars=False)
    starStats.compute(psf, orig_stars, logger=logger)
    fluxs_noadjust = np.array([s.fit.flux for s in starStats.stars])
    ds_noadjust = np.array([s.fit.center for s in starStats.stars])
    # check that fluxes 1
    np.testing.assert_array_equal(fluxs_noadjust, 1)
    # check that ds are 0
    np.testing.assert_array_equal(ds_noadjust, 0)

    # now with starstats == True
    starStats = piff.StarStats(number_plot=0, adjust_stars=True)
    starStats.compute(psf, orig_stars, logger=logger)
    fluxs_adjust = np.array([s.fit.flux for s in starStats.stars])
    ds_adjust = np.array([s.fit.center for s in starStats.stars])
    # copy the right values from setup()
    dx = 0.31
    dy = -0.32
    flux = 123.45
    # compare fluxes
    np.testing.assert_allclose(fluxs_adjust, flux, rtol=1e-4)
    # compare dx and dy, keeping in mind that ds_adjust is dx/y * 0.26 (scale)
    dx_adjust = ds_adjust[:, 0] / 0.26
    dy_adjust = ds_adjust[:, 1] / 0.26
    np.testing.assert_allclose(dx_adjust, dx, rtol=1e-4)
    np.testing.assert_allclose(dy_adjust, dy, rtol=1e-4)

    # do once with adjust_stars = False to graphically demonstrate
    config['output']['stats'][0]['file_name'] = star_noadjust_file
    config['output']['stats'][0]['adjust_stars'] = False
    piff.plotify(config, logger)
    assert os.path.isfile(star_noadjust_file)
Ejemplo n.º 31
0
def measure_psf_shapes(xlist, ylist, psf_file_name, file_name, use_piff=False):
    """Given x,y positions, a psf solution file, and the wcs, measure shapes and sizes
    of the PSF model.

    We use the HSM module from GalSim to do this.

    Returns e1, e2, size, flag.
    """
    print 'Read in PSFEx file: ', psf_file_name

    n_psf = len(xlist)
    e1_list = [999.] * n_psf
    e2_list = [999.] * n_psf
    s_list = [999.] * n_psf
    flag_list = [0] * n_psf

    try:
        if use_piff:
            psf = piff.read(psf_file_name)
        else:
            psf = galsim.des.DES_PSFEx(psf_file_name, file_name)
    except Exception as e:
        if 'CTYPE' in str(e):
            try:
                # Workaround for a bug in DES_PSFEx.  It tries to read the image file using
                # GSFitsWCS, which doesn't work if it's not a normal FITS WCS.
                # galsim.fits.read should work correctly in those cases.
                psf = galsim.des.DES_PSFEx(psf_file_name)
                im = galsim.fits.read(file_name)
                psf.wcs = im.wcs
                e = None
            except Exception as e:
                pass
        if e is not None:
            print 'Caught ', e
            flag_list = [PSFEX_FAILURE] * n_psf
            return e1_list, e2_list, s_list, flag_list

    stamp_size = 64
    pixel_scale = 0.2

    im = galsim.Image(stamp_size, stamp_size, scale=pixel_scale)

    for i in range(n_psf):
        x = xlist[i]
        y = ylist[i]
        print 'Measure PSFEx model shape at ', x, y
        image_pos = galsim.PositionD(x, y)
        #print 'im_pos = ',image_pos
        if use_piff:
            im = psf.draw(x=x, y=y, image=im)
        else:
            psf_i = psf.getPSF(image_pos)
            im = psf_i.drawImage(image=im, method='no_pixel')
        #print 'im = ',im

        try:
            shape_data = im.FindAdaptiveMom(strict=False)
        except:
            print ' *** Bad measurement (caught exception).  Mask this one.'
            flag_list[i] = PSFEX_BAD_MEASUREMENT
            continue
        #print 'shape_date = ',shape_data

        if shape_data.moments_status != 0:
            print 'status = ', shape_data.moments_status
            print ' *** Bad measurement.  Mask this one.'
            flag_list[i] = PSFEX_BAD_MEASUREMENT
            continue

        dx = shape_data.moments_centroid.x - im.trueCenter().x
        dy = shape_data.moments_centroid.y - im.trueCenter().y
        #print 'centroid = ',shape_data.moments_centroid
        #print 'trueCenter = ',im.trueCenter()
        #print 'dcentroid = ',dx,dy
        if dx**2 + dy**2 > MAX_CENTROID_SHIFT**2:
            print ' *** Centroid shifted by ', dx, dy, '.  Mask this one.'
            flag_list[i] = PSFEX_CENTROID_SHIFT
            continue

        g1 = shape_data.observed_shape.g1
        g2 = shape_data.observed_shape.g2
        s = shape_data.moments_sigma * pixel_scale

        #print 'g1,g2,s = ',g1,g2,s

        e1_list[i] = g1
        e2_list[i] = g2
        s_list[i] = s

    return e1_list, e2_list, s_list, flag_list