Exemplo n.º 1
0
def get_catalog_in_wcs(chipwcs,
                       catsurvey_north,
                       catsurvey_south=None,
                       resolve_dec=None,
                       margin=20):
    TT = []
    surveys = [(catsurvey_north, True)]
    if catsurvey_south is not None:
        surveys.append((catsurvey_south, False))

    for catsurvey, north in surveys:
        bricks = bricks_touching_wcs(chipwcs, survey=catsurvey)

        if resolve_dec is not None:
            from astrometry.util.starutil_numpy import radectolb
            bricks.gal_l, bricks.gal_b = radectolb(bricks.ra, bricks.dec)

        for b in bricks:
            # Skip bricks that are entirely on the wrong side of the resolve line (NGC only)
            if resolve_dec is not None and b.gal_b > 0:
                if north and b.dec2 <= resolve_dec:
                    continue
                if not (north) and b.dec1 >= resolve_dec:
                    continue
            # there is some overlap with this brick... read the catalog.
            fn = catsurvey.find_file('tractor', brick=b.brickname)
            if not os.path.exists(fn):
                print('WARNING: catalog', fn, 'does not exist.  Skipping!')
                continue
            print('Reading', fn)
            T = fits_table(fn,
                           columns=[
                               'ra', 'dec', 'brick_primary', 'type', 'release',
                               'brickid', 'brickname', 'objid', 'fracdev',
                               'flux_r', 'shapedev_r', 'shapedev_e1',
                               'shapedev_e2', 'shapeexp_r', 'shapeexp_e1',
                               'shapeexp_e2', 'ref_epoch', 'pmra', 'pmdec',
                               'parallax'
                           ])
            if resolve_dec is not None and b.gal_b > 0:
                if north:
                    T.cut(T.dec >= resolve_dec)
                    print('Cut to', len(T), 'north of the resolve line')
                else:
                    T.cut(T.dec < resolve_dec)
                    print('Cut to', len(T), 'south of the resolve line')
            ok, xx, yy = chipwcs.radec2pixelxy(T.ra, T.dec)
            W, H = chipwcs.get_width(), chipwcs.get_height()
            I, = np.nonzero((xx >= -margin) * (xx <= (W + margin)) *
                            (yy >= -margin) * (yy <= (H + margin)))
            T.cut(I)
            print('Cut to', len(T), 'sources within image + margin')
            T.cut(T.brick_primary)
            print('Cut to', len(T), 'on brick_primary')
            for col in ['out_of_bounds', 'left_blob']:
                if col in T.get_columns():
                    T.cut(T.get(col) == False)
                    print('Cut to', len(T), 'on', col)
            # drop DUP sources
            I, = np.nonzero([t.strip() != 'DUP' for t in T.type])
            T.cut(I)
            print('Cut to', len(T), 'after removing DUP')
            if len(T):
                TT.append(T)
    if len(TT) == 0:
        return None
    T = merge_tables(TT, columns='fillzero')
    T._header = TT[0]._header
    del TT
    print('Total of', len(T), 'catalog sources')

    # Fix up various failure modes:
    # FixedCompositeGalaxy(pos=RaDecPos[240.51147402832561, 10.385488075518923], brightness=NanoMaggies: g=(flux -2.87), r=(flux -5.26), z=(flux -7.65), fracDev=FracDev(0.60177207), shapeExp=re=3.78351e-44, e1=9.30367e-13, e2=1.24392e-16, shapeDev=re=inf, e1=-0, e2=-0)
    # -> convert to EXP
    I, = np.nonzero([
        t == 'COMP' and not np.isfinite(r)
        for t, r in zip(T.type, T.shapedev_r)
    ])
    if len(I):
        print('Converting', len(I), 'bogus COMP galaxies to EXP')
        for i in I:
            T.type[i] = 'EXP'

    # Same thing with the exp component.
    # -> convert to DEV
    I, = np.nonzero([
        t == 'COMP' and not np.isfinite(r)
        for t, r in zip(T.type, T.shapeexp_r)
    ])
    if len(I):
        print('Converting', len(I), 'bogus COMP galaxies to DEV')
        for i in I:
            T.type[i] = 'DEV'
    return T
