コード例 #1
0
def get_flux_and_err(imagedat, psfmodel, xy, ntestpositions=100, psfradpix=3,
                     apradpix=3, skyannpix=None, skyalgorithm='sigmaclipping',
                     setskyval=None, recenter_target=True, recenter_fakes=True,
                     exptime=1, exact=True, ronoise=1, phpadu=1, verbose=False,
                     debug=False):
    """  Measure the flux and flux uncertainty for a source at the given x,y
    position using both aperture and psf-fitting photometry.

    Flux errors are measured by planting fake psfs or empty apertures into the
    sky annulus and recovering a distribution of fluxes with forced photometry.

    :param imagedat: target image numpy data array (with the star still there)
    :param psfmodel: psf model fits file or a 4-tuple with
           [gaussparam,lookuptable,psfmag,psfzpt]
    :param xy: x,y position of the center of the fake planting field
    :param ntestpositions: number of test positions for empty apertures
           and/or fake stars to use for determining the flux error empirically.
    :param psfradpix: radius to use for psf fitting, in pixels
    :param apradpix: radius of photometry aperture, in pixels
    :param skyannpix: inner and outer radius of sky annulus, in pixels
    :param skyalgorithm: algorithm to use for determining the sky value from
           the pixels within the sky annulus: 'sigmaclipping' or 'mmm'
    :param setskyval: if not None, use this value for the sky, ignoring
           the skyannulus
    :param recenter_target: use cntrd to locate the target center near the
           given xy position.
    :param recenter_fakes: recenter on each planted fake when recovering it
    :param exptime: exposure time of the image, for determining poisson noise
    :param ronoise: read-out noise, for determining aperture flux error
           analytically
    :param phpadu: photons-per-ADU, for determining aper flux err analytically
    :param verbose: turn verbosity on
    :param debug: enter pdb debugging mode
    :return: apflux, apfluxerr, psfflux, psffluxerr
             The flux measured through the given aperture and through
             psf fitting, along with associated errors.
    """
    if not np.any(skyannpix):
        skyannpix = [8, 15]

    # locate the target star center position
    x, y = xy
    if recenter_target:
        x, y = cntrd(imagedat, x, y, psfradpix)
        if x < 0 or y < 0:
            print("WARNING [photfunctions.py] : recentering failed")
            import pdb
            pdb.set_trace()

    # do aperture photometry directly on the source
    # (Note : using an arbitrary zeropoint of 25 here)
    aperout = aper(imagedat, x, y, phpadu=phpadu,
                   apr=apradpix, skyrad=skyannpix,
                   setskyval=setskyval,
                   zeropoint=25, exact=exact,
                   verbose=verbose, skyalgorithm=skyalgorithm,
                   debug=debug)
    apmag, apmagerr, apflux, apfluxerr, sky, skyerr, apbadflag, apoutstr = \
        aperout

    # define a set of test position points that uniformly samples the sky
    # annulus region, for planting empty apertures and/or fake stars
    rmin = float(skyannpix[0])
    rmax = float(skyannpix[1])
    u = np.random.uniform(rmin, rmax, ntestpositions)
    v = np.random.uniform(0, rmin + rmax, ntestpositions)
    r = np.where(v < u, u, rmax + rmin - u)
    theta = np.random.uniform(0, 2 * np.pi, ntestpositions)
    xtestpositions = r * np.cos(theta) + x
    ytestpositions = r * np.sin(theta) + y

    psfflux = psffluxerr = np.nan
    if psfmodel is not None:
        # set up the psf model realization
        gaussparam, lookuptable, psfmag, psfzpt = rdpsfmodel(psfmodel)
        psfmodel = [gaussparam, lookuptable, psfmag, psfzpt]
        pk = pkfit_class(imagedat, gaussparam, lookuptable, ronoise, phpadu)

        # do the psf fitting
        try:
            scale = pk.pkfit_fast_norecenter(1, x, y, sky, psfradpix)
            psfflux = scale * 10 ** (0.4 * (25. - psfmag))
        except RuntimeWarning:
            print("PythonPhot.pkfit_norecenter failed.")
            psfflux = np.nan

        if np.isfinite(psfflux):
            # remove the target star from the image
            imagedat = addtoimarray(imagedat, psfmodel, [x, y],
                                    fluxscale=-psfflux)

            # plant fakes and recover their fluxes with psf fitting
            # imdatsubarray = imagedat[y-rmax-2*psfradpix:y+rmax+2*psfradpix,
            #                x-rmax-2*psfradpix:x+rmax+2*psfradpix]
            fakecoordlist, fakefluxlist = [], []
            for xt, yt in zip(xtestpositions, ytestpositions):
                    # To ensure appropriate sampling of sub-pixel positions,
                    # we assign random sub-pixel offsets to each position.
                    xt = int(xt) + np.random.random()
                    yt = int(yt) + np.random.random()
                    fakefluxaper, fakefluxpsf, fakecoord = add_and_recover(
                        imagedat, psfmodel, [xt, yt], fluxscale=psfflux,
                        cleanup=True, psfradius=psfradpix, recenter=recenter_fakes)
                    if np.isfinite(fakefluxpsf):
                        fakecoordlist.append(fakecoord)
                        fakefluxlist.append(fakefluxpsf)
            fakefluxlist = np.array(fakefluxlist)
            fakefluxmean, fakefluxsigma = gaussian_fit_to_histogram(fakefluxlist)
            if abs(fakefluxmean - psfflux) > fakefluxsigma and verbose:
                print("WARNING: psf flux may be biased. Fake psf flux tests "
                      "found a significantly non-zero sky value not accounted for "
                      "in measurement of the target flux:  \\"
                      "Mean psf flux offset in sky annulus = %.3e\\" %
                      (fakefluxmean - psfflux) +
                      "sigma of fake flux distribution = %.3e" %
                      fakefluxsigma +
                      "NOTE: this is included as a systematic error, added in "
                      "quadrature to the psf flux err derived from fake psf "
                      "recovery.")
            psfflux_poissonerr = (poissonErr(psfflux * exptime, confidence=1) /
                                  exptime)
            # Total flux error is the quadratic sum of the poisson noise with
            # the systematic (shift) and statistical (dispersion) errors
            # inferred from fake psf planting and recovery
            psffluxerr = np.sqrt(psfflux_poissonerr**2 +
                                 (fakefluxmean - psfflux)**2 +
                                 fakefluxsigma**2)

    # drop down empty apertures and recover their fluxes with aperture phot
    # NOTE : if the star was removed for psf fitting, then we take advantage
    # of that to get aperture flux errors with the star gone.
    emptyaperout = aper(imagedat, np.array(xtestpositions),
                        np.array(ytestpositions), phpadu=phpadu,
                        apr=apradpix, setskyval=sky, zeropoint=25,
                        exact=False, verbose=verbose,
                        skyalgorithm=skyalgorithm, debug=debug)
    emptyapflux = emptyaperout[2]
    if np.any(np.isfinite(emptyapflux)):
        emptyapmeanflux, emptyapsigma = gaussian_fit_to_histogram(emptyapflux)
        emptyapbias = abs(emptyapmeanflux) - emptyapsigma
        if np.any(emptyapbias > 0) and verbose:
            print("WARNING: aperture flux may be biased. Empty aperture flux tests"
                  " found a significantly non-zero sky value not accounted for in "
                  "measurement of the target flux:  \\"
                  "Mean empty aperture flux in sky annulus = %s\\"
                  % emptyapmeanflux +
                  "sigma of empty aperture flux distribution = %s"
                  % emptyapsigma)
        if np.iterable(apflux):
            apflux_poissonerr = np.array(
                [poissonErr(fap * exptime, confidence=1) / exptime
                 for fap in apflux])
        else:
            apflux_poissonerr = (poissonErr(apflux * exptime, confidence=1) /
                                 exptime)
        apfluxerr = np.sqrt(apflux_poissonerr**2 +
                            emptyapbias**2 + emptyapsigma**2)

    else:
        if np.iterable(apradpix):
            apfluxerr = [np.nan for aprad in apradpix]
        else:
            apfluxerr = np.nan

    if psfmodel is not None and np.isfinite(psfflux):
        # return the target star back into the image
        imagedat = addtoimarray(imagedat, psfmodel, [x, y],
                                fluxscale=psfflux)

    if debug > 1:
        import pdb
        pdb.set_trace()

    return apflux, apfluxerr, psfflux, psffluxerr, sky, skyerr