Exemplo n.º 2
0
def run_one_ccd(survey, catsurvey_north, catsurvey_south, resolve_dec, ccd,
                opt, zoomslice, ps):
    tlast = Time()

    im = survey.get_image_object(ccd)

    if opt.do_calib:
        im.run_calibs(splinesky=True)

    tim = im.get_tractor_image(slc=zoomslice,
                               pixPsf=True,
                               splinesky=True,
                               constant_invvar=opt.constant_invvar,
                               hybridPsf=opt.hybrid_psf,
                               normalizePsf=opt.normalize_psf,
                               old_calibs_ok=True)
    print('Got tim:', tim, 'x0,y0', tim.x0, tim.y0)

    tnow = Time()
    print('Read image:', tnow - tlast)
    tlast = tnow

    # Apply outlier masks
    if True:
        # Outliers masks are computed within a survey (north/south for dr8), and are stored
        # in a brick-oriented way, in the results directories.
        north_ccd = (ccd.camera.strip() != 'decam')
        catsurvey = catsurvey_north
        if not north_ccd and catsurvey_south is not None:
            catsurvey = catsurvey_south
        chipwcs = tim.subwcs
        bricks = bricks_touching_wcs(chipwcs, survey=catsurvey)
        for b in bricks:
            from legacypipe.outliers import read_outlier_mask_file
            print('Reading outlier mask for brick', b.brickname)
            ok = read_outlier_mask_file(catsurvey, [tim],
                                        b.brickname,
                                        subimage=False,
                                        output=False,
                                        ps=ps)
            if not ok:
                print('WARNING: failed to read outliers mask file for brick',
                      b.brickname)

    if opt.catalog:
        T = fits_table(opt.catalog)
    else:
        chipwcs = tim.subwcs
        T = get_catalog_in_wcs(chipwcs,
                               catsurvey_north,
                               catsurvey_south=catsurvey_south,
                               resolve_dec=resolve_dec)
        if T is None:
            print('No sources to photometer.')
            return None
        if opt.write_cat:
            T.writeto(opt.write_cat)
            print('Wrote catalog to', opt.write_cat)

    surveydir = survey.get_survey_dir()
    del survey

    if opt.move_gaia:
        # Gaia stars: move RA,Dec to the epoch of this image.
        I = np.flatnonzero(T.ref_epoch > 0)
        if len(I):
            from legacypipe.survey import radec_at_mjd
            print('Moving', len(I), 'Gaia stars to MJD', tim.time.toMjd())
            ra, dec = radec_at_mjd(T.ra[I], T.dec[I],
                                   T.ref_epoch[I].astype(float), T.pmra[I],
                                   T.pmdec[I], T.parallax[I], tim.time.toMjd())
            T.ra[I] = ra
            T.dec[I] = dec

    tnow = Time()
    print('Read catalog:', tnow - tlast)
    tlast = tnow

    cat = read_fits_catalog(T, bands='r')
    # Replace the brightness (which will be a NanoMaggies with g,r,z)
    # with a NanoMaggies with this image's band only.
    for src in cat:
        src.brightness = NanoMaggies(**{tim.band: 1.})

    tnow = Time()
    print('Parse catalog:', tnow - tlast)
    tlast = tnow

    print('Forced photom...')
    F = run_forced_phot(cat,
                        tim,
                        ceres=opt.ceres,
                        derivs=opt.derivs,
                        fixed_also=True,
                        agn=opt.agn,
                        do_forced=opt.forced,
                        do_apphot=opt.apphot,
                        get_model=opt.save_model,
                        ps=ps,
                        timing=True,
                        ceres_threads=opt.ceres_threads)

    if opt.save_model:
        # unpack results
        F, model_img = F

    F.release = T.release
    F.brickid = T.brickid
    F.brickname = T.brickname
    F.objid = T.objid

    F.camera = np.array([ccd.camera] * len(F))
    F.expnum = np.array([im.expnum] * len(F)).astype(np.int64)
    F.ccdname = np.array([im.ccdname] * len(F))

    # "Denormalizing"
    F.filter = np.array([tim.band] * len(F))
    F.mjd = np.array([tim.primhdr['MJD-OBS']] * len(F))
    F.exptime = np.array([tim.primhdr['EXPTIME']] * len(F)).astype(np.float32)
    F.psfsize = np.array([tim.psf_fwhm * tim.imobj.pixscale] * len(F)).astype(
        np.float32)
    F.ccd_cuts = np.array([ccd.ccd_cuts] * len(F))
    F.airmass = np.array([ccd.airmass] * len(F))
    ### --> also add units to the dict below so the FITS headers have units
    F.sky = np.array([tim.midsky / tim.zpscale / tim.imobj.pixscale**2] *
                     len(F)).astype(np.float32)
    # in the same units as the depth maps -- flux inverse-variance.
    F.psfdepth = np.array([(1. / (tim.sig1 / tim.psfnorm)**2)] *
                          len(F)).astype(np.float32)
    F.galdepth = np.array([(1. / (tim.sig1 / tim.galnorm)**2)] *
                          len(F)).astype(np.float32)
    # F.psfdepth = np.array([-2.5 * (np.log10(5. * tim.sig1 / tim.psfnorm) - 9)] * len(F)).astype(np.float32)
    # F.galdepth = np.array([-2.5 * (np.log10(5. * tim.sig1 / tim.galnorm) - 9)] * len(F)).astype(np.float32)

    # super units questions here
    if opt.derivs:
        cosdec = np.cos(np.deg2rad(T.dec))
        F.dra = (F.flux_dra / F.flux) * 3600. / cosdec
        F.ddec = (F.flux_ddec / F.flux) * 3600.
        F.dra_ivar = F.flux_dra_ivar * (F.flux / 3600. * cosdec)**2
        F.ddec_ivar = F.flux_ddec_ivar * (F.flux / 3600.)**2
        F.delete_column('flux_dra')
        F.delete_column('flux_ddec')
        F.delete_column('flux_dra_ivar')
        F.delete_column('flux_ddec_ivar')
        F.flux = F.flux_fixed
        F.flux_ivar = F.flux_fixed_ivar
        F.delete_column('flux_fixed')
        F.delete_column('flux_fixed_ivar')

        for c in ['dra', 'ddec', 'dra_ivar', 'ddec_ivar', 'flux', 'flux_ivar']:
            F.set(c, F.get(c).astype(np.float32))

    F.ra = T.ra
    F.dec = T.dec

    ok, x, y = tim.sip_wcs.radec2pixelxy(T.ra, T.dec)
    F.x = (x - 1).astype(np.float32)
    F.y = (y - 1).astype(np.float32)

    h, w = tim.shape
    F.dqmask = tim.dq[np.clip(np.round(F.y).astype(int), 0, h - 1),
                      np.clip(np.round(F.x).astype(int), 0, w - 1)]

    program_name = sys.argv[0]
    ## FIXME -- from catalog?
    release = 8002
    version_hdr = get_version_header(program_name, surveydir, release)
    filename = getattr(ccd, 'image_filename')
    if filename is None:
        # HACK -- print only two directory names + filename of CPFILE.
        fname = os.path.basename(im.imgfn.strip())
        d = os.path.dirname(im.imgfn)
        d1 = os.path.basename(d)
        d = os.path.dirname(d)
        d2 = os.path.basename(d)
        filename = os.path.join(d2, d1, fname)
        print('Trimmed filename to', filename)
    version_hdr.add_record(
        dict(name='CPFILE', value=filename, comment='CP file'))
    version_hdr.add_record(dict(name='CPHDU', value=im.hdu, comment='CP ext'))
    version_hdr.add_record(
        dict(name='CAMERA', value=ccd.camera, comment='Camera'))
    version_hdr.add_record(
        dict(name='EXPNUM', value=im.expnum, comment='Exposure num'))
    version_hdr.add_record(
        dict(name='CCDNAME', value=im.ccdname, comment='CCD name'))
    version_hdr.add_record(
        dict(name='FILTER', value=tim.band, comment='Bandpass of this image'))
    version_hdr.add_record(
        dict(name='PLVER', value=ccd.plver, comment='CP pipeline version'))
    version_hdr.add_record(
        dict(name='PLPROCID', value=ccd.plprocid, comment='CP pipeline id'))
    version_hdr.add_record(
        dict(name='PROCDATE', value=ccd.procdate, comment='CP image DATE'))

    keys = [
        'TELESCOP', 'OBSERVAT', 'OBS-LAT', 'OBS-LONG', 'OBS-ELEV', 'INSTRUME'
    ]
    for key in keys:
        if key in tim.primhdr:
            version_hdr.add_record(dict(name=key, value=tim.primhdr[key]))

    if opt.save_model or opt.save_data:
        hdr = fitsio.FITSHDR()
        tim.getWcs().wcs.add_to_header(hdr)
    if opt.save_model:
        fitsio.write(opt.save_model, model_img, header=hdr, clobber=True)
        print('Wrote', opt.save_model)
    if opt.save_data:
        fitsio.write(opt.save_data, tim.getImage(), header=hdr, clobber=True)
        print('Wrote', opt.save_data)

    tnow = Time()
    print('Forced phot:', tnow - tlast)
    return F, version_hdr
Exemplo n.º 3
0
def run_one_ccd(survey, catsurvey_north, catsurvey_south, resolve_dec, ccd,
                opt, zoomslice, ps):
    from functools import reduce
    from legacypipe.bits import DQ_BITS

    tlast = Time()
    #print('Opt:', opt)
    im = survey.get_image_object(ccd)
    print('Run_one_ccd: checking cache', survey.cache_dir)
    if survey.cache_dir is not None:
        im.check_for_cached_files(survey)
    if opt.do_calib:
        im.run_calibs(splinesky=True)

    tim = im.get_tractor_image(slc=zoomslice,
                               pixPsf=True,
                               constant_invvar=opt.constant_invvar,
                               hybridPsf=opt.hybrid_psf,
                               normalizePsf=opt.normalize_psf,
                               old_calibs_ok=True,
                               trim_edges=False)
    print('Got tim:', tim)  #, 'x0,y0', tim.x0, tim.y0)
    chipwcs = tim.subwcs
    H, W = tim.shape

    tnow = Time()
    print('Read image:', tnow - tlast)
    tlast = tnow

    if ccd.camera == 'decam':
        # Halo subtraction
        from legacypipe.halos import subtract_one
        from legacypipe.reference import mask_radius_for_mag, read_gaia
        ref_margin = mask_radius_for_mag(0.)
        mpix = int(np.ceil(ref_margin * 3600. / chipwcs.pixel_scale()))
        marginwcs = chipwcs.get_subimage(-mpix, -mpix, W + 2 * mpix,
                                         H + 2 * mpix)
        gaia = read_gaia(marginwcs, None)
        keeprad = np.ceil(gaia.keep_radius * 3600. /
                          chipwcs.pixel_scale()).astype(int)
        _, xx, yy = chipwcs.radec2pixelxy(gaia.ra, gaia.dec)
        # cut to those touching the chip
        gaia.cut((xx > -keeprad) * (xx < W + keeprad) * (yy > -keeprad) *
                 (yy < H + keeprad))
        Igaia, = np.nonzero(gaia.isgaia * gaia.pointsource)
        halostars = gaia[Igaia]
        print('Got', len(gaia), 'Gaia stars,', len(halostars),
              'for halo subtraction')
        moffat = True
        halos = subtract_one((tim, halostars, moffat))
        tim.data -= halos

    # The "north" and "south" directories often don't have
    # 'survey-bricks" files of their own -- use the 'survey' one
    # instead.
    if catsurvey_south is not None:
        try:
            catsurvey_south.get_bricks_readonly()
        except:
            catsurvey_south.bricks = survey.get_bricks_readonly()
    if catsurvey_north is not None:
        try:
            catsurvey_north.get_bricks_readonly()
        except:
            catsurvey_north.bricks = survey.get_bricks_readonly()

    # Apply outlier masks
    outlier_header = None
    outlier_mask = None
    posneg_mask = None
    if opt.outlier_mask is not None:
        posneg_mask = np.zeros(tim.shape, np.uint8)
    # Outliers masks are computed within a survey (north/south for dr9), and are stored
    # in a brick-oriented way, in the results directories.
    north_ccd = (ccd.camera.strip() != 'decam')
    catsurvey = catsurvey_north
    if not north_ccd and catsurvey_south is not None:
        catsurvey = catsurvey_south
    bricks = bricks_touching_wcs(chipwcs, survey=catsurvey)
    for b in bricks:
        print(
            'Reading outlier mask for brick', b.brickname, ':',
            catsurvey.find_file('outliers_mask',
                                brick=b.brickname,
                                output=False))
        ok = read_outlier_mask_file(catsurvey, [tim],
                                    b.brickname,
                                    pos_neg_mask=posneg_mask,
                                    subimage=False,
                                    output=False,
                                    ps=ps)
        if not ok:
            print('WARNING: failed to read outliers mask file for brick',
                  b.brickname)

    if opt.outlier_mask is not None:
        outlier_mask = np.zeros((ccd.height, ccd.width), np.uint8)
        outlier_mask[tim.y0:tim.y0 + H, tim.x0:tim.x0 + W] = posneg_mask
        del posneg_mask
        # Grab original image headers (including WCS)
        im = survey.get_image_object(ccd)
        imhdr = im.read_image_header()
        imhdr['CAMERA'] = ccd.camera
        imhdr['EXPNUM'] = ccd.expnum
        imhdr['CCDNAME'] = ccd.ccdname
        imhdr['IMGFILE'] = ccd.image_filename.strip()
        outlier_header = imhdr

    if opt.catalog:
        T = fits_table(opt.catalog)
    else:
        chipwcs = tim.subwcs
        T = get_catalog_in_wcs(chipwcs,
                               survey,
                               catsurvey_north,
                               catsurvey_south=catsurvey_south,
                               resolve_dec=resolve_dec)
        if T is None:
            print('No sources to photometer.')
            return None
        if opt.write_cat:
            T.writeto(opt.write_cat)
            print('Wrote catalog to', opt.write_cat)

    surveydir = survey.get_survey_dir()
    del survey

    if opt.move_gaia:
        # Gaia stars: move RA,Dec to the epoch of this image.
        I = np.flatnonzero(T.ref_epoch > 0)
        if len(I):
            print('Moving', len(I), 'Gaia stars to MJD', tim.time.toMjd())
            ra, dec = radec_at_mjd(T.ra[I], T.dec[I],
                                   T.ref_epoch[I].astype(float), T.pmra[I],
                                   T.pmdec[I], T.parallax[I], tim.time.toMjd())
            T.ra[I] = ra
            T.dec[I] = dec

    tnow = Time()
    print('Read catalog:', tnow - tlast)
    tlast = tnow

    # Find SGA galaxies outside this chip and subtract them before we begin.
    chipwcs = tim.subwcs
    _, xx, yy = chipwcs.radec2pixelxy(T.ra, T.dec)
    W, H = chipwcs.get_width(), chipwcs.get_height()
    sga_out = (T.ref_cat == 'L3') * np.logical_not(
        (xx >= 1) * (xx <= W) * (yy >= 1) * (yy <= H))
    I = np.flatnonzero(sga_out)
    if len(I):
        print(len(I), 'SGA galaxies are outside the image.  Subtracting...')
        cat = read_fits_catalog(T[I], bands=[tim.band])
        tr = Tractor([tim], cat)
        mod = tr.getModelImage(0)
        tim.data -= mod
        I = np.flatnonzero(np.logical_not(sga_out))
        T.cut(I)

    cat = read_fits_catalog(T, bands='r')
    # Replace the brightness (which will be a NanoMaggies with g,r,z)
    # with a NanoMaggies with this image's band only.
    for src in cat:
        src.brightness = NanoMaggies(**{tim.band: 1.})

    tnow = Time()
    print('Parse catalog:', tnow - tlast)
    tlast = tnow

    print('Forced photom...')
    F = run_forced_phot(cat,
                        tim,
                        ceres=opt.ceres,
                        derivs=opt.derivs,
                        fixed_also=True,
                        agn=opt.agn,
                        do_forced=opt.forced,
                        do_apphot=opt.apphot,
                        get_model=opt.save_model,
                        ps=ps,
                        timing=True,
                        ceres_threads=opt.ceres_threads)

    if opt.save_model:
        # unpack results
        F, model_img = F

    F.release = T.release
    F.brickid = T.brickid
    F.brickname = T.brickname
    F.objid = T.objid

    F.camera = np.array([ccd.camera] * len(F))
    F.expnum = np.array([im.expnum] * len(F), dtype=np.int64)
    F.ccdname = np.array([im.ccdname] * len(F))

    # "Denormalizing"
    F.filter = np.array([tim.band] * len(F))
    F.mjd = np.array([tim.primhdr['MJD-OBS']] * len(F))
    F.exptime = np.array([tim.primhdr['EXPTIME']] * len(F), dtype=np.float32)
    F.psfsize = np.array([tim.psf_fwhm * tim.imobj.pixscale] * len(F),
                         dtype=np.float32)
    F.ccd_cuts = np.array([ccd.ccd_cuts] * len(F))
    F.airmass = np.array([ccd.airmass] * len(F), dtype=np.float32)
    ### --> also add units to the dict below so the FITS headers have units
    F.sky = np.array([tim.midsky / tim.zpscale / tim.imobj.pixscale**2] *
                     len(F),
                     dtype=np.float32)
    # in the same units as the depth maps -- flux inverse-variance.
    F.psfdepth = np.array([(1. / (tim.sig1 / tim.psfnorm)**2)] * len(F),
                          dtype=np.float32)
    F.galdepth = np.array([(1. / (tim.sig1 / tim.galnorm)**2)] * len(F),
                          dtype=np.float32)
    F.fwhm = np.array([tim.psf_fwhm] * len(F), dtype=np.float32)
    F.skyrms = np.array([ccd.skyrms] * len(F), dtype=np.float32)
    F.ccdzpt = np.array([ccd.ccdzpt] * len(F), dtype=np.float32)
    F.ccdrarms = np.array([ccd.ccdrarms] * len(F), dtype=np.float32)
    F.ccddecrms = np.array([ccd.ccddecrms] * len(F), dtype=np.float32)
    F.ccdphrms = np.array([ccd.ccdphrms] * len(F), dtype=np.float32)

    if opt.derivs:
        cosdec = np.cos(np.deg2rad(T.dec))
        with np.errstate(divide='ignore', invalid='ignore'):
            F.dra = (F.flux_dra / F.flux) * 3600. / cosdec
            F.ddec = (F.flux_ddec / F.flux) * 3600.
        F.dra[F.flux == 0] = 0.
        F.ddec[F.flux == 0] = 0.
        F.dra_ivar = F.flux_dra_ivar * (F.flux / 3600. * cosdec)**2
        F.ddec_ivar = F.flux_ddec_ivar * (F.flux / 3600.)**2
        F.delete_column('flux_dra')
        F.delete_column('flux_ddec')
        F.delete_column('flux_dra_ivar')
        F.delete_column('flux_ddec_ivar')
        F.flux = F.flux_fixed
        F.flux_ivar = F.flux_fixed_ivar
        F.delete_column('flux_fixed')
        F.delete_column('flux_fixed_ivar')

        for c in ['dra', 'ddec', 'dra_ivar', 'ddec_ivar', 'flux', 'flux_ivar']:
            F.set(c, F.get(c).astype(np.float32))

    F.ra = T.ra
    F.dec = T.dec

    _, x, y = tim.sip_wcs.radec2pixelxy(T.ra, T.dec)
    F.x = (x - 1).astype(np.float32)
    F.y = (y - 1).astype(np.float32)

    h, w = tim.shape
    ix = np.round(F.x).astype(int)
    iy = np.round(F.y).astype(int)
    F.dqmask = tim.dq[np.clip(iy, 0, h - 1), np.clip(ix, 0, w - 1)]
    # Set an OUT-OF-BOUNDS bit.
    F.dqmask[reduce(np.logical_or,
                    [ix < 0, ix >= w, iy < 0, iy >= h])] |= DQ_BITS['edge2']

    program_name = sys.argv[0]
    ## FIXME -- from catalog?
    release = 9999
    version_hdr = get_version_header(program_name, surveydir, release)
    filename = getattr(ccd, 'image_filename')
    if filename is None:
        # HACK -- print only two directory names + filename of CPFILE.
        fname = os.path.basename(im.imgfn.strip())
        d = os.path.dirname(im.imgfn)
        d1 = os.path.basename(d)
        d = os.path.dirname(d)
        d2 = os.path.basename(d)
        filename = os.path.join(d2, d1, fname)
        print('Trimmed filename to', filename)
    version_hdr.add_record(
        dict(name='CPFILE', value=filename, comment='CP file'))
    version_hdr.add_record(dict(name='CPHDU', value=im.hdu, comment='CP ext'))
    version_hdr.add_record(
        dict(name='CAMERA', value=ccd.camera, comment='Camera'))
    version_hdr.add_record(
        dict(name='EXPNUM', value=im.expnum, comment='Exposure num'))
    version_hdr.add_record(
        dict(name='CCDNAME', value=im.ccdname, comment='CCD name'))
    version_hdr.add_record(
        dict(name='FILTER', value=tim.band, comment='Bandpass of this image'))
    version_hdr.add_record(
        dict(name='PLVER', value=ccd.plver, comment='CP pipeline version'))
    version_hdr.add_record(
        dict(name='PLPROCID', value=ccd.plprocid, comment='CP pipeline id'))
    version_hdr.add_record(
        dict(name='PROCDATE', value=ccd.procdate, comment='CP image DATE'))

    keys = [
        'TELESCOP', 'OBSERVAT', 'OBS-LAT', 'OBS-LONG', 'OBS-ELEV', 'INSTRUME'
    ]
    for key in keys:
        if key in tim.primhdr:
            version_hdr.add_record(dict(name=key, value=tim.primhdr[key]))

    if opt.save_model or opt.save_data:
        hdr = fitsio.FITSHDR()
        tim.getWcs().wcs.add_to_header(hdr)
    if opt.save_model:
        fitsio.write(opt.save_model, model_img, header=hdr, clobber=True)
        print('Wrote', opt.save_model)
    if opt.save_data:
        fitsio.write(opt.save_data, tim.getImage(), header=hdr, clobber=True)
        print('Wrote', opt.save_data)

    tnow = Time()
    print('Forced phot:', tnow - tlast)
    return F, version_hdr, outlier_mask, outlier_header