コード例 #2
0
def add_and_recover(imagedat, psfmodel, xy, fluxscale=1, psfradius=5,
                    skyannpix=None, skyalgorithm='sigmaclipping',
                    setskyval=None, recenter=False, ronoise=1, phpadu=1,
                    cleanup=True, verbose=False, debug=False):
    """  Add a single fake star psf model to the image at the given position
    and flux scaling, re-measure the flux at that position and report it,
    Also deletes the planted psf from the imagedat array so that we don't
    pollute that image array.

    :param imagedat: target image numpy data array
    :param psfmodel: psf model fits file or tuple with [gaussparam,lookuptable]
    :param xy: x,y position for fake psf, using the IDL/python convention
        where [0,0] is the lower left corner.
    :param fluxscale: flux scaling to apply to the planted psf
    :param recenter: use cntrd to locate the center of the added psf, instead
        of relying on the input x,y position to define the psf fitting
    :param cleanup: remove the planted psf from the input imagedat array.
    :return:
    """
    if not skyannpix:
        skyannpix = [8, 15]

    # add the psf to the image data array
    imdatwithpsf = addtoimarray(imagedat, psfmodel, xy, fluxscale=fluxscale)

    # TODO: allow for uncertainty in the x,y positions

    gaussparam, lookuptable, psfmag, psfzpt = rdpsfmodel(psfmodel)

    # generate an instance of the pkfit class for this psf model
    # and target image
    pk = pkfit_class(imdatwithpsf, gaussparam, lookuptable, ronoise, phpadu)
    x, y = xy

    if debug:
        from .photfunctions import showpkfit
        from matplotlib import pyplot as pl, cm

        fig = pl.figure(3)
        showpkfit(imdatwithpsf, psfmodel, xy, 11, fluxscale, verbose=True)

        fig = pl.figure(1)
        pl.imshow(imdatwithpsf[y - 20:y + 20, x - 20:x + 20], cmap=cm.Greys,
                  interpolation='nearest')
        pl.colorbar()

        import pdb

        pdb.set_trace()

    if recenter:
        xc, yc = cntrd(imdatwithpsf, x, y, psfradius, verbose=verbose)
        if xc > 0 and yc > 0 and abs(xc - xy[0]) < 5 and abs(yc - xy[1]) < 5:
            x, y = xc, yc
    # do aperture photometry to get the sky
    aperout = aper(imdatwithpsf, x, y, phpadu=phpadu,
                   apr=psfradius * 3, skyrad=skyannpix,
                   setskyval=(setskyval is not None and setskyval),
                   zeropoint=psfzpt, exact=False,
                   verbose=verbose, skyalgorithm=skyalgorithm,
                   debug=debug)
    apmag, apmagerr, apflux, apfluxerr, sky, skyerr, apbadflag, apoutstr\
        = aperout

    # do the psf fitting
    try:
        scale = pk.pkfit_fast_norecenter(1, x, y, sky, psfradius)
        fluxpsf = scale * 10 ** (-0.4 * (psfmag - psfzpt))
    except RuntimeWarning:
        print("photfunctions.add_and_recover failed on RuntimeWarning")
        fluxpsf = -99
    if cleanup:
        # remove the fake psf from the image
        imagedat = addtoimarray(imdatwithpsf, psfmodel, xy,
                                fluxscale=-fluxscale)

    return apflux[0], fluxpsf, [x, y]