Exemplo n.º 4
0
def get_catalog_in_wcs(chipwcs,
                       survey,
                       catsurvey_north,
                       catsurvey_south=None,
                       resolve_dec=None,
                       margin=20):
    TT = []
    surveys = [(catsurvey_north, True)]
    if catsurvey_south is not None:
        surveys.append((catsurvey_south, False))

    columns = [
        'ra',
        'dec',
        'brick_primary',
        'type',
        'release',
        'brickid',
        'brickname',
        'objid',
        'flux_g',
        'flux_r',
        'flux_z',
        'sersic',
        'shape_r',
        'shape_e1',
        'shape_e2',
        'ref_epoch',
        'pmra',
        'pmdec',
        'parallax',
        'ref_cat',
        'ref_id',
    ]

    for catsurvey, north in surveys:
        bricks = bricks_touching_wcs(chipwcs, survey=catsurvey)

        if resolve_dec is not None:
            from astrometry.util.starutil_numpy import radectolb
            bricks.gal_l, bricks.gal_b = radectolb(bricks.ra, bricks.dec)

        for b in bricks:
            # Skip bricks that are entirely on the wrong side of the resolve line (NGC only)
            if resolve_dec is not None:
                # Northern survey, brick too far south (max dec is below the resolve line)
                if north and b.dec2 <= resolve_dec:
                    continue
                # Southern survey, brick too far north (min dec is above the resolve line), but only in the North Galactic Cap
                if not (north) and b.dec1 >= resolve_dec and b.gal_b > 0:
                    continue
            # there is some overlap with this brick... read the catalog.
            fn = catsurvey.find_file('tractor', brick=b.brickname)
            if not os.path.exists(fn):
                print('WARNING: catalog', fn, 'does not exist.  Skipping!')
                continue
            print('Reading', fn)
            T = fits_table(fn, columns=columns)
            if resolve_dec is not None:
                if north:
                    T.cut(T.dec >= resolve_dec)
                    print('Cut to', len(T), 'north of the resolve line')
                elif b.gal_b > 0:
                    # Northern galactic cap only: cut Southern survey
                    T.cut(T.dec < resolve_dec)
                    print('Cut to', len(T), 'south of the resolve line')
            _, xx, yy = chipwcs.radec2pixelxy(T.ra, T.dec)
            W, H = chipwcs.get_width(), chipwcs.get_height()
            # Cut to sources that are inside the image+margin
            T.cut((xx >= -margin) * (xx <= (W + margin)) * (yy >= -margin) *
                  (yy <= (H + margin)))
            T.cut(T.brick_primary)
            #print('Cut to', len(T), 'on brick_primary')
            # drop DUP sources
            I, = np.nonzero([t.strip() != 'DUP' for t in T.type])
            T.cut(I)
            #print('Cut to', len(T), 'after removing DUP')
            if len(T):
                TT.append(T)
    if len(TT) == 0:
        return None
    T = merge_tables(TT, columns='fillzero')
    T._header = TT[0]._header
    del TT

    SGA = find_missing_sga(T, chipwcs, survey, surveys, columns)
    if SGA is not None:
        ## Add 'em in!
        T = merge_tables([T, SGA], columns='fillzero')
    print('Total of', len(T), 'catalog sources')
    return T
Exemplo n.º 5
0
def run_one_ccd(survey, catsurvey, ccd, opt, zoomslice, ps):
    tlast = Time()

    im = survey.get_image_object(ccd)

    if opt.do_calib:
        #from legacypipe.survey import run_calibs
        #kwa = dict(splinesky=True)
        #run_calibs((im, kwa))
        im.run_calibs(splinesky=True)

    tim = im.get_tractor_image(slc=zoomslice, pixPsf=True, splinesky=True,
                               constant_invvar=opt.constant_invvar,
                               hybridPsf=opt.hybrid_psf,
                               normalizePsf=opt.normalize_psf,
                               old_calibs_ok=True)
    print('Got tim:', tim)

    tnow = Time()
    print('Read image:', tnow-tlast)
    tlast = tnow

    if opt.catalog:
        T = fits_table(opt.catalog)
    else:
        margin = 20
        TT = []
        chipwcs = tim.subwcs
        bricks = bricks_touching_wcs(chipwcs, survey=catsurvey)
        for b in bricks:
            # there is some overlap with this brick... read the catalog.
            fn = catsurvey.find_file('tractor', brick=b.brickname)
            if not os.path.exists(fn):
                print('WARNING: catalog', fn, 'does not exist.  Skipping!')
                continue
            print('Reading', fn)
            T = fits_table(fn, columns=[
                'ra', 'dec', 'brick_primary', 'type', 'release',
                'brickid', 'brickname', 'objid',
                'fracdev', 'flux_r',
                'shapedev_r', 'shapedev_e1', 'shapedev_e2',
                'shapeexp_r', 'shapeexp_e1', 'shapeexp_e2',
                'ref_epoch', 'pmra', 'pmdec', 'parallax'
            ])
            ok,xx,yy = chipwcs.radec2pixelxy(T.ra, T.dec)
            W,H = chipwcs.get_width(), chipwcs.get_height()
            I = np.flatnonzero((xx >= -margin) * (xx <= (W+margin)) *
                               (yy >= -margin) * (yy <= (H+margin)))
            T.cut(I)
            print('Cut to', len(T), 'sources within image + margin')
            T.cut(T.brick_primary)
            print('Cut to', len(T), 'on brick_primary')
            for col in ['out_of_bounds', 'left_blob']:
                if col in T.get_columns():
                    T.cut(T.get(col) == False)
                    print('Cut to', len(T), 'on', col)
            if len(T):
                TT.append(T)
        if len(TT) == 0:
            print('No sources to photometer.')
            return None
        T = merge_tables(TT, columns='fillzero')
        T._header = TT[0]._header
        del TT
        print('Total of', len(T), 'catalog sources')

        # Fix up various failure modes:
        # FixedCompositeGalaxy(pos=RaDecPos[240.51147402832561, 10.385488075518923], brightness=NanoMaggies: g=(flux -2.87), r=(flux -5.26), z=(flux -7.65), fracDev=FracDev(0.60177207), shapeExp=re=3.78351e-44, e1=9.30367e-13, e2=1.24392e-16, shapeDev=re=inf, e1=-0, e2=-0)
        # -> convert to EXP
        I, = np.nonzero([t == 'COMP' and not np.isfinite(r) for t,r in zip(T.type, T.shapedev_r)])
        if len(I):
            print('Converting', len(I), 'bogus COMP galaxies to EXP')
            for i in I:
                T.type[i] = 'EXP'

        # Same thing with the exp component.
        # -> convert to DEV
        I, = np.nonzero([t == 'COMP' and not np.isfinite(r) for t,r in zip(T.type, T.shapeexp_r)])
        if len(I):
            print('Converting', len(I), 'bogus COMP galaxies to DEV')
            for i in I:
                T.type[i] = 'DEV'

        if opt.write_cat:
            T.writeto(opt.write_cat)
            print('Wrote catalog to', opt.write_cat)

    surveydir = survey.get_survey_dir()
    del survey

    if opt.move_gaia:
        # Gaia stars: move RA,Dec to the epoch of this image.
        I = np.flatnonzero(T.ref_epoch > 0)
        if len(I):
            from legacypipe.survey import radec_at_mjd
            print('Moving', len(I), 'Gaia stars to MJD', tim.time.toMjd())
            ra,dec = radec_at_mjd(T.ra[I], T.dec[I], T.ref_epoch[I].astype(float),
                                  T.pmra[I], T.pmdec[I], T.parallax[I],
                                  tim.time.toMjd())
            T.ra [I] = ra
            T.dec[I] = dec

    kwargs = {}
    cols = T.get_columns()
    if 'flux_r' in cols and not 'decam_flux_r' in cols:
        kwargs.update(fluxPrefix='')

    tnow = Time()
    print('Read catalog:', tnow-tlast)
    tlast = tnow

    cat = read_fits_catalog(T, bands='r', **kwargs)
    # Replace the brightness (which will be a NanoMaggies with g,r,z)
    # with a NanoMaggies with this image's band only.
    for src in cat:
        src.brightness = NanoMaggies(**{tim.band: 1.})

    tnow = Time()
    print('Parse catalog:', tnow-tlast)
    tlast = tnow

    print('Forced photom...')
    F = run_forced_phot(cat, tim,
                        ceres=opt.ceres,
                        derivs=opt.derivs,
                        fixed_also=True,
                        agn=opt.agn,
                        do_forced=opt.forced,
                        do_apphot=opt.apphot,
                        get_model=opt.save_model,
                        ps=ps)

    if opt.save_model:
        # unpack results
        F,model_img = F

    F.release   = T.release
    F.brickid   = T.brickid
    F.brickname = T.brickname
    F.objid     = T.objid

    F.camera  = np.array([ccd.camera] * len(F))
    F.expnum  = np.array([im.expnum]  * len(F)).astype(np.int32)
    F.ccdname = np.array([im.ccdname] * len(F))

    # "Denormalizing"
    F.filter  = np.array([tim.band]               * len(F))
    F.mjd     = np.array([tim.primhdr['MJD-OBS']] * len(F))
    F.exptime = np.array([tim.primhdr['EXPTIME']] * len(F)).astype(np.float32)
    F.psfsize = np.array([tim.psf_fwhm * tim.imobj.pixscale] * len(F)).astype(np.float32)
    #### FIXME -- units?
    ### --> also add units to the dict below so the FITS headers have units
    F.sky     = np.array([tim.midsky / tim.zpscale / tim.imobj.pixscale**2] * len(F)).astype(np.float32)
    # in the same units as the depth maps -- flux inverse-variance.
    F.psfdepth = np.array([(1. / (tim.sig1 / tim.psfnorm)**2)] * len(F)).astype(np.float32)
    F.galdepth = np.array([(1. / (tim.sig1 / tim.galnorm)**2)] * len(F)).astype(np.float32)
    # F.psfdepth = np.array([-2.5 * (np.log10(5. * tim.sig1 / tim.psfnorm) - 9)] * len(F)).astype(np.float32)
    # F.galdepth = np.array([-2.5 * (np.log10(5. * tim.sig1 / tim.galnorm) - 9)] * len(F)).astype(np.float32)

    # super units questions here
    if opt.derivs:
        cosdec = np.cos(np.deg2rad(T.dec))
        F.dra  = (F.flux_dra  / F.flux) * 3600. / cosdec
        F.ddec = (F.flux_ddec / F.flux) * 3600.
        F.dra_ivar  = F.flux_dra_ivar  * (F.flux / 3600. * cosdec)**2
        F.ddec_ivar = F.flux_ddec_ivar * (F.flux / 3600.)**2
        F.delete_column('flux_dra')
        F.delete_column('flux_ddec')
        F.delete_column('flux_dra_ivar')
        F.delete_column('flux_ddec_ivar')
        F.flux = F.flux_fixed
        F.flux_ivar = F.flux_fixed_ivar
        F.delete_column('flux_fixed')
        F.delete_column('flux_fixed_ivar')

        for c in ['dra', 'ddec', 'dra_ivar', 'ddec_ivar', 'flux', 'flux_ivar']:
            F.set(c, F.get(c).astype(np.float32))

    F.ra  = T.ra
    F.dec = T.dec

    ok,x,y = tim.sip_wcs.radec2pixelxy(T.ra, T.dec)
    F.x = (x-1).astype(np.float32)
    F.y = (y-1).astype(np.float32)

    ## FIXME -- read outlier_masks?

    h,w = tim.shape
    F.mask = tim.dq[np.clip(np.round(F.y).astype(int), 0, h-1),
                    np.clip(np.round(F.x).astype(int), 0, w-1)]

    program_name = sys.argv[0]
    ## FIXME -- from catalog?
    release = 0
    version_hdr = get_version_header(program_name, surveydir, release)
    filename = getattr(ccd, 'image_filename')
    if filename is None:
        # HACK -- print only two directory names + filename of CPFILE.
        fname = os.path.basename(im.imgfn.strip())
        d = os.path.dirname(im.imgfn)
        d1 = os.path.basename(d)
        d = os.path.dirname(d)
        d2 = os.path.basename(d)
        filename = os.path.join(d2, d1, fname)
        print('Trimmed filename to', filename)
    version_hdr.add_record(dict(name='CPFILE', value=filename, comment='CP file'))
    version_hdr.add_record(dict(name='CPHDU', value=im.hdu, comment='CP ext'))
    version_hdr.add_record(dict(name='CAMERA', value=ccd.camera, comment='Camera'))
    version_hdr.add_record(dict(name='EXPNUM', value=im.expnum, comment='Exposure num'))
    version_hdr.add_record(dict(name='CCDNAME', value=im.ccdname, comment='CCD name'))
    version_hdr.add_record(dict(name='FILTER', value=tim.band, comment='Bandpass of this image'))
    version_hdr.add_record(dict(name='EXPOSURE',
                                value='%s-%s-%s' % (ccd.camera, im.expnum, im.ccdname),
                                comment='Name of this image'))
    version_hdr.add_record(dict(name='PLVER', value=ccd.plver, comment='CP pipeline version'))
    version_hdr.add_record(dict(name='PROCDATE', value=ccd.procdate, comment='CP image DATE'))

    keys = ['TELESCOP','OBSERVAT','OBS-LAT','OBS-LONG','OBS-ELEV',
            'INSTRUME']
    for key in keys:
        if key in tim.primhdr:
            version_hdr.add_record(dict(name=key, value=tim.primhdr[key]))

    if opt.save_model or opt.save_data:
        hdr = fitsio.FITSHDR()
        tim.getWcs().wcs.add_to_header(hdr)
    if opt.save_model:
        fitsio.write(opt.save_model, model_img, header=hdr, clobber=True)
        print('Wrote', opt.save_model)
    if opt.save_data:
        fitsio.write(opt.save_data, tim.getImage(), header=hdr, clobber=True)
        print('Wrote', opt.save_data)

    tnow = Time()
    print('Forced phot:', tnow-tlast)
    return F,version_hdr
def main(survey=None, opt=None):
    '''Driver function for forced photometry of individual DECam images.
    '''
    if opt is None:
        parser = get_parser()
        opt = parser.parse_args()

    Time.add_measurement(MemMeas)
    t0 = Time()

    if os.path.exists(opt.outfn):
        print('Ouput file exists:', opt.outfn)
        sys.exit(0)

    if not opt.forced:
        opt.apphot = True

    zoomslice = None
    if opt.zoom is not None:
        (x0,x1,y0,y1) = opt.zoom
        zoomslice = (slice(y0,y1), slice(x0,x1))

    ps = None
    if opt.plots is not None:
        from astrometry.util.plotutils import PlotSequence
        ps = PlotSequence(opt.plots)

    # Try parsing filename as exposure number.
    try:
        expnum = int(opt.filename)
        opt.filename = None
    except:
        # make this 'None' for survey.find_ccds()
        expnum = None

    # Try parsing HDU number
    try:
        opt.hdu = int(opt.hdu)
        ccdname = None
    except:
        ccdname = opt.hdu
        opt.hdu = -1

    if survey is None:
        survey = LegacySurveyData()

    if opt.filename is not None and opt.hdu >= 0:
        # Read metadata from file
        T = exposure_metadata([opt.filename], hdus=[opt.hdu])
        print('Metadata:')
        T.about()
    else:
        # Read metadata from survey-ccds.fits table
        T = survey.find_ccds(expnum=expnum, ccdname=ccdname)
        print(len(T), 'with expnum', expnum, 'and CCDname', ccdname)
        if opt.hdu >= 0:
            T.cut(T.image_hdu == opt.hdu)
            print(len(T), 'with HDU', opt.hdu)
        if opt.filename is not None:
            T.cut(np.array([f.strip() == opt.filename for f in T.image_filename]))
            print(len(T), 'with filename', opt.filename)
        assert(len(T) == 1)

    ccd = T[0]
    im = survey.get_image_object(ccd)
    tim = im.get_tractor_image(slc=zoomslice, pixPsf=True, splinesky=True,
                               constant_invvar=opt.constant_invvar)
    print('Got tim:', tim)

    print('Read image:', Time()-t0)

    if opt.catfn in ['DR1', 'DR2', 'DR3']:

        margin = 20
        TT = []
        chipwcs = tim.subwcs
        bricks = bricks_touching_wcs(chipwcs, survey=survey)
        for b in bricks:
            # there is some overlap with this brick... read the catalog.
            fn = survey.find_file('tractor', brick=b.brickname)
            if not os.path.exists(fn):
                print('WARNING: catalog', fn, 'does not exist.  Skipping!')
                continue
            print('Reading', fn)
            T = fits_table(fn)
            ok,xx,yy = chipwcs.radec2pixelxy(T.ra, T.dec)
            W,H = chipwcs.get_width(), chipwcs.get_height()
            I = np.flatnonzero((xx >= -margin) * (xx <= (W+margin)) *
                               (yy >= -margin) * (yy <= (H+margin)))
            T.cut(I)
            print('Cut to', len(T), 'sources within image + margin')
            # print('Brick_primary:', np.unique(T.brick_primary))
            T.cut(T.brick_primary)
            print('Cut to', len(T), 'on brick_primary')
            T.cut((T.out_of_bounds == False) * (T.left_blob == False))
            print('Cut to', len(T), 'on out_of_bounds and left_blob')
            if len(T):
                TT.append(T)
        if len(TT) == 0:
            print('No sources to photometer.')
            return 0
        T = merge_tables(TT, columns='fillzero')
        T._header = TT[0]._header
        del TT

        # Fix up various failure modes:
        # FixedCompositeGalaxy(pos=RaDecPos[240.51147402832561, 10.385488075518923], brightness=NanoMaggies: g=(flux -2.87), r=(flux -5.26), z=(flux -7.65), fracDev=FracDev(0.60177207), shapeExp=re=3.78351e-44, e1=9.30367e-13, e2=1.24392e-16, shapeDev=re=inf, e1=-0, e2=-0)
        # -> convert to EXP
        I = np.flatnonzero(np.array([((t.type == 'COMP') and
                                      (not np.isfinite(t.shapedev_r)))
                                     for t in T]))
        if len(I):
            print('Converting', len(I), 'bogus COMP galaxies to EXP')
            for i in I:
                T.type[i] = 'EXP'

        # Same thing with the exp component.
        # -> convert to DEV
        I = np.flatnonzero(np.array([((t.type == 'COMP') and
                                      (not np.isfinite(t.shapeexp_r)))
                                     for t in T]))
        if len(I):
            print('Converting', len(I), 'bogus COMP galaxies to DEV')
            for i in I:
                T.type[i] = 'DEV'

        if opt.write_cat:
            T.writeto(opt.write_cat)
            print('Wrote catalog to', opt.write_cat)

    else:
        T = fits_table(opt.catfn)

    surveydir = survey.get_survey_dir()
    del survey
        
    cat = read_fits_catalog(T)
    # print('Got cat:', cat)

    print('Read catalog:', Time()-t0)

    print('Forced photom...')
    opti = None
    forced_kwargs = {}
    if opt.ceres:
        from tractor.ceres_optimizer import CeresOptimizer
        B = 8
        opti = CeresOptimizer(BW=B, BH=B)
        #forced_kwargs.update(verbose=True)

    for src in cat:
        # Limit sizes of huge models
        from tractor.galaxy import ProfileGalaxy
        if isinstance(src, ProfileGalaxy):
            px,py = tim.wcs.positionToPixel(src.getPosition())
            h = src._getUnitFluxPatchSize(tim, px, py, tim.modelMinval)
            MAXHALF = 128
            if h > MAXHALF:
                print('halfsize', h,'for',src,'-> setting to',MAXHALF)
                src.halfsize = MAXHALF
        
    tr = Tractor([tim], cat, optimizer=opti)
    tr.freezeParam('images')
    for src in cat:
        src.freezeAllBut('brightness')
        src.getBrightness().freezeAllBut(tim.band)
    disable_galaxy_cache()
        
    F = fits_table()
    F.brickid   = T.brickid
    F.brickname = T.brickname
    F.objid     = T.objid

    F.filter  = np.array([tim.band]               * len(T))
    F.mjd     = np.array([tim.primhdr['MJD-OBS']] * len(T))
    F.exptime = np.array([tim.primhdr['EXPTIME']] * len(T)).astype(np.float32)

    ok,x,y = tim.sip_wcs.radec2pixelxy(T.ra, T.dec)
    F.x = (x-1).astype(np.float32)
    F.y = (y-1).astype(np.float32)

    if opt.forced:
        if opt.plots is None:
            forced_kwargs.update(wantims=False)

        R = tr.optimize_forced_photometry(variance=True, fitstats=True,
                                          shared_params=False, priors=False, **forced_kwargs)

        if opt.plots:
            (data,mod,ie,chi,roi) = R.ims1[0]

            ima = tim.ima
            imchi = dict(interpolation='nearest', origin='lower', vmin=-5, vmax=5)
            plt.clf()
            plt.imshow(data, **ima)
            plt.title('Data: %s' % tim.name)
            ps.savefig()

            plt.clf()
            plt.imshow(mod, **ima)
            plt.title('Model: %s' % tim.name)
            ps.savefig()

            plt.clf()
            plt.imshow(chi, **imchi)
            plt.title('Chi: %s' % tim.name)
            ps.savefig()

        F.flux = np.array([src.getBrightness().getFlux(tim.band)
                           for src in cat]).astype(np.float32)
        F.flux_ivar = R.IV.astype(np.float32)

        F.fracflux = R.fitstats.profracflux.astype(np.float32)
        F.rchi2    = R.fitstats.prochi2    .astype(np.float32)

        print('Forced photom:', Time()-t0)

        
    if opt.apphot:
        import photutils

        img = tim.getImage()
        ie = tim.getInvError()
        with np.errstate(divide='ignore'):
            imsigma = 1. / ie
        imsigma[ie == 0] = 0.

        apimg = []
        apimgerr = []

        # Aperture photometry locations
        xxyy = np.vstack([tim.wcs.positionToPixel(src.getPosition()) for src in cat]).T
        apxy = xxyy - 1.

        apertures = apertures_arcsec / tim.wcs.pixel_scale()
        print('Apertures:', apertures, 'pixels')

        for rad in apertures:
            aper = photutils.CircularAperture(apxy, rad)
            p = photutils.aperture_photometry(img, aper, error=imsigma)
            apimg.append(p.field('aperture_sum'))
            apimgerr.append(p.field('aperture_sum_err'))
        ap = np.vstack(apimg).T
        ap[np.logical_not(np.isfinite(ap))] = 0.
        F.apflux = ap.astype(np.float32)
        ap = 1./(np.vstack(apimgerr).T)**2
        ap[np.logical_not(np.isfinite(ap))] = 0.
        F.apflux_ivar = ap.astype(np.float32)
        print('Aperture photom:', Time()-t0)

    program_name = sys.argv[0]
    version_hdr = get_version_header(program_name, surveydir)
    filename = getattr(ccd, 'image_filename')
    if filename is None:
        # HACK -- print only two directory names + filename of CPFILE.
        fname = os.path.basename(im.imgfn)
        d = os.path.dirname(im.imgfn)
        d1 = os.path.basename(d)
        d = os.path.dirname(d)
        d2 = os.path.basename(d)
        filename = os.path.join(d2, d1, fname)
        print('Trimmed filename to', filename)
    version_hdr.add_record(dict(name='CPFILE', value=filename, comment='CP file'))
    version_hdr.add_record(dict(name='CPHDU', value=im.hdu, comment='CP ext'))
    version_hdr.add_record(dict(name='CAMERA', value=ccd.camera, comment='Camera'))
    version_hdr.add_record(dict(name='EXPNUM', value=im.expnum, comment='Exposure num'))
    version_hdr.add_record(dict(name='CCDNAME', value=im.ccdname, comment='CCD name'))
    version_hdr.add_record(dict(name='FILTER', value=tim.band, comment='Bandpass of this image'))
    version_hdr.add_record(dict(name='EXPOSURE',
                                value='%s-%s-%s' % (ccd.camera, im.expnum, im.ccdname),
                                comment='Name of this image'))

    keys = ['TELESCOP','OBSERVAT','OBS-LAT','OBS-LONG','OBS-ELEV',
            'INSTRUME']
    for key in keys:
        if key in tim.primhdr:
            version_hdr.add_record(dict(name=key, value=tim.primhdr[key]))

    hdr = fitsio.FITSHDR()
    units = {'exptime':'sec', 'flux':'nanomaggy', 'flux_ivar':'1/nanomaggy^2'}
    columns = F.get_columns()
    for i,col in enumerate(columns):
        if col in units:
            hdr.add_record(dict(name='TUNIT%i' % (i+1), value=units[col]))

    outdir = os.path.dirname(opt.outfn)
    if len(outdir):
        trymakedirs(outdir)
    fitsio.write(opt.outfn, None, header=version_hdr, clobber=True)
    F.writeto(opt.outfn, header=hdr, append=True)
    print('Wrote', opt.outfn)
    
    if opt.save_model or opt.save_data:
        hdr = fitsio.FITSHDR()
        tim.getWcs().wcs.add_to_header(hdr)
    if opt.save_model:
        print('Getting model image...')
        mod = tr.getModelImage(tim)
        fitsio.write(opt.save_model, mod, header=hdr, clobber=True)
        print('Wrote', opt.save_model)
    if opt.save_data:
        fitsio.write(opt.save_data, tim.getImage(), header=hdr, clobber=True)
        print('Wrote', opt.save_data)
    
    print('Finished forced phot:', Time()-t0)
    return 0
Exemplo n.º 7
0
def main(survey=None, opt=None):
    '''Driver function for forced photometry of individual Legacy
    Survey images.
    '''
    if opt is None:
        parser = get_parser()
        opt = parser.parse_args()

    Time.add_measurement(MemMeas)
    t0 = Time()

    if os.path.exists(opt.outfn):
        print('Ouput file exists:', opt.outfn)
        sys.exit(0)

    if opt.derivs and opt.agn:
        print('Sorry, can\'t do --derivs AND --agn')
        sys.exit(0)

    if not opt.forced:
        opt.apphot = True

    zoomslice = None
    if opt.zoom is not None:
        (x0, x1, y0, y1) = opt.zoom
        zoomslice = (slice(y0, y1), slice(x0, x1))

    ps = None
    if opt.plots is not None:
        import pylab as plt
        from astrometry.util.plotutils import PlotSequence
        ps = PlotSequence(opt.plots)

    # Try parsing filename as exposure number.
    try:
        expnum = int(opt.expnum)
        filename = None
    except:
        # make this 'None' for survey.find_ccds()
        expnum = None
        filename = opt.expnum

    # Try parsing HDU number
    try:
        hdu = int(opt.ccdname)
        ccdname = None
    except:
        hdu = -1
        ccdname = opt.ccdname

    if survey is None:
        survey = LegacySurveyData()

    catsurvey = survey
    if opt.catalog_dir is not None:
        catsurvey = LegacySurveyData(survey_dir=opt.catalog_dir)

    if filename is not None and hdu >= 0:
        # FIXME -- try looking up in CCDs file?
        # Read metadata from file
        print('Warning: faking metadata from file contents')
        T = exposure_metadata([filename], hdus=[hdu])
        print('Metadata:')
        T.about()

        if not 'ccdzpt' in T.columns():
            phdr = fitsio.read_header(filename)
            T.ccdzpt = np.array([phdr['MAGZERO']])
            print('WARNING: using header MAGZERO')
            T.ccdraoff = np.array([0.])
            T.ccddecoff = np.array([0.])
            print('WARNING: setting CCDRAOFF, CCDDECOFF to zero.')

    else:
        # Read metadata from survey-ccds.fits table
        T = survey.find_ccds(expnum=expnum, ccdname=ccdname)
        print(len(T), 'with expnum', expnum, 'and CCDname', ccdname)
        if hdu >= 0:
            T.cut(T.image_hdu == hdu)
            print(len(T), 'with HDU', hdu)
        if filename is not None:
            T.cut(np.array([f.strip() == filename for f in T.image_filename]))
            print(len(T), 'with filename', filename)
        if opt.camera is not None:
            T.cut(T.camera == opt.camera)
            print(len(T), 'with camera', opt.camera)
        assert (len(T) == 1)

    ccd = T[0]
    im = survey.get_image_object(ccd)

    if opt.do_calib:
        #from legacypipe.survey import run_calibs
        #kwa = dict(splinesky=True)
        #run_calibs((im, kwa))
        im.run_calibs(splinesky=True)

    tim = im.get_tractor_image(slc=zoomslice,
                               pixPsf=True,
                               splinesky=True,
                               constant_invvar=opt.constant_invvar,
                               hybridPsf=opt.hybrid_psf,
                               normalizePsf=opt.normalize_psf)
    print('Got tim:', tim)

    print('Read image:', Time() - t0)

    if opt.catfn in ['DR1', 'DR2', 'DR3', 'DR5', 'DR']:

        margin = 20
        TT = []
        chipwcs = tim.subwcs
        bricks = bricks_touching_wcs(chipwcs, survey=catsurvey)
        for b in bricks:
            # there is some overlap with this brick... read the catalog.
            fn = catsurvey.find_file('tractor', brick=b.brickname)
            if not os.path.exists(fn):
                print('WARNING: catalog', fn, 'does not exist.  Skipping!')
                continue
            print('Reading', fn)
            T = fits_table(fn)
            ok, xx, yy = chipwcs.radec2pixelxy(T.ra, T.dec)
            W, H = chipwcs.get_width(), chipwcs.get_height()
            I = np.flatnonzero((xx >= -margin) * (xx <= (W + margin)) *
                               (yy >= -margin) * (yy <= (H + margin)))
            T.cut(I)
            print('Cut to', len(T), 'sources within image + margin')
            # print('Brick_primary:', np.unique(T.brick_primary))
            T.cut(T.brick_primary)
            print('Cut to', len(T), 'on brick_primary')
            for col in ['out_of_bounds', 'left_blob']:
                if col in T.get_columns():
                    T.cut(T.get(col) == False)
                    print('Cut to', len(T), 'on', col)
            if len(T):
                TT.append(T)
        if len(TT) == 0:
            print('No sources to photometer.')
            return 0
        T = merge_tables(TT, columns='fillzero')
        T._header = TT[0]._header
        del TT
        print('Total of', len(T), 'catalog sources')

        # Fix up various failure modes:
        # FixedCompositeGalaxy(pos=RaDecPos[240.51147402832561, 10.385488075518923], brightness=NanoMaggies: g=(flux -2.87), r=(flux -5.26), z=(flux -7.65), fracDev=FracDev(0.60177207), shapeExp=re=3.78351e-44, e1=9.30367e-13, e2=1.24392e-16, shapeDev=re=inf, e1=-0, e2=-0)
        # -> convert to EXP
        I = np.flatnonzero(
            np.array([((t.type == 'COMP') and (not np.isfinite(t.shapedev_r)))
                      for t in T]))
        if len(I):
            print('Converting', len(I), 'bogus COMP galaxies to EXP')
            for i in I:
                T.type[i] = 'EXP'

        # Same thing with the exp component.
        # -> convert to DEV
        I = np.flatnonzero(
            np.array([((t.type == 'COMP') and (not np.isfinite(t.shapeexp_r)))
                      for t in T]))
        if len(I):
            print('Converting', len(I), 'bogus COMP galaxies to DEV')
            for i in I:
                T.type[i] = 'DEV'

        if opt.write_cat:
            T.writeto(opt.write_cat)
            print('Wrote catalog to', opt.write_cat)

    else:
        T = fits_table(opt.catfn)

    surveydir = survey.get_survey_dir()
    del survey

    kwargs = {}
    cols = T.get_columns()
    if 'flux_r' in cols and not 'decam_flux_r' in cols:
        kwargs.update(fluxPrefix='')
    cat = read_fits_catalog(T, **kwargs)
    # Replace the brightness (which will be a NanoMaggies with g,r,z)
    # with a NanoMaggies with this image's band only.
    for src in cat:
        src.brightness = NanoMaggies(**{tim.band: 1.})

    print('Read catalog:', Time() - t0)

    print('Forced photom...')
    F = run_forced_phot(cat,
                        tim,
                        ceres=opt.ceres,
                        derivs=opt.derivs,
                        fixed_also=True,
                        agn=opt.agn,
                        do_forced=opt.forced,
                        do_apphot=opt.apphot,
                        ps=ps)
    t0 = Time()

    F.release = T.release
    F.brickid = T.brickid
    F.brickname = T.brickname
    F.objid = T.objid

    F.camera = np.array([ccd.camera] * len(F))
    F.expnum = np.array([im.expnum] * len(F)).astype(np.int32)
    F.ccdname = np.array([im.ccdname] * len(F))

    # "Denormalizing"
    F.filter = np.array([tim.band] * len(T))
    F.mjd = np.array([tim.primhdr['MJD-OBS']] * len(T))
    F.exptime = np.array([tim.primhdr['EXPTIME']] * len(T)).astype(np.float32)
    F.ra = T.ra
    F.dec = T.dec

    ok, x, y = tim.sip_wcs.radec2pixelxy(T.ra, T.dec)
    F.x = (x - 1).astype(np.float32)
    F.y = (y - 1).astype(np.float32)

    h, w = tim.shape
    F.mask = tim.dq[np.clip(np.round(F.y).astype(int), 0, h - 1),
                    np.clip(np.round(F.x).astype(int), 0, w - 1)]

    program_name = sys.argv[0]
    version_hdr = get_version_header(program_name, surveydir)
    filename = getattr(ccd, 'image_filename')
    if filename is None:
        # HACK -- print only two directory names + filename of CPFILE.
        fname = os.path.basename(im.imgfn)
        d = os.path.dirname(im.imgfn)
        d1 = os.path.basename(d)
        d = os.path.dirname(d)
        d2 = os.path.basename(d)
        filename = os.path.join(d2, d1, fname)
        print('Trimmed filename to', filename)
    version_hdr.add_record(
        dict(name='CPFILE', value=filename, comment='CP file'))
    version_hdr.add_record(dict(name='CPHDU', value=im.hdu, comment='CP ext'))
    version_hdr.add_record(
        dict(name='CAMERA', value=ccd.camera, comment='Camera'))
    version_hdr.add_record(
        dict(name='EXPNUM', value=im.expnum, comment='Exposure num'))
    version_hdr.add_record(
        dict(name='CCDNAME', value=im.ccdname, comment='CCD name'))
    version_hdr.add_record(
        dict(name='FILTER', value=tim.band, comment='Bandpass of this image'))
    version_hdr.add_record(
        dict(name='EXPOSURE',
             value='%s-%s-%s' % (ccd.camera, im.expnum, im.ccdname),
             comment='Name of this image'))

    keys = [
        'TELESCOP', 'OBSERVAT', 'OBS-LAT', 'OBS-LONG', 'OBS-ELEV', 'INSTRUME'
    ]
    for key in keys:
        if key in tim.primhdr:
            version_hdr.add_record(dict(name=key, value=tim.primhdr[key]))

    hdr = fitsio.FITSHDR()
    units = {
        'exptime': 'sec',
        'flux': 'nanomaggy',
        'flux_ivar': '1/nanomaggy^2'
    }
    columns = F.get_columns()
    for i, col in enumerate(columns):
        if col in units:
            hdr.add_record(dict(name='TUNIT%i' % (i + 1), value=units[col]))

    outdir = os.path.dirname(opt.outfn)
    if len(outdir):
        trymakedirs(outdir)
    fitsio.write(opt.outfn, None, header=version_hdr, clobber=True)
    F.writeto(opt.outfn, header=hdr, append=True)
    print('Wrote', opt.outfn)

    if opt.save_model or opt.save_data:
        hdr = fitsio.FITSHDR()
        tim.getWcs().wcs.add_to_header(hdr)
    if opt.save_model:
        print('Getting model image...')
        tr = Tractor([tim], cat)
        mod = tr.getModelImage(tim)
        fitsio.write(opt.save_model, mod, header=hdr, clobber=True)
        print('Wrote', opt.save_model)
    if opt.save_data:
        fitsio.write(opt.save_data, tim.getImage(), header=hdr, clobber=True)
        print('Wrote', opt.save_data)

    print('Finished forced phot:', Time() - t0)
    return 0