Ejemplo n.º 1
0
def get_healpixes_touching_wcs(tan, nside=None, topscale=256.):
    '''
    tan: TanWCS database object.
    '''
    from astrometry.util.starutil_numpy import degrees_between

    if nside is None:
        # print 'Pixscale', tan.get_pixscale()
        nside = 2 ** int(np.round(np.log2(topscale / tan.get_pixscale())))
        # print 'Nside', nside
        nside = int(np.clip(nside, 1, 2**10))
        # print 'Nside', nside

    r1,d1 = healpix_to_radecdeg(0, nside, 0., 0.)
    r2,d2 = healpix_to_radecdeg(0, nside, 0.5, 0.5)
    hpradius = degrees_between(r1,d1, r2,d2)
    # HACK -- padding for squished parallelograms
    hpradius *= 1.5

    r,d,radius = tan.get_center_radecradius()
    radius = np.hypot(radius, hpradius)
    hh = healpix_rangesearch_radec(r, d, radius, nside)
    hh.sort()
    #print 'Healpixes:', hh
    return (nside, hh)
Ejemplo n.º 2
0
def get_healpixes_touching_wcs(tan, nside=None, topscale=256.):
    '''
    tan: TanWCS database object.
    '''
    from astrometry.util.starutil_numpy import degrees_between

    if nside is None:
        # print 'Pixscale', tan.get_pixscale()
        nside = 2**int(np.round(np.log2(topscale / tan.get_pixscale())))
        # print 'Nside', nside
        nside = int(np.clip(nside, 1, 2**10))
        # print 'Nside', nside

    r1, d1 = healpix_to_radecdeg(0, nside, 0., 0.)
    r2, d2 = healpix_to_radecdeg(0, nside, 0.5, 0.5)
    hpradius = degrees_between(r1, d1, r2, d2)
    # HACK -- padding for squished parallelograms
    hpradius *= 1.5

    r, d, radius = tan.get_center_radecradius()
    radius = np.hypot(radius, hpradius)
    hh = healpix_rangesearch_radec(r, d, radius, nside)
    hh.sort()
    #print 'Healpixes:', hh
    return (nside, hh)
Ejemplo n.º 3
0
def ccds_touching_wcs(targetwcs, T, ccdrad=0.17, polygons=True):
    '''
    targetwcs: wcs object describing region of interest
    T: fits_table object of CCDs

    ccdrad: radius of CCDs, in degrees.  Default 0.17 is for DECam.
    #If None, computed from T.

    Returns: index array I of CCDs within range.
    '''
    trad = targetwcs.radius()
    if ccdrad is None:
        ccdrad = max(np.sqrt(np.abs(T.cd1_1 * T.cd2_2 - T.cd1_2 * T.cd2_1)) *
                     np.hypot(T.width, T.height) / 2.)

    rad = trad + ccdrad
    #r,d = targetwcs.crval
    r,d = targetwcs.radec_center()
    #print len(T), 'ccds'
    #print 'trad', trad, 'ccdrad', ccdrad
    I = np.flatnonzero(np.abs(T.dec - d) < rad)
    #print 'Cut to', len(I), 'on Dec'
    I = I[degrees_between(T.ra[I], T.dec[I], r, d) < rad]
    #print 'Cut to', len(I), 'on RA,Dec'

    if not polygons:
        return I
    # now check actual polygon intersection
    tw,th = targetwcs.imagew, targetwcs.imageh
    targetpoly = [(0.5,0.5),(tw+0.5,0.5),(tw+0.5,th+0.5),(0.5,th+0.5)]
    cd = targetwcs.get_cd()
    tdet = cd[0]*cd[3] - cd[1]*cd[2]
    #print 'tdet', tdet
    if tdet > 0:
        targetpoly = list(reversed(targetpoly))
    targetpoly = np.array(targetpoly)

    keep = []
    for i in I:
        W,H = T.width[i],T.height[i]
        wcs = Tan(*[float(x) for x in
                    [T.crval1[i], T.crval2[i], T.crpix1[i], T.crpix2[i], T.cd1_1[i],
                     T.cd1_2[i], T.cd2_1[i], T.cd2_2[i], W, H]])
        cd = wcs.get_cd()
        wdet = cd[0]*cd[3] - cd[1]*cd[2]
        #print 'wdet', wdet
        poly = []
        for x,y in [(0.5,0.5),(W+0.5,0.5),(W+0.5,H+0.5),(0.5,H+0.5)]:
            rr,dd = wcs.pixelxy2radec(x,y)
            ok,xx,yy = targetwcs.radec2pixelxy(rr,dd)
            poly.append((xx,yy))
        if wdet > 0:
            poly = list(reversed(poly))
        poly = np.array(poly)
        if polygons_intersect(targetpoly, poly):
            keep.append(i)
    I = np.array(keep)
    #print 'Cut to', len(I), 'on polygons'
    return I
Ejemplo n.º 4
0
def ccds_touching_wcs(targetwcs, ccds, ccdrad=0.17, polygons=True):
    '''
    targetwcs: wcs object describing region of interest
    ccds: fits_table object of CCDs

    ccdrad: radius of CCDs, in degrees.  Default 0.17 is for DECam.
    #If None, computed from T.

    Returns: index array I of CCDs within range.
    '''
    trad = targetwcs.radius()
    if ccdrad is None:
        ccdrad = max(
            np.sqrt(np.abs(ccds.cd1_1 * ccds.cd2_2 - ccds.cd1_2 * ccds.cd2_1))
            * np.hypot(ccds.width, ccds.height) / 2.)

    rad = trad + ccdrad
    r, d = targetwcs.radec_center()
    I, = np.nonzero(np.abs(ccds.dec - d) < rad)
    I = I[np.atleast_1d(degrees_between(ccds.ra[I], ccds.dec[I], r, d) < rad)]

    if not polygons:
        return I
    # now check actual polygon intersection
    tw, th = targetwcs.imagew, targetwcs.imageh
    targetpoly = [(0.5, 0.5), (tw + 0.5, 0.5), (tw + 0.5, th + 0.5),
                  (0.5, th + 0.5)]
    cd = targetwcs.get_cd()
    tdet = cd[0] * cd[3] - cd[1] * cd[2]
    if tdet > 0:
        targetpoly = list(reversed(targetpoly))
    targetpoly = np.array(targetpoly)

    keep = []
    for i in I:
        W, H = ccds.width[i], ccds.height[i]
        wcs = Tan(*[
            float(x) for x in [
                ccds.crval1[i], ccds.crval2[i], ccds.crpix1[i], ccds.crpix2[i],
                ccds.cd1_1[i], ccds.cd1_2[i], ccds.cd2_1[i], ccds.cd2_2[i], W,
                H
            ]
        ])
        cd = wcs.get_cd()
        wdet = cd[0] * cd[3] - cd[1] * cd[2]
        poly = []
        for x, y in [(0.5, 0.5), (W + 0.5, 0.5), (W + 0.5, H + 0.5),
                     (0.5, H + 0.5)]:
            rr, dd = wcs.pixelxy2radec(x, y)
            ok, xx, yy = targetwcs.radec2pixelxy(rr, dd)
            poly.append((xx, yy))
        if wdet > 0:
            poly = list(reversed(poly))
        poly = np.array(poly)
        if polygons_intersect(targetpoly, poly):
            keep.append(i)
    I = np.array(keep)
    return I
Ejemplo n.º 5
0
def cat_sdss(req, ver):
    import json
    import numpy as np
    from astrometry.util.starutil_numpy import degrees_between, radectoxyz, xyztoradec
    from map.views import sdss_ccds_near
    from astrometry.util.fits import fits_table, merge_tables

    tag = 'sdss-cat'
    ralo = float(req.GET['ralo'])
    rahi = float(req.GET['rahi'])
    declo = float(req.GET['declo'])
    dechi = float(req.GET['dechi'])

    ver = int(ver)
    if not ver in catversions[tag]:
        raise RuntimeError('Invalid version %i for tag %s' % (ver, tag))

    rad = degrees_between(ralo, declo, rahi, dechi) / 2.
    xyz1 = radectoxyz(ralo, declo)
    xyz2 = radectoxyz(rahi, dechi)
    xyz = (xyz1 + xyz2)
    xyz /= np.sqrt(np.sum(xyz**2))
    rc,dc = xyztoradec(xyz)
    rad = rad + np.hypot(10.,14.)/2./60.
    ccds = sdss_ccds_near(rc[0], dc[0], rad)
    if ccds is None:
        print('No SDSS CCDs nearby')
        return HttpResponse(json.dumps(dict(rd=[])),
                            content_type='application/json')
    print(len(ccds), 'SDSS CCDs')

    T = []
    for ccd in ccds:
        # env/BOSS_PHOTOOBJ/301/2073/3/photoObj-002073-3-0088.fits
        fn = os.path.join(settings.SDSS_BASEDIR, 'env', 'BOSS_PHOTOOBJ',
                          str(ccd.rerun), str(ccd.run), str(ccd.camcol),
                          'photoObj-%06i-%i-%04i.fits' % (ccd.run, ccd.camcol, ccd.field))
        print('Reading', fn)
        T.append(fits_table(fn, columns='ra dec objid mode objc_type objc_flags objc_flags nchild tai expflux devflux psfflux cmodelflux fracdev mjd'.split()))
    T = merge_tables(T)
    T.cut((T.dec >= declo) * (T.dec <= dechi))
    # FIXME
    T.cut((T.ra  >= ralo) * (T.ra <= rahi))
    
    # primary
    T.cut(T.mode == 1)
    types = ['P' if t == 6 else 'C' for t in T.objc_type]
    fluxes = [p if t == 6 else c for t,p,c in zip(T.objc_type, T.psfflux, T.cmodelflux)]

    return HttpResponse(json.dumps(dict(
        rd=[(float(o.ra),float(o.dec)) for o in T],
        sourcetype=types,
        fluxes = [dict(u=float(f[0]), g=float(f[1]), r=float(f[2]),
                       i=float(f[3]), z=float(f[4])) for f in fluxes],
    )),
                        content_type='application/json')
Ejemplo n.º 6
0
def ccds_touching_wcs(targetwcs, ccds, ccdrad=0.17, polygons=True):
    '''
    targetwcs: wcs object describing region of interest
    ccds: fits_table object of CCDs

    ccdrad: radius of CCDs, in degrees.  Default 0.17 is for DECam.
    #If None, computed from T.

    Returns: index array I of CCDs within range.
    '''
    trad = targetwcs.radius()
    if ccdrad is None:
        ccdrad = max(np.sqrt(np.abs(ccds.cd1_1 * ccds.cd2_2 -
                                    ccds.cd1_2 * ccds.cd2_1)) *
                     np.hypot(ccds.width, ccds.height) / 2.)

    rad = trad + ccdrad
    r,d = targetwcs.radec_center()
    I, = np.nonzero(np.abs(ccds.dec - d) < rad)
    I = I[np.atleast_1d(degrees_between(ccds.ra[I], ccds.dec[I], r, d) < rad)]

    if not polygons:
        return I
    # now check actual polygon intersection
    tw,th = targetwcs.imagew, targetwcs.imageh
    targetpoly = [(0.5,0.5),(tw+0.5,0.5),(tw+0.5,th+0.5),(0.5,th+0.5)]
    cd = targetwcs.get_cd()
    tdet = cd[0]*cd[3] - cd[1]*cd[2]
    if tdet > 0:
        targetpoly = list(reversed(targetpoly))
    targetpoly = np.array(targetpoly)

    keep = []
    for i in I:
        W,H = ccds.width[i],ccds.height[i]
        wcs = Tan(*[float(x) for x in
                    [ccds.crval1[i], ccds.crval2[i], ccds.crpix1[i], ccds.crpix2[i],
                     ccds.cd1_1[i], ccds.cd1_2[i], ccds.cd2_1[i], ccds.cd2_2[i], W, H]])
        cd = wcs.get_cd()
        wdet = cd[0]*cd[3] - cd[1]*cd[2]
        poly = []
        for x,y in [(0.5,0.5),(W+0.5,0.5),(W+0.5,H+0.5),(0.5,H+0.5)]:
            rr,dd = wcs.pixelxy2radec(x,y)
            ok,xx,yy = targetwcs.radec2pixelxy(rr,dd)
            poly.append((xx,yy))
        if wdet > 0:
            poly = list(reversed(poly))
        poly = np.array(poly)
        if polygons_intersect(targetpoly, poly):
            keep.append(i)
    I = np.array(keep)
    return I
Ejemplo n.º 7
0
def unwise_tiles_touching_wcs(wcs, polygons=True):
    '''
    Returns a FITS table (with RA,Dec,coadd_id) of unWISE tiles
    '''
    from astrometry.util.miscutils import polygons_intersect
    from astrometry.util.starutil_numpy import degrees_between

    from pkg_resources import resource_filename
    atlasfn = resource_filename('legacypipe', 'data/wise-tiles.fits')

    T = fits_table(atlasfn)
    trad = wcs.radius()
    wrad = np.sqrt(2.) / 2. * 2048 * 2.75 / 3600.
    rad = trad + wrad
    r, d = wcs.radec_center()
    I, = np.nonzero(np.abs(T.dec - d) < rad)
    I = I[degrees_between(T.ra[I], T.dec[I], r, d) < rad]

    if not polygons:
        return T[I]
    # now check actual polygon intersection
    tw, th = wcs.imagew, wcs.imageh
    targetpoly = [(0.5, 0.5), (tw + 0.5, 0.5), (tw + 0.5, th + 0.5),
                  (0.5, th + 0.5)]
    cd = wcs.get_cd()
    tdet = cd[0] * cd[3] - cd[1] * cd[2]
    if tdet > 0:
        targetpoly = list(reversed(targetpoly))
    targetpoly = np.array(targetpoly)
    keep = []
    for i in I:
        wwcs = unwise_tile_wcs(T.ra[i], T.dec[i])
        cd = wwcs.get_cd()
        wdet = cd[0] * cd[3] - cd[1] * cd[2]
        H, W = wwcs.shape
        poly = []
        for x, y in [(0.5, 0.5), (W + 0.5, 0.5), (W + 0.5, H + 0.5),
                     (0.5, H + 0.5)]:
            rr, dd = wwcs.pixelxy2radec(x, y)
            _, xx, yy = wcs.radec2pixelxy(rr, dd)
            poly.append((xx, yy))
        if wdet > 0:
            poly = list(reversed(poly))
        poly = np.array(poly)
        if polygons_intersect(targetpoly, poly):
            keep.append(i)
    I = np.array(keep)
    return T[I]
Ejemplo n.º 8
0
def unWISE2BOSS(tilename, channelNumber, BOSSra, BOSSdec, plot=True, vmin=-50,vmax=300):
	# Input tile name
	RA = BOSSra.copy()
	DEC =BOSSdec.copy()
	tileName = tilename
	channel = channelNumber
	# Contructing file address
	fileaddress = get_unwise_filename(tileName, channel)

	tol = 2.00
	if 'm' in tileName:
		ra = float(tileName.split('m')[0])/10.0
		dec = float(tileName.split('m')[1])/10.0
	else: 
		ra = float(tileName.split('p')[0])/10.0
		dec = float(tileName.split('p')[1])/10.0

	iBool = degrees_between(ra, dec, RA,DEC) <tol

	# Getting x,y positions of the objects near by the center of the tile. 
	wcs = Tan(fileaddress)
	ok, x, y = wcs.radec2pixelxy(RA[np.where(iBool==True)], DEC[np.where(iBool==True)])

	a = np.isnan(x)
	b = np.isnan(y)

	x[a] = 0
	y[b] = 0


	iBool = (1<x)&(x<2048)&(1<y)&(y<2048)
	x -= 1
	y -= 1

	x=x[iBool]
	y=y[iBool]


	#From the result, I choose to use 1504p196
	if plot:
		objs1 = fitsio.FITS(fileaddress)
		blockImage =objs1[0][:,:] 
		plt.imshow(blockImage, cmap='gray', vmin=vmin, vmax=vmax, origin='lower',interpolation='nearest') # 10/8/2015: Becareful about the orientation of the matrix. 
		plt.scatter(x, y, facecolors='none', edgecolors='r',s=100)
		plt.show() 

	#Return RA/DEC
	return x, y
Ejemplo n.º 9
0
def unwise_tiles_touching_wcs(wcs, polygons=True):
    '''
    Returns a FITS table (with RA,Dec,coadd_id) of unWISE tiles
    '''
    atlasfn = os.path.join(os.path.dirname(__file__), 'allsky-atlas.fits')
    T = fits_table(atlasfn)
    trad = wcs.radius()
    wrad = np.sqrt(2.) / 2. * 2048 * 2.75 / 3600.
    rad = trad + wrad
    r, d = wcs.radec_center()
    I, = np.nonzero(np.abs(T.dec - d) < rad)
    I = I[degrees_between(T.ra[I], T.dec[I], r, d) < rad]

    if not polygons:
        return T[I]
    # now check actual polygon intersection
    tw, th = wcs.imagew, wcs.imageh
    targetpoly = [(0.5, 0.5), (tw + 0.5, 0.5), (tw + 0.5, th + 0.5),
                  (0.5, th + 0.5)]
    cd = wcs.get_cd()
    tdet = cd[0] * cd[3] - cd[1] * cd[2]
    if tdet > 0:
        targetpoly = list(reversed(targetpoly))
    targetpoly = np.array(targetpoly)
    keep = []
    for i in I:
        wwcs = unwise_tile_wcs(T.ra[i], T.dec[i])
        cd = wwcs.get_cd()
        wdet = cd[0] * cd[3] - cd[1] * cd[2]
        H, W = wwcs.shape
        poly = []
        for x, y in [(0.5, 0.5), (W + 0.5, 0.5), (W + 0.5, H + 0.5),
                     (0.5, H + 0.5)]:
            rr, dd = wwcs.pixelxy2radec(x, y)
            ok, xx, yy = wcs.radec2pixelxy(rr, dd)
            poly.append((xx, yy))
        if wdet > 0:
            poly = list(reversed(poly))
        poly = np.array(poly)
        if polygons_intersect(targetpoly, poly):
            keep.append(i)
    I = np.array(keep)
    return T[I]
Ejemplo n.º 10
0
def cat_kd(req, ver, tag, fn):
    tag = 'spec'
    ralo = float(req.GET['ralo'])
    rahi = float(req.GET['rahi'])
    declo = float(req.GET['declo'])
    dechi = float(req.GET['dechi'])
    ver = int(ver)
    if not ver in catversions[tag]:
        raise RuntimeError('Invalid version %i for tag %s' % (ver, tag))

    import numpy as np
    from astrometry.util.fits import fits_table, merge_tables
    from astrometry.libkd.spherematch import tree_open, tree_search_radec
    from astrometry.util.starutil_numpy import radectoxyz, xyztoradec, degrees_between

    xyz1 = radectoxyz(ralo, declo)
    xyz2 = radectoxyz(rahi, dechi)
    xyz = (xyz1 + xyz2) / 2.
    xyz /= np.sqrt(np.sum(xyz**2))
    rc, dc = xyztoradec(xyz)
    rc = rc[0]
    dc = dc[0]
    rad = degrees_between(rc, dc, ralo, declo)

    kd = tree_open(fn)
    I = tree_search_radec(kd, rc, dc, rad)
    print('Matched', len(I), 'from', fn)
    if len(I) == 0:
        return None
    T = fits_table(fn, rows=I)
    debug(len(T), 'spectra')
    if ralo > rahi:
        # RA wrap
        T.cut(
            np.logical_or(T.ra > ralo, T.ra < rahi) * (T.dec > declo) *
            (T.dec < dechi))
    else:
        T.cut(
            (T.ra > ralo) * (T.ra < rahi) * (T.dec > declo) * (T.dec < dechi))
    debug(len(T), 'in cut')

    return T
Ejemplo n.º 11
0
def unwise_tiles_touching_wcs(wcs, polygons=True):
    '''
    Returns a FITS table (with RA,Dec,coadd_id) of unWISE tiles
    '''
    atlasfn = os.path.join(os.path.dirname(__file__), 'allsky-atlas.fits')
    T = fits_table(atlasfn)
    trad = wcs.radius()
    wrad = np.sqrt(2.)/2. * 2048 * 2.75/3600.
    rad = trad + wrad
    r,d = wcs.radec_center()
    I, = np.nonzero(np.abs(T.dec - d) < rad)
    I = I[degrees_between(T.ra[I], T.dec[I], r, d) < rad]

    if not polygons:
        return T[I]
    # now check actual polygon intersection
    tw,th = wcs.imagew, wcs.imageh
    targetpoly = [(0.5,0.5),(tw+0.5,0.5),(tw+0.5,th+0.5),(0.5,th+0.5)]
    cd = wcs.get_cd()
    tdet = cd[0]*cd[3] - cd[1]*cd[2]
    if tdet > 0:
        targetpoly = list(reversed(targetpoly))
    targetpoly = np.array(targetpoly)
    keep = []
    for i in I:
        wwcs = unwise_tile_wcs(T.ra[i], T.dec[i])
        cd = wwcs.get_cd()
        wdet = cd[0]*cd[3] - cd[1]*cd[2]
        H,W = wwcs.shape
        poly = []
        for x,y in [(0.5,0.5),(W+0.5,0.5),(W+0.5,H+0.5),(0.5,H+0.5)]:
            rr,dd = wwcs.pixelxy2radec(x,y)
            ok,xx,yy = wcs.radec2pixelxy(rr,dd)
            poly.append((xx,yy))
        if wdet > 0:
            poly = list(reversed(poly))
        poly = np.array(poly)
        if polygons_intersect(targetpoly, poly):
            keep.append(i)
    I = np.array(keep)
    return T[I]
Ejemplo n.º 12
0
    def bricks_touching_radec_box(self, bricks,
                                  ralo, rahi, declo, dechi):
        '''
        Returns an index vector of the bricks that touch the given RA,Dec box.
        '''
        if bricks is None:
            bricks = self.get_bricks_readonly()
        if self.cache_tree and bricks == self.bricks:
            from astrometry.libkd.spherematch import tree_build_radec, tree_search_radec
            # Use kdtree
            if self.bricktree is None:
                self.bricktree = tree_build_radec(bricks.ra, bricks.dec)
            # brick size
            radius = np.sqrt(2.)/2. * self.bricksize
            # + RA,Dec box size
            radius = radius + degrees_between(ralo, declo, rahi, dechi) / 2.
            dec = (dechi + declo) / 2.
            c = (np.cos(np.deg2rad(rahi)) + np.cos(np.deg2rad(ralo))) / 2.
            s = (np.sin(np.deg2rad(rahi)) + np.sin(np.deg2rad(ralo))) / 2.
            ra  = np.rad2deg(np.arctan2(s, c))
            J = tree_search_radec(self.bricktree, ra, dec, radius)
            I = J[np.nonzero((bricks.ra1[J]  <= rahi ) * (bricks.ra2[J]  >= ralo) *
                             (bricks.dec1[J] <= dechi) * (bricks.dec2[J] >= declo))[0]]
            return I

        if rahi < ralo:
            # Wrap-around
            print('In Dec slice:', len(np.flatnonzero((bricks.dec1 <= dechi) *
                                                      (bricks.dec2 >= declo))))
            print('Above RAlo=', ralo, ':', len(np.flatnonzero(bricks.ra2 >= ralo)))
            print('Below RAhi=', rahi, ':', len(np.flatnonzero(bricks.ra1 <= rahi)))
            print('In RA slice:', len(np.nonzero(np.logical_or(bricks.ra2 >= ralo,
                                                               bricks.ra1 <= rahi))))
                    
            I, = np.nonzero(np.logical_or(bricks.ra2 >= ralo, bricks.ra1 <= rahi) *
                            (bricks.dec1 <= dechi) * (bricks.dec2 >= declo))
            print('In RA&Dec slice', len(I))
        else:
            I, = np.nonzero((bricks.ra1  <= rahi ) * (bricks.ra2  >= ralo) *
                            (bricks.dec1 <= dechi) * (bricks.dec2 >= declo))
        return I
Ejemplo n.º 13
0
    def bricks_touching_radec_box(self, bricks,
                                  ralo, rahi, declo, dechi):
        '''
        Returns an index vector of the bricks that touch the given RA,Dec box.
        '''
        if bricks is None:
            bricks = self.get_bricks_readonly()
        if self.cache_tree and bricks == self.bricks:
            from astrometry.libkd.spherematch import tree_build_radec, tree_search_radec
            # Use kdtree
            if self.bricktree is None:
                self.bricktree = tree_build_radec(bricks.ra, bricks.dec)
            # brick size
            radius = np.sqrt(2.)/2. * self.bricksize
            # + RA,Dec box size
            radius = radius + degrees_between(ralo, declo, rahi, dechi) / 2.
            dec = (dechi + declo) / 2.
            c = (np.cos(np.deg2rad(rahi)) + np.cos(np.deg2rad(ralo))) / 2.
            s = (np.sin(np.deg2rad(rahi)) + np.sin(np.deg2rad(ralo))) / 2.
            ra  = np.rad2deg(np.arctan2(s, c))
            J = tree_search_radec(self.bricktree, ra, dec, radius)
            I = J[np.nonzero((bricks.ra1[J]  <= rahi ) * (bricks.ra2[J]  >= ralo) *
                             (bricks.dec1[J] <= dechi) * (bricks.dec2[J] >= declo))[0]]
            return I

        if rahi < ralo:
            # Wrap-around
            print('In Dec slice:', len(np.flatnonzero((bricks.dec1 <= dechi) *
                                                      (bricks.dec2 >= declo))))
            print('Above RAlo=', ralo, ':', len(np.flatnonzero(bricks.ra2 >= ralo)))
            print('Below RAhi=', rahi, ':', len(np.flatnonzero(bricks.ra1 <= rahi)))
            print('In RA slice:', len(np.nonzero(np.logical_or(bricks.ra2 >= ralo,
                                                               bricks.ra1 <= rahi))))
                    
            I, = np.nonzero(np.logical_or(bricks.ra2 >= ralo, bricks.ra1 <= rahi) *
                            (bricks.dec1 <= dechi) * (bricks.dec2 >= declo))
            print('In RA&Dec slice', len(I))
        else:
            I, = np.nonzero((bricks.ra1  <= rahi ) * (bricks.ra2  >= ralo) *
                            (bricks.dec1 <= dechi) * (bricks.dec2 >= declo))
        return I
Ejemplo n.º 14
0
def cat_targets_dr2(req, ver):
    import json
    tag = 'targets-dr2'
    ralo = float(req.GET['ralo'])
    rahi = float(req.GET['rahi'])
    declo = float(req.GET['declo'])
    dechi = float(req.GET['dechi'])

    ver = int(ver)
    if not ver in catversions[tag]:
        raise RuntimeError('Invalid version %i for tag %s' % (ver, tag))

    from astrometry.util.fits import fits_table, merge_tables
    import numpy as np
    from cat.models import DR2_Target as Target

    from astrometry.util.starutil_numpy import radectoxyz, xyztoradec, degrees_between
    xyz1 = radectoxyz(ralo, declo)
    xyz2 = radectoxyz(rahi, dechi)
    xyz = (xyz1 + xyz2) / 2.
    xyz /= np.sqrt(np.sum(xyz**2))
    rc, dc = xyztoradec(xyz)
    rc = rc[0]
    dc = dc[0]
    rad = degrees_between(rc, dc, ralo, declo)

    objs = Target.objects.extra(where=[
        'q3c_radial_query(target.ra, target.dec, %.4f, %.4f, %g)' %
        (rc, dc, rad * 1.01)
    ])
    print('Got', objs.count(), 'targets')
    print('types:', np.unique([o.type for o in objs]))
    print('versions:', np.unique([o.version for o in objs]))

    return HttpResponse(json.dumps(
        dict(
            rd=[(float(o.ra), float(o.dec)) for o in objs],
            name=[o.type for o in objs],
        )),
                        content_type='application/json')
Ejemplo n.º 15
0
def cat_kd(req, ver, tag, fn):
    tag = 'spec'
    ralo = float(req.GET['ralo'])
    rahi = float(req.GET['rahi'])
    declo = float(req.GET['declo'])
    dechi = float(req.GET['dechi'])
    ver = int(ver)
    if not ver in catversions[tag]:
        raise RuntimeError('Invalid version %i for tag %s' % (ver, tag))

    import numpy as np
    from astrometry.util.fits import fits_table, merge_tables
    from astrometry.libkd.spherematch import tree_open, tree_search_radec
    from astrometry.util.starutil_numpy import radectoxyz, xyztoradec, degrees_between

    xyz1 = radectoxyz(ralo, declo)
    xyz2 = radectoxyz(rahi, dechi)
    xyz = (xyz1 + xyz2)/2.
    xyz /= np.sqrt(np.sum(xyz**2))
    rc,dc = xyztoradec(xyz)
    rc = rc[0]
    dc = dc[0]
    rad = degrees_between(rc, dc, ralo, declo)

    kd = tree_open(fn)
    I = tree_search_radec(kd, rc, dc, rad)
    print('Matched', len(I), 'from', fn)
    if len(I) == 0:
        return None
    T = fits_table(fn, rows=I)
    debug(len(T), 'spectra')
    if ralo > rahi:
        # RA wrap
        T.cut(np.logical_or(T.ra > ralo, T.ra < rahi) * (T.dec > declo) * (T.dec < dechi))
    else:
        T.cut((T.ra > ralo) * (T.ra < rahi) * (T.dec > declo) * (T.dec < dechi))
    debug(len(T), 'in cut')

    return T
Ejemplo n.º 16
0
def cat_targets_dr2(req, ver):
    import json
    tag = 'targets-dr2'
    ralo = float(req.GET['ralo'])
    rahi = float(req.GET['rahi'])
    declo = float(req.GET['declo'])
    dechi = float(req.GET['dechi'])

    ver = int(ver)
    if not ver in catversions[tag]:
        raise RuntimeError('Invalid version %i for tag %s' % (ver, tag))

    from astrometry.util.fits import fits_table, merge_tables
    import numpy as np
    from cat.models import DR2_Target as Target

    from astrometry.util.starutil_numpy import radectoxyz, xyztoradec, degrees_between
    xyz1 = radectoxyz(ralo, declo)
    xyz2 = radectoxyz(rahi, dechi)
    xyz = (xyz1 + xyz2)/2.
    xyz /= np.sqrt(np.sum(xyz**2))
    rc,dc = xyztoradec(xyz)
    rc = rc[0]
    dc = dc[0]
    rad = degrees_between(rc, dc, ralo, declo)

    objs = Target.objects.extra(where=[
            'q3c_radial_query(target.ra, target.dec, %.4f, %.4f, %g)'
            % (rc, dc, rad * 1.01)])
    print('Got', objs.count(), 'targets')
    print('types:', np.unique([o.type for o in objs]))
    print('versions:', np.unique([o.version for o in objs]))

    return HttpResponse(json.dumps(dict(
                rd=[(float(o.ra),float(o.dec)) for o in objs],
                name=[o.type for o in objs],
                )),
                        content_type='application/json')
Ejemplo n.º 17
0
def BOSS2unWISE(ra, dec, tileID, tileRA, tileDEC,plot=True):
	tol = 1.56
	iBool = degrees_between(ra, dec, tileRA,tileDEC) <tol
	tilesCandidates = tileID[iBool] 
	tiles = []
	for tName in tilesCandidates:
		channel = 'w1'
		fileaddress = get_unwise_filename(tName, channel)
		wcs = Tan(fileaddress)
		ok, x, y = wcs.radec2pixelxy(ra, dec)
		x -= 1
		y -= 1
		iTile= (0<x) &(x<2047)&(0<y)&(y<2047)
		if iTile:
			tiles = np.append(tiles, [tName])
			if plot:
				objs1 = fitsio.FITS(fileaddress)
				blockImage =objs1[0][:,:]
				plt.imshow(blockImage, cmap='gray', vmin=-50, vmax=300, origin='lower',interpolation='nearest') # 10/8/2015: Becareful about the orientation of the matrix. 
				plt.scatter(x, y, facecolors='none', edgecolors='r',s=100)
				plt.show()

	return tiles
Ejemplo n.º 18
0
def read_star_clusters(targetwcs):
    """The code to generate the NGC-star-clusters-fits catalog is in
    legacypipe/bin/build-cluster-catalog.py.

    """
    from pkg_resources import resource_filename
    from astrometry.util.starutil_numpy import degrees_between

    clusterfile = resource_filename('legacypipe',
                                    'data/NGC-star-clusters.fits')
    debug('Reading {}'.format(clusterfile))
    clusters = fits_table(clusterfile,
                          columns=['ra', 'dec', 'radius', 'type', 'ba', 'pa'])
    clusters.ref_id = np.arange(len(clusters))

    radius = 1.
    rc, dc = targetwcs.radec_center()
    d = degrees_between(rc, dc, clusters.ra, clusters.dec)
    clusters.cut(d < radius)
    if len(clusters) == 0:
        return None

    debug('Cut to {} star cluster(s) within the brick'.format(len(clusters)))
    clusters.ref_cat = np.array(['CL'] * len(clusters))

    # Radius in degrees
    clusters.radius = clusters.radius
    clusters.radius[np.logical_not(np.isfinite(clusters.radius))] = 1. / 60.

    # Set isbright=True
    clusters.isbright = np.zeros(len(clusters), bool)
    clusters.iscluster = np.ones(len(clusters), bool)

    clusters.sources = np.array([None] * len(clusters))

    return clusters
Ejemplo n.º 19
0
 def distanceFrom(self, pos):
     from astrometry.util.starutil_numpy import degrees_between
     return degrees_between(self.ra, self.dec, pos.ra, pos.dec)
Ejemplo n.º 20
0
    H, W = 100, 100

    ##  WCS.
    targetwcs = Tan(ra, dec, W / 2. + 0.5, H / 2. + 0.5, -ps, 0., 0., ps,
                    float(W), float(H))
    wcs = tractor.ConstantFitsWcs(targetwcs)

    targetrd = np.array([
        targetwcs.pixelxy2radec(x, y)
        for x, y in [(1, 1), (W, 1), (W, H), (1, H), (1, 1)]
    ])

    ##  Bricks.
    B = survey.get_bricks_readonly()
    B.about()
    B.cut(np.argsort(degrees_between(ra, dec, B.ra, B.dec)))

    brick = B[0]

    tims = []

    for band in bands:
        sky_level_sig, psf_fwhm, zpt, psf_theta, psf_ell = unpack_ccds(
            band=band, index=0)

        ##  Gaussian approx.
        psf_sigma = psf_fwhm / (2. * np.sqrt(2. * np.log(2.)))
        psf_sigma2 = psf_sigma**2.

        psfnorm = 1. / (2. * np.sqrt(np.pi) * psf_sigma)
Ejemplo n.º 21
0
def annotate_one_ccd(X):
    ccd, survey, normalizePsf, carryOn = X
    print('Annotating CCD', ccd.image_filename.strip(), 'expnum', ccd.expnum,
          'CCD', ccd.ccdname)
    result = {}
    try:
        im = survey.get_image_object(ccd)
    except:
        print('Failed to get_image_object()')
        import traceback
        traceback.print_exc()
        if carryOn:
            return result
        else:
            raise

    X = im.get_good_image_subregion()
    reg = [-1, -1, -1, -1]
    for i, x in enumerate(X):
        if x is not None:
            reg[i] = x
    result.update(good_region=reg)

    kwargs = dict(pixPsf=True,
                  splinesky=True,
                  subsky=False,
                  pixels=False,
                  dq=False,
                  invvar=False,
                  normalizePsf=normalizePsf)
    psf = None
    wcs = None
    sky = None

    if ccd.ccdnastrom == 0:  # something went terribly wrong
        print('ccdnastrom == 0; bailing on annotation')
        return result

    try:
        tim = im.get_tractor_image(**kwargs)
    except:
        print('Failed to get_tractor_image')
        import traceback
        traceback.print_exc()
        if carryOn:
            return result
        else:
            raise

    if tim is None:
        print('Failed to get_tractor_image; bailing on annotation')
        return result

    psf = tim.psf
    wcs = tim.wcs.wcs
    sky = tim.sky
    hdr = tim.primhdr

    result.update(humidity=hdr.get('HUMIDITY'),
                  outtemp=hdr.get('OUTTEMP'),
                  plver=tim.plver,
                  procdate=tim.procdate,
                  plprocid=tim.plprocid)

    # parse 'DECaLS_15150_r' to get tile number
    obj = ccd.object.strip()
    words = obj.split('_')
    if len(words) == 3 and words[0] in ('DECaLS', 'MzLS', 'MOSAIC'):
        try:
            tileid = int(words[1])
            result.update(tileid=tileid)
        except:
            import traceback
            traceback.print_exc()

    # Instantiate PSF on a grid
    S = 32
    W, H = ccd.width, ccd.height
    xx = np.linspace(1 + S, W - S, 5)
    yy = np.linspace(1 + S, H - S, 5)
    xx, yy = np.meshgrid(xx, yy)
    psfnorms = []
    galnorms = []
    for x, y in zip(xx.ravel(), yy.ravel()):
        tim.psf = psf.constantPsfAt(x, y)
        try:
            p = im.psf_norm(tim, x=x, y=y)
            g = im.galaxy_norm(tim, x=x, y=y)
            psfnorms.append(p)
            galnorms.append(g)
        except:
            pass

    tim.psf = psf
    result.update(psfnorm_mean=np.mean(psfnorms),
                  psfnorm_std=np.std(psfnorms),
                  galnorm_mean=np.mean(galnorms),
                  galnorm_std=np.std(galnorms))

    # PSF in center of field
    cx, cy = (W + 1) / 2., (H + 1) / 2.
    p = psf.getPointSourcePatch(cx, cy).patch
    ph, pw = p.shape
    px, py = np.meshgrid(np.arange(pw), np.arange(ph))
    psum = np.sum(p)
    p /= psum
    # centroids
    cenx = np.sum(p * px)
    ceny = np.sum(p * py)
    # second moments
    x2 = np.sum(p * (px - cenx)**2)
    y2 = np.sum(p * (py - ceny)**2)
    xy = np.sum(p * (px - cenx) * (py - ceny))
    # semi-major/minor axes and position angle
    theta = np.rad2deg(np.arctan2(2 * xy, x2 - y2) / 2.)
    theta = np.abs(theta) * np.sign(xy)
    s = np.sqrt(((x2 - y2) / 2.)**2 + xy**2)
    a = np.sqrt((x2 + y2) / 2. + s)
    b = np.sqrt((x2 + y2) / 2. - s)
    ell = 1. - b / a
    result.update(psf_mx2=x2,
                  psf_my2=y2,
                  psf_mxy=xy,
                  psf_a=a,
                  psf_b=b,
                  psf_theta=theta,
                  psf_ell=ell)
    # Galaxy norm using Gaussian approximation of PSF.
    realpsf = tim.psf

    tim.psf = im.read_psf_model(0, 0, gaussPsf=True, psf_sigma=tim.psf_sigma)
    result.update(gaussgalnorm=im.galaxy_norm(tim, x=cx, y=cy))
    tim.psf = realpsf

    has_skygrid = hasattr(sky, 'evaluateGrid')

    # Sky -- evaluate on a grid (every ~10th pixel)
    if has_skygrid:
        skygrid = sky.evaluateGrid(
            np.linspace(0, ccd.width - 1, int(1 + ccd.width / 10)),
            np.linspace(0, ccd.height - 1, int(1 + ccd.height / 10)))
        result.update(meansky=np.mean(skygrid),
                      stdsky=np.std(skygrid),
                      maxsky=skygrid.max(),
                      minsky=skygrid.min())
    else:
        skyval = sky.getConstant()
        result.update(meansky=skyval, stdsky=0., maxsky=skyval, minsky=skyval)

    # WCS
    r0, d0 = wcs.pixelxy2radec(1, 1)
    r1, d1 = wcs.pixelxy2radec(1, H)
    r2, d2 = wcs.pixelxy2radec(W, H)
    r3, d3 = wcs.pixelxy2radec(W, 1)
    result.update(ra0=r0,
                  dec0=d0,
                  ra1=r1,
                  dec1=d1,
                  ra2=r2,
                  dec2=d2,
                  ra3=r3,
                  dec3=d3)

    midx, midy = (W + 1) / 2., (H + 1) / 2.
    rc, dc = wcs.pixelxy2radec(midx, midy)
    ra, dec = wcs.pixelxy2radec([1, W, midx, midx], [midy, midy, 1, H])

    result.update(dra=max(degrees_between(ra, dc + np.zeros_like(ra), rc, dc)),
                  ddec=max(
                      degrees_between(rc + np.zeros_like(dec), dec, rc, dc)),
                  ra_center=rc,
                  dec_center=dc)

    # Compute scale change across the chip
    # how many pixels to step
    step = 10
    xx = np.linspace(1 + step, W - step, 5)
    yy = np.linspace(1 + step, H - step, 5)
    xx, yy = np.meshgrid(xx, yy)
    pixscale = []
    for x, y in zip(xx.ravel(), yy.ravel()):
        sx = [x - step, x - step, x + step, x + step, x - step]
        sy = [y - step, y + step, y + step, y - step, y - step]
        sr, sd = wcs.pixelxy2radec(sx, sy)
        rc, dc = wcs.pixelxy2radec(x, y)
        # project around a tiny little TAN WCS at (x,y), with 1" pixels
        locwcs = Tan(rc, dc, 0., 0., 1. / 3600, 0., 0., 1. / 3600, 1., 1.)
        ok, lx, ly = locwcs.radec2pixelxy(sr, sd)
        A = polygon_area((lx, ly))
        pixscale.append(np.sqrt(A / (2 * step)**2))
    result.update(pixscale_mean=np.mean(pixscale),
                  pixscale_std=np.std(pixscale),
                  pixscale_min=min(pixscale),
                  pixscale_max=max(pixscale))
    result.update(annotated=True)
    print('Finished annotation')
    return result
Ejemplo n.º 22
0
def main(outfn='ccds-annotated.fits', ccds=None):
    decals = Decals()
    if ccds is None:
        ccds = decals.get_ccds()

    # File from the "observing" svn repo:
    # https://desi.lbl.gov/svn/decam/code/observing/trunk
    tiles = fits_table('decam-tiles_obstatus.fits')

    #ccds.cut(np.arange(100))
    #print("HACK!")
    #ccds.cut(np.array([name in ['N15', 'N16', 'N21', 'N9']
    #                   for name in ccds.ccdname]) *
    #                   ccds.expnum == 229683)

    I = decals.photometric_ccds(ccds)
    ccds.photometric = np.zeros(len(ccds), bool)
    ccds.photometric[I] = True

    I = decals.apply_blacklist(ccds)
    ccds.blacklist_ok = np.zeros(len(ccds), bool)
    ccds.blacklist_ok[I] = True

    ccds.good_region = np.empty((len(ccds), 4), np.int16)
    ccds.good_region[:,:] = -1

    ccds.ra0  = np.zeros(len(ccds), np.float64)
    ccds.dec0 = np.zeros(len(ccds), np.float64)
    ccds.ra1  = np.zeros(len(ccds), np.float64)
    ccds.dec1 = np.zeros(len(ccds), np.float64)
    ccds.ra2  = np.zeros(len(ccds), np.float64)
    ccds.dec2 = np.zeros(len(ccds), np.float64)
    ccds.ra3  = np.zeros(len(ccds), np.float64)
    ccds.dec3 = np.zeros(len(ccds), np.float64)

    ccds.dra  = np.zeros(len(ccds), np.float32)
    ccds.ddec = np.zeros(len(ccds), np.float32)
    ccds.ra_center  = np.zeros(len(ccds), np.float64)
    ccds.dec_center = np.zeros(len(ccds), np.float64)

    ccds.sig1 = np.zeros(len(ccds), np.float32)

    ccds.meansky = np.zeros(len(ccds), np.float32)
    ccds.stdsky  = np.zeros(len(ccds), np.float32)
    ccds.maxsky  = np.zeros(len(ccds), np.float32)
    ccds.minsky  = np.zeros(len(ccds), np.float32)

    ccds.pixscale_mean = np.zeros(len(ccds), np.float32)
    ccds.pixscale_std  = np.zeros(len(ccds), np.float32)
    ccds.pixscale_max  = np.zeros(len(ccds), np.float32)
    ccds.pixscale_min  = np.zeros(len(ccds), np.float32)

    ccds.psfnorm_mean = np.zeros(len(ccds), np.float32)
    ccds.psfnorm_std  = np.zeros(len(ccds), np.float32)
    ccds.galnorm_mean = np.zeros(len(ccds), np.float32)
    ccds.galnorm_std  = np.zeros(len(ccds), np.float32)

    gaussgalnorm = np.zeros(len(ccds), np.float32)

    # 2nd moments
    ccds.psf_mx2 = np.zeros(len(ccds), np.float32)
    ccds.psf_my2 = np.zeros(len(ccds), np.float32)
    ccds.psf_mxy = np.zeros(len(ccds), np.float32)
    #
    ccds.psf_a = np.zeros(len(ccds), np.float32)
    ccds.psf_b = np.zeros(len(ccds), np.float32)
    ccds.psf_theta = np.zeros(len(ccds), np.float32)
    ccds.psf_ell   = np.zeros(len(ccds), np.float32)

    ccds.humidity = np.zeros(len(ccds), np.float32)
    ccds.outtemp  = np.zeros(len(ccds), np.float32)

    ccds.tileid   = np.zeros(len(ccds), np.int32)
    ccds.tilepass = np.zeros(len(ccds), np.uint8)
    ccds.tileebv  = np.zeros(len(ccds), np.float32)

    plvers = []

    for iccd,ccd in enumerate(ccds):
        im = decals.get_image_object(ccd)
        print('Reading CCD %i of %i:' % (iccd+1, len(ccds)), im)

        X = im.get_good_image_subregion()
        for i,x in enumerate(X):
            if x is not None:
                ccds.good_region[iccd,i] = x

        W,H = ccd.width, ccd.height

        psf = None
        wcs = None
        sky = None
        try:
            tim = im.get_tractor_image(pixPsf=True, splinesky=True,
                                       subsky=False, pixels=False)
        except:
            import traceback
            traceback.print_exc()
            plvers.append('')
            continue

        if tim is None:
            plvers.append('')
            continue

        psf = tim.psf
        wcs = tim.wcs.wcs
        sky = tim.sky
        hdr = tim.primhdr

        # print('Got PSF', psf)
        # print('Got sky', type(sky))
        # print('Got WCS', wcs)

        ccds.humidity[iccd] = hdr.get('HUMIDITY')
        ccds.outtemp[iccd]  = hdr.get('OUTTEMP')

        ccds.sig1[iccd] = tim.sig1
        plvers.append(tim.plver)

        obj = hdr.get('OBJECT')
        # parse 'DECaLS_15150_r'
        words = obj.split('_')
        tile = None
        if len(words) == 3 and words[0] == 'DECaLS':
            try:
                tileid = int(words[1])
                tile = tiles[tileid - 1]
                if tile.tileid != tileid:
                    I = np.flatnonzero(tile.tileid == tileid)
                    tile = tiles[I[0]]
            except:
                pass

        if tile is not None:
            ccds.tileid  [iccd] = tile.tileid
            ccds.tilepass[iccd] = tile.get('pass')
            ccds.tileebv [iccd] = tile.ebv_med

        # Instantiate PSF on a grid
        S = 32
        xx = np.linspace(1+S, W-S, 5)
        yy = np.linspace(1+S, H-S, 5)
        xx,yy = np.meshgrid(xx, yy)
        psfnorms = []
        galnorms = []
        for x,y in zip(xx.ravel(), yy.ravel()):
            p = im.psf_norm(tim, x=x, y=y)
            g = im.galaxy_norm(tim, x=x, y=y)
            psfnorms.append(p)
            galnorms.append(g)
        ccds.psfnorm_mean[iccd] = np.mean(psfnorms)
        ccds.psfnorm_std [iccd] = np.std (psfnorms)
        ccds.galnorm_mean[iccd] = np.mean(galnorms)
        ccds.galnorm_std [iccd] = np.std (galnorms)

        # PSF in center of field
        cx,cy = (W+1)/2., (H+1)/2.
        p = psf.getPointSourcePatch(cx, cy).patch
        ph,pw = p.shape
        px,py = np.meshgrid(np.arange(pw), np.arange(ph))
        psum = np.sum(p)
        # print('psum', psum)
        p /= psum
        # centroids
        cenx = np.sum(p * px)
        ceny = np.sum(p * py)
        # print('cenx,ceny', cenx,ceny)
        # second moments
        x2 = np.sum(p * (px - cenx)**2)
        y2 = np.sum(p * (py - ceny)**2)
        xy = np.sum(p * (px - cenx)*(py - ceny))
        # semi-major/minor axes and position angle
        theta = np.rad2deg(np.arctan2(2 * xy, x2 - y2) / 2.)
        theta = np.abs(theta) * np.sign(xy)
        s = np.sqrt(((x2 - y2)/2.)**2 + xy**2)
        a = np.sqrt((x2 + y2) / 2. + s)
        b = np.sqrt((x2 + y2) / 2. - s)
        ell = 1. - b/a

        # print('PSF second moments', x2, y2, xy)
        # print('PSF position angle', theta)
        # print('PSF semi-axes', a, b)
        # print('PSF ellipticity', ell)

        ccds.psf_mx2[iccd] = x2
        ccds.psf_my2[iccd] = y2
        ccds.psf_mxy[iccd] = xy
        ccds.psf_a[iccd] = a
        ccds.psf_b[iccd] = b
        ccds.psf_theta[iccd] = theta
        ccds.psf_ell  [iccd] = ell

        # Galaxy norm using Gaussian approximation of PSF.
        realpsf = tim.psf
        tim.psf = im.read_psf_model(0, 0, gaussPsf=True,
                                    psf_sigma=tim.psf_sigma)
        gaussgalnorm[iccd] = im.galaxy_norm(tim, x=cx, y=cy)
        tim.psf = realpsf
        
        # Sky
        mod = np.zeros((ccd.height, ccd.width), np.float32)
        sky.addTo(mod)
        ccds.meansky[iccd] = np.mean(mod)
        ccds.stdsky[iccd]  = np.std(mod)
        ccds.maxsky[iccd]  = mod.max()
        ccds.minsky[iccd]  = mod.min()

        # WCS
        ccds.ra0[iccd],ccds.dec0[iccd] = wcs.pixelxy2radec(1, 1)
        ccds.ra1[iccd],ccds.dec1[iccd] = wcs.pixelxy2radec(1, H)
        ccds.ra2[iccd],ccds.dec2[iccd] = wcs.pixelxy2radec(W, H)
        ccds.ra3[iccd],ccds.dec3[iccd] = wcs.pixelxy2radec(W, 1)

        midx, midy = (W+1)/2., (H+1)/2.
        rc,dc  = wcs.pixelxy2radec(midx, midy)
        ra,dec = wcs.pixelxy2radec([1,W,midx,midx], [midy,midy,1,H])
        ccds.dra [iccd] = max(degrees_between(ra, dc+np.zeros_like(ra),
                                              rc, dc))
        ccds.ddec[iccd] = max(degrees_between(rc+np.zeros_like(dec), dec,
                                              rc, dc))
        ccds.ra_center [iccd] = rc
        ccds.dec_center[iccd] = dc

        # Compute scale change across the chip
        # how many pixels to step
        step = 10
        xx = np.linspace(1+step, W-step, 5)
        yy = np.linspace(1+step, H-step, 5)
        xx,yy = np.meshgrid(xx, yy)
        pixscale = []
        for x,y in zip(xx.ravel(), yy.ravel()):
            sx = [x-step, x-step, x+step, x+step, x-step]
            sy = [y-step, y+step, y+step, y-step, y-step]
            sr,sd = wcs.pixelxy2radec(sx, sy)
            rc,dc = wcs.pixelxy2radec(x, y)
            # project around a tiny little TAN WCS at (x,y), with 1" pixels
            locwcs = Tan(rc, dc, 0., 0., 1./3600, 0., 0., 1./3600, 1., 1.)
            ok,lx,ly = locwcs.radec2pixelxy(sr, sd)
            #print('local x,y:', lx, ly)
            A = polygon_area((lx, ly))
            pixscale.append(np.sqrt(A / (2*step)**2))
        # print('Pixel scales:', pixscale)
        ccds.pixscale_mean[iccd] = np.mean(pixscale)
        ccds.pixscale_min[iccd] = min(pixscale)
        ccds.pixscale_max[iccd] = max(pixscale)
        ccds.pixscale_std[iccd] = np.std(pixscale)


    ccds.plver = np.array(plvers)

    sfd = tractor.sfd.SFDMap()
    allbands = 'ugrizY'
    filts = ['%s %s' % ('DES', f) for f in allbands]
    wisebands = ['WISE W1', 'WISE W2', 'WISE W3', 'WISE W4']
    ebv,ext = sfd.extinction(filts + wisebands, ccds.ra_center,
                             ccds.dec_center, get_ebv=True)
    ext = ext.astype(np.float32)
    ccds.ebv = ebv.astype(np.float32)
    ccds.decam_extinction = ext[:,:len(allbands)]
    ccds.wise_extinction = ext[:,len(allbands):]

    # Depth
    detsig1 = ccds.sig1 / ccds.psfnorm_mean
    depth = 5. * detsig1
    # that's flux in nanomaggies -- convert to mag
    ccds.psfdepth = -2.5 * (np.log10(depth) - 9)

    detsig1 = ccds.sig1 / ccds.galnorm_mean
    depth = 5. * detsig1
    # that's flux in nanomaggies -- convert to mag
    ccds.galdepth = -2.5 * (np.log10(depth) - 9)

    # Depth using Gaussian FWHM.
    psf_sigma = ccds.fwhm / 2.35
    gnorm = 1./(2. * np.sqrt(np.pi) * psf_sigma)
    detsig1 = ccds.sig1 / gnorm
    depth = 5. * detsig1
    # that's flux in nanomaggies -- convert to mag
    ccds.gausspsfdepth = -2.5 * (np.log10(depth) - 9)

    # Gaussian galaxy depth
    detsig1 = ccds.sig1 / gaussgalnorm
    depth = 5. * detsig1
    # that's flux in nanomaggies -- convert to mag
    ccds.gaussgaldepth = -2.5 * (np.log10(depth) - 9)

    ccds.writeto(outfn)
Ejemplo n.º 23
0
    def update_for_image(self, M, forcepass=None, now=None):
        # M: measurements for the image that's we're going to use to update
        # exposure times.
        # now: for testing purposes only; defaults to ephem.now()
        
        # filename patterns for the exposure and slew scripts
        expscriptpat  = os.path.join(self.scriptdir, self.expscriptpattern)
        slewscriptpat = os.path.join(self.scriptdir, self.slewscriptpattern)

        if M is not None:
            # Choose the pass, based on...
            trans  = M['transparency']
            seeing = M['seeing']
            skybright = M['skybright']
            # eg, nominal = 20, sky = 19, brighter is 1 mag brighter than nom.
            meas_band = M['band']
            nomsky = self.nom.sky(meas_band)
            brighter = nomsky - skybright
        
            print('Transparency: %6.02f' % trans)
            print('Seeing      : %6.02f' % seeing)
            print('Sky         : %6.02f' % skybright)
            print('Nominal sky : %6.02f' % nomsky)
            print('Sky over nom: %6.02f   (positive means brighter than nominal)' %
                  brighter)
    
            nextpass = choose_pass(trans, seeing, skybright, nomsky,
                                   forcedir=self.scriptdir)
        elif forcepass is not None:
            nextpass = forcepass
        else:
            nextpass = self.opt.passnum
        print()
        print('Selected pass:'******'%s: reading sequence number from %s' %
                  (str(ephem.now()), self.seqnumpath))
            f = open(self.seqnumpath, 'r')
            s = f.read()
            f.close()
            seqnum = int(s)
        else:
            # Tonight.sh may not have started yet -- pretend that
            # we're currently taking seqnum=0, so the next one to be
            # planned is seqnum=1.
            seqnum = 0
        print('%s: sequence number: %i' % (str(now), seqnum))
        
        # 'iplan': the tile index we will use for exposure # 'seqnum'
        iplan = None
        if self.opt.sequence:
            iplan = seqnum + self.sequence_offset
            # Check whether the next tile will be observed more than an hour
            # later than its scheduled time -- if so, skip a block of tiles.
            if iplan < len(J):
                j = J[iplan]
                tstart = ephem.Date(str(j['approx_datetime']))
                if now > (tstart + 3600./86400.):
                    print('The next tile will be observed more than an hour late.  Skipping a block of observations...')
                    for i,j in enumerate(J[iplan:]):
                        tstart = ephem.Date(str(j['approx_datetime']))
                        if tstart <= now:
                            continue
                        print('Found tile', j['object'], 'which starts at', str(tstart))
                        print('Skipping', i, 'tiles')
                        self.sequence_offset += i
                        iplan += i
                        break

        elif self.opt.cut_before_now:
            # The usual case -- find the next tile scheduled for after now.
            for i,j in enumerate(J):
                tstart = ephem.Date(str(j['approx_datetime']))
                if tstart <= now:
                    continue
                print('Found tile', j['object'], 'which starts at', str(tstart))
                iplan = i
                break
            if iplan is None:
                print('Could not find a JSON observation in pass', nextpass,
                      'with approx_datetime after now =', str(now),
                      '-- latest one', str(tstart))
                return False
        else:
            # For when we want to observe every tile in the plan:
            # 'seqnum' is the exposure currently running;
            # seqnum is 1-indexed, so that's the index we want for iplan.
            iplan = seqnum

        # Set observing conditions for computing exposure time
        self.obs.date = now

        # Planned exposures:
        P = fits_table()
        P.type = []
        P.tilename = []
        P.filter = []
        P.exptime = []
        P.ra = []
        P.dec = []
        P.passnumber = []

        lasttile = None
        lastdate = None
        
        iahead = 0
        for ii,jplan in enumerate(J[iplan:]):
            from astrometry.util.starutil_numpy import degrees_between
            if iahead >= self.Nahead:
                break
            tilename = str(jplan['object'])
            nextseq = seqnum + 1 + iahead

            if self.n_exposures > 0 and nextseq > self.n_exposures:
                print('Planned tile is beyond the exposure number in ',
                      'tonight.sh -- RESTART MOSBOT')
                return False
            
            print('Considering planning tile %s for exp %i'%(tilename,nextseq))

            # Check all planned tiles before this one for a duplicate tile.
            dup = False
            for s in range(nextseq-1, 0, -1):
                if tilename == self.planned_tiles[s]:
                    dup = True
                    print('Wanted to plan tile %s (pass %i element %i) for exp %i'
                          % (tilename, nextpass, iplan+ii, nextseq),
                          'but it was already planned for exp %i' % s)
                    break
            if dup:
                continue

            self.planned_tiles[nextseq] = tilename
            iahead += 1

            # Find this tile in the tiles table.
            tile = get_tile_from_name(tilename, self.tiles)
            ebv = tile.ebv_med
            nextband = str(jplan['filter'])[0]

            print('Selected tile:', tile.tileid, nextband)
            rastr  = ra2hms (jplan['RA' ])
            decstr = dec2dms(jplan['dec'])
            ephemstr = str('%s,f,%s,%s,20' % (tilename, rastr, decstr))
            etile = ephem.readdb(ephemstr)
            etile.compute(self.obs)
            airmass = get_airmass(float(etile.alt))
            print('Airmass of planned tile:', airmass)

            print('Time of observation:', self.obs.date)
            # HACK -- try setting the date to the planned datetime from the plan file.
            #self.obs.date = ephem.Date(str(jplan['approx_datetime']))

            lst = np.rad2deg(float(self.obs.sidereal_time()))
            ha = lst - jplan['RA']
            if ha < -180:
                ha += 360.
            print('LST:', lst, 'Tile RA:', jplan['RA'], 'Dec', jplan['dec'])
            print('HA of planned tile:', ha)

            readout_during_move = True
            
            # Check for large slew
            slew = 0.
            if lasttile is None:
                # Look up the tile we previously planned
                prevname = self.planned_tiles.get(nextseq - 1, None)
                Jall = self.J1 + self.J2 + self.J3
                I, = np.nonzero([str(j['object']) == prevname for j in Jall])
                if len(I) == 0:
                    print('Could not find previous tile "%s"' % prevname)
                else:
                    jprev = Jall[I[0]]
                    lasttile = jprev
                    lastdate = ephem.Date(str(jprev['approx_datetime']))

            if lasttile is not None:
                slew = degrees_between(lasttile['RA'], lasttile['dec'],
                                       jplan['RA'], jplan['dec'])
                print('Slew: %.1f degrees' % slew)

                # Compute HA for previous tile
                thedate = self.obs.date
                self.obs.date = lastdate
                last_lst = np.rad2deg(float(self.obs.sidereal_time()))
                self.obs.date = thedate
                last_ha = last_lst - lasttile['RA']
                if last_ha < -180:
                    last_ha += 360.
                print('Last tile LST:', last_lst, 'Tile RA:', lasttile['RA'], 'Dec', lasttile['dec'])
                print('Last HA:', last_ha)

                fuzz = 3.
                maybe_flip = maybe_ha_flip(ha, last_ha, fuzz)
                print('Over-the-pole flip possible:', maybe_flip)
                if maybe_flip:
                    readout_during_move = False

            if iahead == 1 and slew > 10.:
                # Beep the terminal -- OA has to okay it (?)
                print()
                print()
                print('Large slew from current exposure to next: ' +
                      'RA,Dec %.1f, %.1f to %.1f, %.1f ==> %.1f degrees' %
                      (jprev['RA'], jprev['dec'], jplan['RA'],
                       jplan['dec'], slew))
                print()
                print()
                os.system('tput bel; sleep 0.2; ' * 5)

            if slew > 35:
                # We risk a timeout -- modify the "slewread"
                # script we write out so that we read out before
                # commanding the telescope to move.
                print('Large slew from current exposure to next: reading out before moving the telescope')
                readout_during_move = False

            lasttile = jplan
            lastdate = self.obs.date

            if M is not None:
                if M['band'] == nextband:
                    nextsky = skybright
                else:
                    # Guess that the sky is as much brighter than canonical
                    # in the next band as it is in this one!
                    nextsky = ((skybright - nomsky) + self.nom.sky(nextband))
    
                fid = self.nom.fiducial_exptime(nextband)
                expfactor = exposure_factor(fid, self.nom,
                                            airmass, ebv, seeing, nextsky, trans)
                print('Exposure factor:', expfactor)
    
                expfactor_orig = expfactor
    
                # Adjust for previous exposures?
                if self.opt.adjust:
                    debug=True
                    adjfactor,others = self.adjust_for_previous(
                        tile, nextband, fid, debug=debug, get_others=True)
                    # Don't adjust exposure times down, only up.
                    adjfactor = max(adjfactor, 1.0)
                    expfactor *= adjfactor
                else:
                    adjfactor = 0.
                    others = []
    
                exptime = expfactor * fid.exptime
    
                ### HACK -- safety factor!
                print('Exposure time:', exptime)
                exptime *= 1.1
                print('Exposure time with safety factor:', exptime)
                exptime_unclipped = exptime
    
                exptime = np.clip(exptime, fid.exptime_min, fid.exptime_max)
                print('Clipped exptime', exptime)
    
                exptime_satclipped = 0.
                if nextband == 'z':
                    # Compute cap on exposure time to avoid saturation /
                    # loss of dynamic range.
                    t_sat = self.nom.saturation_time(nextband, nextsky)
                    if exptime > t_sat:
                        exptime_satclipped = t_sat
                        exptime = t_sat
                        print('Reduced exposure time to avoid z-band saturation:',
                        '%.1f' % exptime)
                exptime = int(np.ceil(exptime))
    
                print('Changing exptime from', jplan['expTime'], 'to', exptime)
                jplan['expTime'] = exptime

                # Update the computed exposure-time database.
                if self.opt.db:
                    try:
                        # NOTE, these kwargs MUST match the names in models.py
                        self.update_exptime_db(
                            nextseq, others, tileid=tile.tileid,
                            passnumber=nextpass, band=nextband, airmass=airmass,
                            ebv=ebv, meas_band=meas_band,
                            zeropoint=M['zp'], transparency=trans,
                            seeing=seeing, sky=skybright, expfactor=expfactor_orig,
                            adjfactor=adjfactor,
                            exptime_unclipped=exptime_unclipped,
                            exptime_satclipped=exptime_satclipped,
                            exptime=exptime)
                    except:
                        print('Failed to update computed-exptime database.')
                        import traceback
                        traceback.print_exc()
                        # carry on
                
            print('Predict tile will be observed at', str(self.obs.date),
                  'vs approx_datetime', jplan.get('approx_datetime',None))

            status = ('Exp %i: Tile %s, Pass %i, RA %s, Dec %s' %
                      (nextseq, tilename, nextpass, rastr, decstr))

            print('%s: updating exposure %i to tile %s' %
                  (str(ephem.now()), nextseq, tilename))

            expscriptfn = expscriptpat % (nextseq)
            exptmpfn = expscriptfn + '.tmp'
            f = open(exptmpfn, 'w')
            f.write(('# Exp %i Tile: %s, set at Seq %i, %s\n' %
                     (nextseq, tilename, seqnum, str(ephem.now()))) +
                    expscript_for_json(jplan, status=status))
            f.close()

            slewscriptfn = slewscriptpat % (nextseq)
            slewtmpfn = slewscriptfn + '.tmp'
            f = open(slewtmpfn, 'w')
            f.write(slewscript_for_json(jplan, readout_during_move=readout_during_move))
            f.close()

            os.rename(exptmpfn, expscriptfn)
            print('Wrote', expscriptfn)
            os.rename(slewtmpfn, slewscriptfn)
            print('Wrote', slewscriptfn)

            exptime = jplan['expTime']
            self.obs.date += (exptime + self.nom.overhead) / 86400.

            print('%s: updated exposure %i to tile %s' %
                  (str(ephem.now()), nextseq, tilename))

            P.tilename.append(tilename)
            P.filter.append(nextband)
            P.exptime.append(exptime)
            P.ra.append(jplan['RA'])
            P.dec.append(jplan['dec'])
            P.passnumber.append(nextpass)
            P.type.append('P')

        if iahead < self.Nahead:
            # We ran out of tiles.
            # Overwrite the default planned exposures with blanks to avoid
            # running the defaults (eg, at end of night).
            seqstart = seqnum + 1 + iahead
            seqend = self.n_exposures
            print('Overwriting remaining exposure scripts (%i to %i inclusive) with blanks.' % (seqstart, seqend))
            for nextseq in range(seqstart, seqend+1):
                print('Blanking out exposure %i' % nextseq)
                fn = self.expscriptpattern % nextseq
                path = os.path.join(self.scriptdir, fn)
                f = open(path, 'w')
                f.write('\n')
                f.close()
                fn = self.slewscriptpattern % nextseq
                path = os.path.join(self.scriptdir, fn)
                f = open(path, 'w')
                f.write('\n')
                f.close()

        for i,J in enumerate([self.J1,self.J2,self.J3]):
            passnum = i+1
            for j in J:
                tstart = ephem.Date(str(j['approx_datetime']))
                if self.opt.cut_before_now and tstart < now:
                    continue
                P.tilename.append(str(j['object']))
                filt = str(j['filter'])[0]
                P.filter.append(filt)
                P.exptime.append(j['expTime'])
                P.ra.append(j['RA'])
                P.dec.append(j['dec'])
                P.passnumber.append(passnum)
                P.type.append('%i' % passnum)

        P.to_np_arrays()
        fn = 'mosbot-plan.fits'
        tmpfn = fn + '.tmp'
        P.writeto(tmpfn)
        os.rename(tmpfn, fn)
        print('Wrote', fn)

        return True
Ejemplo n.º 24
0
def main():
    import optparse
    import sys

    parser = optparse.OptionParser(usage='%prog <json>')
    parser.add_option('--base', default='plan', help='Plot base filename')
    parser.add_option('-t', '--obstatus', help='Show already-observed tiles?')
    parser.add_option(
        '--bands',
        help='Plot only already-observed tiles in the given bands',
        default='g,r,z')
    parser.add_option('--sgc', action='store_true', help='Center on SGC?')

    parser.add_option('--ralo', type=float, default=None)
    parser.add_option('--rahi', type=float, default=None)
    parser.add_option('--declo', type=float, default=None)
    parser.add_option('--dechi', type=float, default=None)
    parser.add_option(
        '--scaled',
        action='store_true',
        default=False,
        help='Scale plot so that 1 deg RA = 1 deg Dec (no COS term)')
    parser.add_option('--wide',
                      action='store_true',
                      default=False,
                      help='Make wider plots?')

    parser.add_option('--also',
                      action='append',
                      default=[],
                      help='Also plot the plan from the given filename.')

    parser.add_option('--mosaic',
                      action='store_true',
                      help='Set defaults for Mosaic survey')

    parser.add_option(
        '--start-time',
        help=
        'Start time for this plan, HH:MM:SS UTC.  Default: 12-degree twilight tonight.'
    )
    parser.add_option('--start-date',
                      help='Start date for this plan, YYYY-MM-DD UTC.')

    parser.add_option(
        '--stop-time',
        help='Stop time for this plan, HH:MM:SS UTC.  Default: no limit.')

    parser.add_option(
        '--second-half',
        action='store_true',
        help='This plan starts at the start of the second half-night.')

    parser.add_option('--skip',
                      type=int,
                      default=1,
                      help='Write every Nth plot only')

    parser.add_option('--threads', type=int, help='Multi-processing?')

    opt, args = parser.parse_args()
    if len(args) != 1:
        parser.print_help()
        sys.exit(-1)

    if opt.mosaic:
        dd = dict(ralo=0, rahi=360, declo=30, dechi=88)
    else:
        dd = dict(ralo=0, rahi=360, declo=-10, dechi=35)
    for k in dd.keys():
        if getattr(opt, k, None) is None:
            setattr(opt, k, dd[k])

    start_date_specified = (opt.start_date is not None)

    if opt.start_date is None:
        # Get date at start of night, where we define a new day as
        # starting at noon UTC.
        now = datetime.datetime.utcnow()
        # noon
        nightstart = now - datetime.timedelta(0, 12 * 3600)
        d = nightstart.date()
        opt.start_date = '%04i-%02i-%02i' % (d.year, d.month, d.day)
        print('Set start date to', opt.start_date)

    if opt.mosaic:
        from camera_mosaic import ephem_observer
    else:
        from camera_decam import ephem_observer
    obs = ephem_observer()

    obs.temp = 10.0  # deg celsius; average temp for August
    obs.pressure = 780.0  # mbar

    ### HACK
    obs.date = ephem.Date(opt.start_date + ' 8:00:00')
    #print('Obs date:', obs.date)
    daystart = obs.date
    obs.horizon = -ephem.degrees('12:00:00.0')
    sun = ephem.Sun()
    eve_twi = obs.next_setting(sun)
    obs.date = eve_twi
    morn_twi = obs.next_rising(sun)
    print('Evening twilight:', eve_twi)
    print('Morning twilight:', morn_twi)
    assert (morn_twi > eve_twi)
    obs.horizon = 0.
    print('Eve twi:', eve_twi, 'Morning:', morn_twi)

    if opt.second_half:
        # Set start-time to the midpoint between 12-degree twilights.
        obs.date = ephem.Date((eve_twi + morn_twi) / 2.)
        print('Second half starts at', obs.date)

    elif opt.start_time is None:
        # 12-degree twilight on start_date
        obs.date = eve_twi

    else:
        obs.date = ephem.Date(opt.start_date + ' ' + opt.start_time)
        if not start_date_specified and obs.date < daystart:
            # If --start-date is, eg, 2am, assume it's during the night starting on daystart.
            obs.date = ephem.Date(float(obs.date) + 1.)
        print('Start date:', obs.date)

    if opt.stop_time is not None:
        # The date should be unambiguous -- try the same as obs.date =
        # start time, add one day if necessary.
        date = obs.date.datetime()
        stopdate = ephem.Date('%04i-%02i-%02i' %
                              (date.year, date.month, date.day) + ' ' +
                              opt.stop_time)
        if stopdate < obs.date:
            stopdate = ephem.Date(float(stopdate) + 1.)
        print('Stop date:', stopdate)

    jfn = args[0]
    print('Reading JSON file', jfn)
    J = json.loads(open(jfn, 'rb').read())
    print(len(J), 'entries')

    Jalso = [json.loads(open(fn, 'rb').read()) for fn in opt.also]

    # Get times when exposures should occur.
    times = []
    LSTs = []

    # If the JSON files include estimated times, use those
    if 'approx_datetime' in J[0]:
        for i, j in enumerate(J):
            obs.date = ephem.Date(str(j['approx_datetime']))
            if opt.stop_time is not None and obs.date > stopdate:
                print('Tile', i, 'is after --stopdate')
                J = J[:i]
                assert (len(J) == len(times))
                break
            times.append(ephem.Date(obs.date))
            LSTs.append(np.rad2deg(float(obs.sidereal_time())))
            print('Date', obs.date)
            print('LST', obs.sidereal_time())
    else:
        # Predict overheads
        lastra, lastdec = None, None
        for i in range(len(J)):
            print('Exposure', i, 'should start at', str(obs.date))
            if opt.stop_time is not None and obs.date > stopdate:
                print('Tile', J[i], 'is after --stopdate')
                break
            times.append(ephem.Date(obs.date))
            LSTs.append(np.rad2deg(float(obs.sidereal_time())))
            overhead = 30.
            if lastra is not None:
                slew = degrees_between(lastra, lastdec, ras[i], decs[i])
                lastra = ras[i]
                lastdec = decs[i]
                # Add 3 seconds per degree for slews longer than 2 degrees
                overhead += np.maximum(0, slew - 2.) * 3.
            # Add overhead
            print('Adding', exptime[i], 'seconds exptime plus', overhead,
                  'seconds overhead')
            obs.date += (exptime[i] + overhead) / (24 * 3600.)

    tiles = None
    if opt.obstatus is not None:
        from astrometry.util.fits import fits_table

        tiles = fits_table(opt.obstatus)
        print('Read', len(tiles), 'tiles')
        tiles = tiles[(tiles.in_des == 0) * np.logical_or(
            (tiles.in_sdss == 1), (tiles.in_sdss == 0) * (tiles.in_desi == 1))]
        print(len(tiles), 'in footprint')

    fcmap = dict(g='g', r='r', z='m', zd='m')
    ddecmap = dict(g=-0.2, r=0, z=0.2, zd=0.2)

    ras = np.array([j['RA'] for j in J])
    decs = np.array([j['dec'] for j in J])
    filts = np.array([j['filter'] for j in J])
    exptime = np.array([j['expTime'] for j in J])
    fieldname = [j['object'] for j in J]
    passnum = np.zeros(len(J), int)

    filtcc = np.array([fcmap[f] for f in filts])
    ddecs = np.array([ddecmap[f] for f in filts])

    # passmap = { 1: dict(marker='.'),
    #             2: dict(marker='o', mfc='none'),
    #             3: dict(marker='x') }
    passmap = {
        1: dict(marker='.'),
        2: dict(marker='.'),
        3: dict(marker='.'),
    }

    opt.bands = opt.bands.split(',')
    if len(opt.bands) == 1:
        filtddec = {'g': 0, 'r': 0, 'z': 0}
    else:
        ddec = 0.4
        filtddec = {'g': -ddec, 'r': 0, 'z': ddec}

    seqmap = ['r', 'y', 'g', 'b', 'm']
    #seqcc = np.array([seqmap[s % len(seqmap)] for s in seqnum])
    #seqcc = np.array([seqmap[s % len(seqmap)] for s in seqid])

    ax = [
        transform_ra(opt.rahi, opt),
        transform_ra(opt.ralo, opt), opt.declo, opt.dechi
    ]

    alsocolors = 'kbr'

    also = []
    for Ja in Jalso:
        # We assume the --also plan files contain approx_datetime...
        atimes = np.array([ephem.Date(str(j['approx_datetime'])) for j in Ja])
        aras = np.array([j['RA'] for j in Ja])
        adecs = np.array([j['dec'] for j in Ja])
        afilts = np.array([j['filter'] for j in Ja])
        aexptime = np.array([j['expTime'] for j in Ja])
        afieldname = [j['object'] for j in Ja]
        apassnum = np.zeros(len(Ja), int)
        if tiles is not None:
            for i, f in enumerate(afieldname):
                tile = get_tile_from_name(f, tiles)
                if tile is None:
                    continue
                pa = tile.get('pass')
                apassnum[i] = pa
        also.append(
            (atimes, aras, adecs, afilts, aexptime, afieldname, apassnum))

    # Try to get the pass number via parsing the field name to get tile id
    # and looking up the pass number in the tiles table.
    if tiles is not None:
        for i, f in enumerate(fieldname):
            tile = get_tile_from_name(f, tiles)
            if tile is None:
                continue
            pa = tile.get('pass')
            passnum[i] = pa
            print('Field', f, 'tileid', tile.tileid, 'pass', pa)

    allargs = []
    for i in reversed(range(0, len(J), opt.skip)):
        #print('Exposure', i, 'of', len(J))
        fn = '%s-%03i.png' % (opt.base, i)
        fn = os.path.join(os.path.dirname(args[0]), fn)
        pargs = (opt, ax, tiles, filtddec, fcmap, passmap, also, LSTs, times,
                 ras, decs, ddecs, fieldname, passnum, exptime, i, filtcc,
                 alsocolors, ddecmap, fn)
        allargs.append(pargs)

    if opt.threads:
        from astrometry.util.multiproc import multiproc
        mp = multiproc(opt.threads, init=plot_init)
        mp.map(plot_one, allargs)
    else:
        plot_init()
        map(plot_one, allargs)
    #plot_one(pargs)

    print()
    cmd = 'avconv -r 4 -i %s-%%03d.png -y %s.mov' % (opt.base, opt.base)
    print(cmd)
    os.system(cmd)
Ejemplo n.º 25
0
def cat_sdss(req, ver):
    import json
    import numpy as np
    from astrometry.util.starutil_numpy import degrees_between, radectoxyz, xyztoradec
    from map.views import sdss_ccds_near
    from astrometry.util.fits import fits_table, merge_tables

    tag = 'sdss-cat'
    ralo = float(req.GET['ralo'])
    rahi = float(req.GET['rahi'])
    declo = float(req.GET['declo'])
    dechi = float(req.GET['dechi'])

    ver = int(ver)
    if not ver in catversions[tag]:
        raise RuntimeError('Invalid version %i for tag %s' % (ver, tag))

    rad = degrees_between(ralo, declo, rahi, dechi) / 2.
    xyz1 = radectoxyz(ralo, declo)
    xyz2 = radectoxyz(rahi, dechi)
    xyz = (xyz1 + xyz2)
    xyz /= np.sqrt(np.sum(xyz**2))
    rc, dc = xyztoradec(xyz)
    rad = rad + np.hypot(10., 14.) / 2. / 60.
    ccds = sdss_ccds_near(rc[0], dc[0], rad)
    if ccds is None:
        print('No SDSS CCDs nearby')
        return HttpResponse(json.dumps(dict(rd=[])),
                            content_type='application/json')
    print(len(ccds), 'SDSS CCDs')

    T = []
    for ccd in ccds:
        # env/BOSS_PHOTOOBJ/301/2073/3/photoObj-002073-3-0088.fits
        fn = os.path.join(
            settings.SDSS_BASEDIR, 'env', 'BOSS_PHOTOOBJ', str(ccd.rerun),
            str(ccd.run), str(ccd.camcol),
            'photoObj-%06i-%i-%04i.fits' % (ccd.run, ccd.camcol, ccd.field))
        print('Reading', fn)
        T.append(
            fits_table(
                fn,
                columns=
                'ra dec objid mode objc_type objc_flags objc_flags nchild tai expflux devflux psfflux cmodelflux fracdev mjd'
                .split()))
    T = merge_tables(T)
    T.cut((T.dec >= declo) * (T.dec <= dechi))
    # FIXME
    T.cut((T.ra >= ralo) * (T.ra <= rahi))

    # primary
    T.cut(T.mode == 1)
    types = ['P' if t == 6 else 'C' for t in T.objc_type]
    fluxes = [
        p if t == 6 else c
        for t, p, c in zip(T.objc_type, T.psfflux, T.cmodelflux)
    ]

    return HttpResponse(json.dumps(
        dict(
            rd=[(float(o.ra), float(o.dec)) for o in T],
            sourcetype=types,
            fluxes=[
                dict(u=float(f[0]),
                     g=float(f[1]),
                     r=float(f[2]),
                     i=float(f[3]),
                     z=float(f[4])) for f in fluxes
            ],
        )),
                        content_type='application/json')
Ejemplo n.º 26
0
def map_decals_wl(req, ver, zoom, x, y):
    tag = 'decals-wl'
    ignoreCached = False
    filename = None
    forcecache = False

    from decals import settings
    savecache = settings.SAVE_CACHE

    zoom = int(zoom)
    zoomscale = 2.**zoom
    x = int(x)
    y = int(y)
    if zoom < 0 or x < 0 or y < 0 or x >= zoomscale or y >= zoomscale:
        raise RuntimeError('Invalid zoom,x,y %i,%i,%i' % (zoom,x,y))
    ver = int(ver)
    if not ver in tileversions[tag]:
        raise RuntimeError('Invalid version %i for tag %s' % (ver, tag))

    basedir = settings.DATA_DIR
    tilefn = os.path.join(basedir, 'tiles', tag,
                          '%i/%i/%i/%i.jpg' % (ver, zoom, x, y))
    if os.path.exists(tilefn) and not ignoreCached:
        print('Cached:', tilefn)
        return send_file(tilefn, 'image/jpeg', expires=oneyear,
                         modsince=req.META.get('HTTP_IF_MODIFIED_SINCE'),
                         filename=filename)
    else:
        print('Tile image does not exist:', tilefn)
    from astrometry.util.resample import resample_with_wcs, OverlapError
    from astrometry.util.util import Tan
    from astrometry.libkd.spherematch import match_radec
    from astrometry.util.fits import fits_table
    from astrometry.util.starutil_numpy import degrees_between
    import numpy as np
    import fitsio

    try:
        wcs, W, H, zoomscale, zoom,x,y = get_tile_wcs(zoom, x, y)
    except RuntimeError as e:
        return HttpResponse(e.strerror)

    mydir = os.path.join(basedir, 'coadd', 'weak-lensing')

    rlo,d = wcs.pixelxy2radec(W, H/2)[-2:]
    rhi,d = wcs.pixelxy2radec(1, H/2)[-2:]
    r,d1 = wcs.pixelxy2radec(W/2, 1)[-2:]
    r,d2 = wcs.pixelxy2radec(W/2, H)[-2:]
    #dlo = min(d1, d2)
    #dhi = max(d1, d2)

    r,d = wcs.pixelxy2radec(W/2, H/2)[-2:]
    rad = degrees_between(r, d, rlo, d1)

    fn = os.path.join(mydir, 'index.fits')
    if not os.path.exists(fn):
        #
        ii,rr,dd = [],[],[]
        for i in range(1, 52852+1):
            imgfn = os.path.join(mydir, 'map%i.fits' % i)
            hdr = fitsio.read_header(imgfn)
            r = hdr['CRVAL1']
            d = hdr['CRVAL2']
            ii.append(i)
            rr.append(r)
            dd.append(d)
        T = fits_table()
        T.ra  = np.array(rr)
        T.dec = np.array(dd)
        T.i   = np.array(ii)
        T.writeto(fn)

    T = fits_table(fn)
    I,J,d = match_radec(T.ra, T.dec, r, d, rad + 0.2)
    T.cut(I)
    print(len(T), 'weak-lensing maps in range')
    
    if len(I) == 0:
        from django.http import HttpResponseRedirect
        if forcecache:
            # create symlink to blank.jpg!
            trymakedirs(tilefn)
            src = os.path.join(settings.STATIC_ROOT, 'blank.jpg')
            if os.path.exists(tilefn):
                os.unlink(tilefn)
            os.symlink(src, tilefn)
            print('Symlinked', tilefn, '->', src)
        return HttpResponseRedirect(settings.STATIC_URL + 'blank.jpg')

    r,d = wcs.pixelxy2radec([1,1,1,W/2,W,W,W,W/2],
                            [1,H/2,H,H,H,H/2,1,1])[-2:]

    foundany = False
    rimg = np.zeros((H,W), np.float32)
    rn   = np.zeros((H,W), np.uint8)
    for tilei in T.i:
        fn = os.path.join(mydir, 'map%i.fits' % tilei)
        try:
            bwcs = _read_tan_wcs(fn, 0)
        except:
            print('Failed to read WCS:', fn)
            savecache = False
            import traceback
            import sys
            traceback.print_exc(None, sys.stdout)
            continue

        foundany = True
        print('Reading', fn)
        ok,xx,yy = bwcs.radec2pixelxy(r, d)
        xx = xx.astype(np.int)
        yy = yy.astype(np.int)
        imW,imH = int(bwcs.get_width()), int(bwcs.get_height())
        M = 10
        xlo = np.clip(xx.min() - M, 0, imW)
        xhi = np.clip(xx.max() + M, 0, imW)
        ylo = np.clip(yy.min() - M, 0, imH)
        yhi = np.clip(yy.max() + M, 0, imH)
        if xlo >= xhi or ylo >= yhi:
            continue

        subwcs = bwcs.get_subimage(xlo, ylo, xhi-xlo, yhi-ylo)
        slc = slice(ylo,yhi), slice(xlo,xhi)
        try:
            f = fitsio.FITS(fn)[0]
            img = f[slc]
            del f
        except:
            print('Failed to read image and WCS:', fn)
            savecache = False
            import traceback
            import sys
            traceback.print_exc(None, sys.stdout)
            continue

        try:
            Yo,Xo,Yi,Xi,nil = resample_with_wcs(wcs, subwcs, [], 3)
        except OverlapError:
            print('Resampling exception')
            continue

        rimg[Yo,Xo] += img[Yi,Xi]
        rn  [Yo,Xo] += 1
    rimg /= np.maximum(rn, 1)

    if forcecache:
        savecache = True

    if savecache:
        trymakedirs(tilefn)
    else:
        import tempfile
        f,tilefn = tempfile.mkstemp(suffix='.jpg')
        os.close(f)

    import pylab as plt

    # S/N
    #lo,hi = 1.5, 5.0
    lo,hi = 0, 5.0
    rgb = plt.cm.hot((rimg - lo) / (hi - lo))
    plt.imsave(tilefn, rgb)
    print('Wrote', tilefn)

    return send_file(tilefn, 'image/jpeg', unlink=(not savecache),
                     filename=filename)
Ejemplo n.º 27
0
def cat_targets_drAB(req,
                     ver,
                     cats=[],
                     tag='',
                     bgs=False,
                     sky=False,
                     bright=False,
                     dark=False,
                     color_name_func=desitarget_color_names):
    '''
    color_name_func: function that selects names and colors for targets
    (eg based on targeting bit values)
    '''

    import json
    ralo = float(req.GET['ralo'])
    rahi = float(req.GET['rahi'])
    declo = float(req.GET['declo'])
    dechi = float(req.GET['dechi'])

    ver = int(ver)
    if not ver in catversions[tag]:
        raise RuntimeError('Invalid version %i for tag %s' % (ver, tag))

    from astrometry.util.fits import fits_table, merge_tables
    from astrometry.libkd.spherematch import tree_open, tree_search_radec
    import numpy as np
    from astrometry.util.starutil_numpy import radectoxyz, xyztoradec, degrees_between

    xyz1 = radectoxyz(ralo, declo)
    xyz2 = radectoxyz(rahi, dechi)
    xyz = (xyz1 + xyz2) / 2.
    xyz /= np.sqrt(np.sum(xyz**2))
    rc, dc = xyztoradec(xyz)
    rc = rc[0]
    dc = dc[0]
    rad = degrees_between(rc, dc, ralo, declo)
    '''
    startree -i /project/projectdirs/desi/target/catalogs/targets-dr4-0.20.0.fits -o data/targets-dr4-0.20.0.kd.fits -P -k -T
    '''
    TT = []
    for fn in cats:
        kd = tree_open(fn)
        I = tree_search_radec(kd, rc, dc, rad)
        print('Matched', len(I), 'from', fn)
        if len(I) == 0:
            continue
        T = fits_table(fn, rows=I)
        TT.append(T)
    if len(TT) == 0:
        return HttpResponse(json.dumps(dict(rd=[], name=[])),
                            content_type='application/json')
    T = merge_tables(TT, columns='fillzero')

    if bgs:
        T.cut(T.bgs_target > 0)

    if bright:
        T.cut(np.logical_or(T.bgs_target > 0, T.mws_target > 0))

    if dark:
        T.cut(T.desi_target > 0)

    names = None
    colors = None
    if color_name_func is not None:
        names, colors = color_name_func(T)

    if sky:
        fluxes = [
            dict(g=float(g), r=float(r), z=float(z))
            for (g, r, z) in zip(T.apflux_g[:,
                                            0], T.apflux_r[:,
                                                           0], T.apflux_z[:,
                                                                          0])
        ]
        nobs = None
    else:
        fluxes = [
            dict(g=float(g),
                 r=float(r),
                 z=float(z),
                 W1=float(W1),
                 W2=float(W2))
            for (g, r, z, W1,
                 W2) in zip(T.flux_g, T.flux_r, T.flux_z, T.flux_w1, T.flux_w2)
        ]
        nobs = [
            dict(g=int(g), r=int(r), z=int(z))
            for g, r, z in zip(T.nobs_g, T.nobs_r, T.nobs_z)
        ],

    rtn = dict(
        rd=[(t.ra, t.dec) for t in T],
        targetid=[int(t) for t in T.targetid],
        fluxes=fluxes,
    )
    if names is not None:
        rtn.update(name=names)
    if colors is not None:
        rtn.update(color=colors)
    if nobs is not None:
        rtn.update(nobs=nobs)
    return HttpResponse(json.dumps(rtn), content_type='application/json')
Ejemplo n.º 28
0
def map_sdss(req,
             ver,
             zoom,
             x,
             y,
             savecache=None,
             tag='sdss',
             get_images=False,
             ignoreCached=False,
             wcs=None,
             forcecache=False,
             forcescale=None,
             bestOnly=False,
             bands='gri',
             **kwargs):
    from decals import settings

    if savecache is None:
        savecache = settings.SAVE_CACHE
    zoom = int(zoom)
    zoomscale = 2.**zoom
    x = int(x)
    y = int(y)
    if zoom < 0 or x < 0 or y < 0 or x >= zoomscale or y >= zoomscale:
        raise RuntimeError('Invalid zoom,x,y %i,%i,%i' % (zoom, x, y))
    ver = int(ver)

    if not ver in tileversions[tag]:
        raise RuntimeError('Invalid version %i for tag %s' % (ver, tag))

    basedir = settings.DATA_DIR
    tilefn = os.path.join(basedir, 'tiles', tag,
                          '%i/%i/%i/%i.jpg' % (ver, zoom, x, y))
    if os.path.exists(tilefn) and not ignoreCached:
        if get_images:
            return None
        return send_file(tilefn,
                         'image/jpeg',
                         expires=oneyear,
                         modsince=req.META.get('HTTP_IF_MODIFIED_SINCE'))

    if not savecache:
        import tempfile
        f, tilefn = tempfile.mkstemp(suffix='.jpg')
        os.close(f)

    if wcs is None:
        try:
            wcs, W, H, zoomscale, zoom, x, y = get_tile_wcs(zoom, x, y)
        except RuntimeError as e:
            if get_images:
                return None
            return HttpResponse(e.strerror)
    else:
        W = wcs.get_width()
        H = wcs.get_height()

    from astrometry.util.fits import fits_table
    import numpy as np
    from astrometry.libkd.spherematch import tree_build_radec, tree_search_radec
    from astrometry.util.starutil_numpy import degrees_between, arcsec_between
    from astrometry.util.resample import resample_with_wcs, OverlapError
    from astrometry.util.util import Tan, Sip
    import fitsio

    print('Tile wcs: center', wcs.radec_center(), 'pixel scale',
          wcs.pixel_scale())

    global w_flist
    global w_flist_tree
    if w_flist is None:
        w_flist = fits_table(
            os.path.join(settings.DATA_DIR, 'sdss', 'window_flist.fits'),
            columns=['run', 'rerun', 'camcol', 'field', 'ra', 'dec', 'score'])
        print('Read', len(w_flist), 'window_flist entries')
        w_flist.cut(w_flist.rerun == '301')
        print('Cut to', len(w_flist), 'in rerun 301')
        w_flist_tree = tree_build_radec(w_flist.ra, w_flist.dec)

    # SDSS field size
    radius = 1.01 * np.hypot(10., 14.) / 2. / 60.

    # leaflet tile size
    ra, dec = wcs.pixelxy2radec(W / 2., H / 2.)[-2:]
    r0, d0 = wcs.pixelxy2radec(1, 1)[-2:]
    r1, d1 = wcs.pixelxy2radec(W, H)[-2:]
    radius = radius + max(degrees_between(ra, dec, r0, d0),
                          degrees_between(ra, dec, r1, d1))

    J = tree_search_radec(w_flist_tree, ra, dec, radius)

    print(len(J), 'overlapping SDSS fields found')
    if len(J) == 0:
        if get_images:
            return None
        if forcecache:
            # create symlink to blank.jpg!
            trymakedirs(tilefn)
            src = os.path.join(settings.STATIC_ROOT, 'blank.jpg')
            if os.path.exists(tilefn):
                os.unlink(tilefn)
            os.symlink(src, tilefn)
            print('Symlinked', tilefn, '->', src)
        from django.http import HttpResponseRedirect
        return HttpResponseRedirect(settings.STATIC_URL + 'blank.jpg')

    ww = [1, W * 0.25, W * 0.5, W * 0.75, W]
    hh = [1, H * 0.25, H * 0.5, H * 0.75, H]

    r, d = wcs.pixelxy2radec(
        [1] * len(hh) + ww + [W] * len(hh) + list(reversed(ww)),
        hh + [1] * len(ww) + list(reversed(hh)) + [H] * len(ww))[-2:]

    scaled = 0
    scalepat = None
    scaledir = 'sdss'

    if zoom <= 13 and forcescale is None:
        # Get *actual* pixel scales at the top & bottom
        r1, d1 = wcs.pixelxy2radec(W / 2., H)[-2:]
        r2, d2 = wcs.pixelxy2radec(W / 2., H - 1.)[-2:]
        r3, d3 = wcs.pixelxy2radec(W / 2., 1.)[-2:]
        r4, d4 = wcs.pixelxy2radec(W / 2., 2.)[-2:]
        # Take the min = most zoomed-in
        scale = min(arcsec_between(r1, d1, r2, d2),
                    arcsec_between(r3, d3, r4, d4))

        native_scale = 0.396
        scaled = int(np.floor(np.log2(scale / native_scale)))
        print('Zoom:', zoom, 'x,y', x, y, 'Tile pixel scale:', scale,
              'Scale step:', scaled)
        scaled = np.clip(scaled, 1, 7)
        dirnm = os.path.join(basedir, 'scaled', scaledir)
        scalepat = os.path.join(
            dirnm, '%(scale)i%(band)s', '%(rerun)s', '%(run)i', '%(camcol)i',
            'sdss-%(run)i-%(camcol)i-%(field)i-%(band)s.fits')

    if forcescale is not None:
        scaled = forcescale

    rimgs = [np.zeros((H, W), np.float32) for band in bands]
    rns = [np.zeros((H, W), np.float32) for band in bands]

    from astrometry.sdss import AsTransWrapper, DR9
    sdss = DR9(basedir=settings.SDSS_DIR)
    sdss.saveUnzippedFiles(settings.SDSS_DIR)
    #sdss.setFitsioReadBZ2()
    if settings.SDSS_PHOTOOBJS:
        sdss.useLocalTree(photoObjs=settings.SDSS_PHOTOOBJS,
                          resolve=settings.SDSS_RESOLVE)

    for jnum, j in enumerate(J):
        print('SDSS field', jnum, 'of', len(J), 'for zoom', zoom, 'x', x, 'y',
              y)
        im = w_flist[j]

        if im.score >= 0.5:
            weight = 1.
        else:
            weight = 0.001

        for band, rimg, rn in zip(bands, rimgs, rns):
            if im.rerun != '301':
                continue
            tmpsuff = '.tmp%08i' % np.random.randint(100000000)
            basefn = sdss.retrieve('frame',
                                   im.run,
                                   im.camcol,
                                   field=im.field,
                                   band=band,
                                   rerun=im.rerun,
                                   tempsuffix=tmpsuff)
            if scaled > 0:
                fnargs = dict(band=band,
                              rerun=im.rerun,
                              run=im.run,
                              camcol=im.camcol,
                              field=im.field)
                fn = get_scaled(scalepat,
                                fnargs,
                                scaled,
                                basefn,
                                read_base_wcs=read_astrans,
                                read_wcs=read_sip_wcs)
                print('get_scaled:', fn)
            else:
                fn = basefn
            frame = None
            if fn == basefn:
                frame = sdss.readFrame(im.run,
                                       im.camcol,
                                       im.field,
                                       band,
                                       filename=fn)
                h, w = frame.getImageShape()
                # Trim off the overlapping top of the image
                # Wimp out and instead of trimming 128 pix, trim 124!
                trim = 124
                subh = h - trim
                astrans = frame.getAsTrans()
                fwcs = AsTransWrapper(astrans, w, subh)
                fullimg = frame.getImage()
                fullimg = fullimg[:-trim, :]
            else:
                fwcs = Sip(fn)
                fitsimg = fitsio.FITS(fn)[0]
                h, w = fitsimg.get_info()['dims']
                fullimg = fitsimg.read()

            try:
                #Yo,Xo,Yi,Xi,nil = resample_with_wcs(wcs, fwcs, [], 3)
                Yo, Xo, Yi, Xi, [resamp
                                 ] = resample_with_wcs(wcs, fwcs, [fullimg], 2)
            except OverlapError:
                continue
            if len(Xi) == 0:
                #print 'No overlap'
                continue

            if sdssps is not None:
                x0 = Xi.min()
                x1 = Xi.max()
                y0 = Yi.min()
                y1 = Yi.max()
                slc = (slice(y0, y1 + 1), slice(x0, x1 + 1))
                if frame is not None:
                    img = frame.getImageSlice(slc)
                else:
                    img = fitsimg[slc]
            #rimg[Yo,Xo] += img[Yi-y0, Xi-x0]

            if bestOnly:
                K = np.flatnonzero(weight > rn[Yo, Xo])
                print('Updating', len(K), 'of', len(Yo), 'pixels')
                if len(K):
                    rimg[Yo[K], Xo[K]] = resamp[K] * weight
                    rn[Yo[K], Xo[K]] = weight
            else:
                rimg[Yo, Xo] += resamp * weight
                rn[Yo, Xo] += weight

            if sdssps is not None:
                # goodpix = np.ones(img.shape, bool)
                # fpM = sdss.readFpM(im.run, im.camcol, im.field, band)
                # for plane in [ 'INTERP', 'SATUR', 'CR', 'GHOST' ]:
                #     fpM.setMaskedPixels(plane, goodpix, False, roi=[x0,x1,y0,y1])
                plt.clf()
                #ima = dict(vmin=-0.05, vmax=0.5)
                #ima = dict(vmin=-0.5, vmax=2.)
                ima = dict(vmax=np.percentile(img, 99))
                plt.subplot(2, 3, 1)
                dimshow(img, ticks=False, **ima)
                plt.title('image')
                rthis = np.zeros_like(rimg)
                #rthis[Yo,Xo] += img[Yi-y0, Xi-x0]
                rthis[Yo, Xo] += resamp
                plt.subplot(2, 3, 2)
                dimshow(rthis, ticks=False, **ima)
                plt.title('resampled')
                # plt.subplot(2,3,3)
                # dimshow(goodpix, ticks=False, vmin=0, vmax=1)
                # plt.title('good pix')
                plt.subplot(2, 3, 4)
                dimshow(rimg / np.maximum(rn, 1), ticks=False, **ima)
                plt.title('coadd')
                plt.subplot(2, 3, 5)
                dimshow(rn, vmin=0, ticks=False)
                plt.title('coverage: max %i' % rn.max())
                plt.subplot(2, 3, 6)
                rgb = sdss_rgb(
                    [rimg / np.maximum(rn, 1) for rimg, rn in zip(rimgs, rns)],
                    bands)
                dimshow(rgb)
                plt.suptitle('SDSS %s, R/C/F %i/%i/%i' %
                             (band, im.run, im.camcol, im.field))
                sdssps.savefig()

    for rimg, rn in zip(rimgs, rns):
        rimg /= np.maximum(rn, 1e-3)
    del rns

    if get_images:
        return rimgs

    rgb = sdss_rgb(rimgs, bands)
    trymakedirs(tilefn)
    save_jpeg(tilefn, rgb)
    print('Wrote', tilefn)

    return send_file(tilefn, 'image/jpeg', unlink=(not savecache))
Ejemplo n.º 29
0
def cat_targets_drAB(req, ver, cats=None, tag='', bgs=False, sky=False, bright=False, dark=False, color_name_func=desitarget_color_names):
    '''
    color_name_func: function that selects names and colors for targets
    (eg based on targeting bit values)
    '''
    if cats is None:
        cats = []

    import json
    ralo = float(req.GET['ralo'])
    rahi = float(req.GET['rahi'])
    declo = float(req.GET['declo'])
    dechi = float(req.GET['dechi'])

    ver = int(ver)
    if not ver in catversions[tag]:
        raise RuntimeError('Invalid version %i for tag %s' % (ver, tag))

    from astrometry.util.fits import fits_table, merge_tables
    from astrometry.libkd.spherematch import tree_open, tree_search_radec
    import numpy as np
    from astrometry.util.starutil_numpy import radectoxyz, xyztoradec, degrees_between

    xyz1 = radectoxyz(ralo, declo)
    xyz2 = radectoxyz(rahi, dechi)
    xyz = (xyz1 + xyz2)/2.
    xyz /= np.sqrt(np.sum(xyz**2))
    rc,dc = xyztoradec(xyz)
    rc = rc[0]
    dc = dc[0]
    rad = degrees_between(rc, dc, ralo, declo)

    '''
    startree -i /project/projectdirs/desi/target/catalogs/targets-dr4-0.20.0.fits -o data/targets-dr4-0.20.0.kd.fits -P -k -T
    '''
    TT = []
    for fn in cats:
        kd = tree_open(fn)
        I = tree_search_radec(kd, rc, dc, rad)
        print('Matched', len(I), 'from', fn)
        if len(I) == 0:
            continue
        T = fits_table(fn, rows=I)
        TT.append(T)
    if len(TT) == 0:
        return HttpResponse(json.dumps(dict(rd=[], name=[])),
                            content_type='application/json')
    T = merge_tables(TT, columns='fillzero')

    if bgs:
        T.cut(T.bgs_target > 0)

    if bright:
        T.cut(np.logical_or(T.bgs_target > 0, T.mws_target > 0))

    if dark:
        T.cut(T.desi_target > 0)

    names = None
    colors = None
    if color_name_func is not None:
        names,colors = color_name_func(T)

    if sky:
        fluxes = [dict(g=float(g), r=float(r), z=float(z))
                  for (g,r,z) in zip(T.apflux_g[:,0], T.apflux_r[:,0], T.apflux_z[:,0])]
        nobs = None
    else:
        fluxes = [dict(g=float(g), r=float(r), z=float(z),
                       W1=float(W1), W2=float(W2))
                  for (g,r,z,W1,W2)
                  in zip(T.flux_g, T.flux_r, T.flux_z, T.flux_w1, T.flux_w2)]
        nobs=[dict(g=int(g), r=int(r), z=int(z)) for g,r,z
              in zip(T.nobs_g, T.nobs_r, T.nobs_z)],

    rtn = dict(rd=[(t.ra, t.dec) for t in T],
               targetid=[int(t) for t in T.targetid],
               fluxes=fluxes,
           )
    if names is not None:
        rtn.update(name=names)
    if colors is not None:
        rtn.update(color=colors)
    if nobs is not None:
        rtn.update(nobs=nobs)
    
    # Convert targetid to string to prevent rounding errors
    rtn['targetid'] = [str(s) for s in rtn['targetid']]
    
    return HttpResponse(json.dumps(rtn), content_type='application/json')
Ejemplo n.º 30
0
def run_tiles(X):
    tiles, tag = X
    print('Running', tag, '-', len(tiles), 'tiles')

    # Aaron's file has all images share the boresight CRVAL, so they have large CRPIX values.
    T = fits_table(
        '/global/cfs/cdirs/desi/users/ameisner/GFA/gfa_reduce_etc/gfa_wcs+focus.bigtan-zenith.fits'
    )

    Nbright = 10
    tiles_ann = fits_table()
    tiles_ann.index = tiles.index
    gfa_regions = []
    maxr = 0.

    #t.cd[0,0], t.cd[0,1], t.cd[1,0], t.cd[1,1],
    for t in T:
        wcs = Tan(0., 0., t.crpix[0], t.crpix[1], t.cd[0, 0], t.cd[1, 0],
                  t.cd[0, 1], t.cd[1, 1], float(t.naxis[0]), float(t.naxis[1]))
        ctype = t.extname[:5]
        cnum = int(t.extname[5])
        h, w = wcs.shape
        x, y = [1, 1, w, w, 1], [1, h, h, 1, 1]
        r, d = wcs.pixelxy2radec(x, y)
        dists = degrees_between(0., 0., r, d)
        maxr = max(maxr, max(dists))

        # x0, y0, x1, y1
        rois = []
        if ctype == 'FOCUS':
            # add the two half-chips.
            # wcs.get_subimage moves the CRPIX, but leave CRVAL unchanged, so tx,ty still work unchanged.
            # Aaron's WCS templates correct for the overscans
            #wcs_subs.append((cstr, cnum, 'a', wcs.get_subimage(0, 0, 1024, h)))
            #wcs_subs.append((cstr, cnum, 'b', wcs.get_subimage(1024, 0, 1024, h)))

            #all_sub_wcs[(cstr, cnum, 1)] = (tx, ty, wcs.get_subimage(50, 0, 1024, 1032))
            #all_sub_wcs[(cstr, cnum, 2)] = (tx, ty, wcs.get_subimage(1174, 0, 1024, 1032))
            # Add (negative) margin for donut size and telescope pointing uncertainty.
            # ~10" for donuts and ~10" for telescope pointing
            #margin = 100
            #wcs_subs.append((cstr, cnum, 'a_margin', wcs.get_subimage(margin, margin, 1024-2*margin, h-2*margin)))
            #wcs_subs.append((cstr, cnum, 'b_margin', wcs.get_subimage(1024+margin, margin, 1024-2*margin, h-2*margin)))

            # Also add a positive margin for bright-star reflections off filters
            #margin = 125
            #wcs_subs.append((cstr, cnum, 'expanded', wcs.get_subimage(-margin, -margin, w+2*margin, h+2*margin)))

            rois.append(('a', 0, 0, 1024, h))
            rois.append(('b', 1024, 0, 2048, h))
            margin = 100
            rois.append(
                ('a_margin', margin, margin, 1024 - margin, h - margin))
            rois.append(
                ('b_margin', 1024 + margin, margin, 2048 - margin, h - margin))

            margin = 125
            rois.append(('expanded', -margin, -margin, w + margin, h + margin))

        else:
            # Guide chips include overscan pixels -- including a blank region in the middle.
            #print(cstr,cnum, 'shape', wcs.shape)
            #wcs_subs.append((cstr, cnum, 'ccd', wcs))

            rois.append(('ccd', 0, 0, w, h))

            # Add expanded GUIDE chips -- 25" margin / 0.2"/pix = 125 pix
            margin = 125
            #wcs_subs.append((cstr, cnum, 'expanded', wcs.get_subimage(-margin, -margin, w+2*margin, h+2*margin)))
            rois.append(('expanded', -margin, -margin, w + margin, h + margin))

        margin = 125
        expwcs = wcs.get_subimage(-margin, -margin, w + 2 * margin,
                                  h + 2 * margin)

        newrois = []
        for tag, x0, y0, x1, y1 in rois:
            name = '%s_%i_%s' % (ctype.lower(), cnum, tag)
            arr = np.zeros(len(tiles), (np.float32, Nbright))
            tiles_ann.set('brightest_' + name, arr)
            # (the rois have zero-indexed x0,y0, and non-inclusive x1,y1!)
            newrois.append((name, arr, 1 + x0, 1 + y0, x1, y1))

        gfa_regions.append((ctype, cnum, wcs, expwcs, newrois))

    # DEBUG WCS
    # s = []
    # for ctype,cnum,wcs,expwcs,rois in gfa_regions:
    #     WCS = wcs
    #     h,w = WCS.shape
    #     #print('Expwcs:', w, 'x', h)
    #     x = [1,1,w,w,1]
    #     y = [1,h,h,1,1]
    #     r,d = WCS.pixelxy2radec(x, y)
    #     p = ','.join(['%.4f,%.4f' % (rr,dd) for rr,dd in zip(r,d)])
    #     s.append(p)
    # s = ';'.join(s)
    # print('http://legacysurvey.org/viewer/?ra=0&dec=0&poly='+s)
    # sys.exit(0)

    gaia = CachingGaiaCatalog(columns=[
        'ra', 'dec', 'phot_g_mean_mag', 'phot_bp_mean_mag', 'phot_rp_mean_mag',
        'astrometric_excess_noise', 'astrometric_params_solved', 'source_id',
        'pmra_error', 'pmdec_error', 'parallax_error', 'ra_error', 'dec_error',
        'pmra', 'pmdec', 'parallax', 'ref_epoch'
    ])

    tyc2fn = '/global/cfs/cdirs/cosmo/staging/tycho2/tycho2.kd.fits'
    tycho_kd = tree_open(tyc2fn)
    tycho_cat = fits_table(tyc2fn)

    maxrad = maxr * 1.05
    for itile, tile in enumerate(tiles):
        #if not tile.in_imaging:
        #    continue
        #if tile.centerid % 10 == 0:
        #print('tile program', tile.program, 'pass', tile.get('pass'), 'id', tile.centerid, gaia.get_healpix_tree.cache_info())

        I = tree_search_radec(tycho_kd, tile.ra, tile.dec, maxrad)
        tycstars = tycho_cat[I]
        fix_tycho(tycstars)

        for cstr, cname, chipwcs, bigwcs, rois in gfa_regions:
            h, w = chipwcs.shape
            chipwcs.set_crval(tile.ra, tile.dec)
            bigwcs.set_crval(tile.ra, tile.dec)
            gstars = gaia.get_catalog_in_wcs(bigwcs, step=1032, margin=0)
            fix_gaia(gstars)

            bh, bw = bigwcs.shape
            ok, x, y = bigwcs.radec2pixelxy(tycstars.ra, tycstars.dec)
            tstars = tycstars[(x >= 1) * (y >= 1) * (x <= bw) * (y <= bh)]

            #print('Tile', tile.program, 'p', tile.get('pass'), tile.centerid,
            #      'GFA', cstr, cname, ':', len(gstars), 'Gaia stars', len(tstars), 'Tycho-2 stars')

            if len(gstars) + len(tstars) == 0:
                print('No stars in tile centerid', tile.centerid, 'chip', name)
                continue

            if len(gstars) > 0 and len(tstars) > 0:
                merge_gaia_tycho(gstars, tstars)
                stars = merge_tables([gstars, tstars], columns='fillzero')
            elif len(tstars) > 0:
                stars = tstars
            else:
                stars = gstars

            ok, x, y = chipwcs.radec2pixelxy(stars.ra, stars.dec)

            for name, arr, x0, y0, x1, y1 in rois:
                J = np.flatnonzero(
                    (x >= x0) * (x <= x1) * (y >= y0) * (y <= y1))
                mags = stars.mag[J]
                #print('  ', len(mags), 'in name')
                K = np.argsort(mags)
                K = K[:Nbright]
                arr[itile, :len(K)] = mags[K]

    #tiles.add_columns_from(tiles_ann)
    return tiles_ann
Ejemplo n.º 31
0
def main(outfn='ccds-annotated.fits', ccds=None):
    decals = Decals()
    if ccds is None:
        ccds = decals.get_ccds()

    # File from the "observing" svn repo:
    # https://desi.lbl.gov/svn/decam/code/observing/trunk
    tiles = fits_table('decam-tiles_obstatus.fits')

    #ccds.cut(np.arange(100))
    #print("HACK!")
    #ccds.cut(np.array([name in ['N15', 'N16', 'N21', 'N9']
    #                   for name in ccds.ccdname]) *
    #                   ccds.expnum == 229683)

    I = decals.photometric_ccds(ccds)
    ccds.photometric = np.zeros(len(ccds), bool)
    ccds.photometric[I] = True

    I = decals.apply_blacklist(ccds)
    ccds.blacklist_ok = np.zeros(len(ccds), bool)
    ccds.blacklist_ok[I] = True

    ccds.good_region = np.empty((len(ccds), 4), np.int16)
    ccds.good_region[:, :] = -1

    ccds.ra0 = np.zeros(len(ccds), np.float64)
    ccds.dec0 = np.zeros(len(ccds), np.float64)
    ccds.ra1 = np.zeros(len(ccds), np.float64)
    ccds.dec1 = np.zeros(len(ccds), np.float64)
    ccds.ra2 = np.zeros(len(ccds), np.float64)
    ccds.dec2 = np.zeros(len(ccds), np.float64)
    ccds.ra3 = np.zeros(len(ccds), np.float64)
    ccds.dec3 = np.zeros(len(ccds), np.float64)

    ccds.dra = np.zeros(len(ccds), np.float32)
    ccds.ddec = np.zeros(len(ccds), np.float32)
    ccds.ra_center = np.zeros(len(ccds), np.float64)
    ccds.dec_center = np.zeros(len(ccds), np.float64)

    ccds.sig1 = np.zeros(len(ccds), np.float32)

    ccds.meansky = np.zeros(len(ccds), np.float32)
    ccds.stdsky = np.zeros(len(ccds), np.float32)
    ccds.maxsky = np.zeros(len(ccds), np.float32)
    ccds.minsky = np.zeros(len(ccds), np.float32)

    ccds.pixscale_mean = np.zeros(len(ccds), np.float32)
    ccds.pixscale_std = np.zeros(len(ccds), np.float32)
    ccds.pixscale_max = np.zeros(len(ccds), np.float32)
    ccds.pixscale_min = np.zeros(len(ccds), np.float32)

    ccds.psfnorm_mean = np.zeros(len(ccds), np.float32)
    ccds.psfnorm_std = np.zeros(len(ccds), np.float32)
    ccds.galnorm_mean = np.zeros(len(ccds), np.float32)
    ccds.galnorm_std = np.zeros(len(ccds), np.float32)

    gaussgalnorm = np.zeros(len(ccds), np.float32)

    # 2nd moments
    ccds.psf_mx2 = np.zeros(len(ccds), np.float32)
    ccds.psf_my2 = np.zeros(len(ccds), np.float32)
    ccds.psf_mxy = np.zeros(len(ccds), np.float32)
    #
    ccds.psf_a = np.zeros(len(ccds), np.float32)
    ccds.psf_b = np.zeros(len(ccds), np.float32)
    ccds.psf_theta = np.zeros(len(ccds), np.float32)
    ccds.psf_ell = np.zeros(len(ccds), np.float32)

    ccds.humidity = np.zeros(len(ccds), np.float32)
    ccds.outtemp = np.zeros(len(ccds), np.float32)

    ccds.tileid = np.zeros(len(ccds), np.int32)
    ccds.tilepass = np.zeros(len(ccds), np.uint8)
    ccds.tileebv = np.zeros(len(ccds), np.float32)

    plvers = []

    for iccd, ccd in enumerate(ccds):
        im = decals.get_image_object(ccd)
        print('Reading CCD %i of %i:' % (iccd + 1, len(ccds)), im)

        X = im.get_good_image_subregion()
        for i, x in enumerate(X):
            if x is not None:
                ccds.good_region[iccd, i] = x

        W, H = ccd.width, ccd.height

        psf = None
        wcs = None
        sky = None
        try:
            tim = im.get_tractor_image(pixPsf=True,
                                       splinesky=True,
                                       subsky=False,
                                       pixels=False)
        except:
            import traceback
            traceback.print_exc()
            plvers.append('')
            continue

        if tim is None:
            plvers.append('')
            continue

        psf = tim.psf
        wcs = tim.wcs.wcs
        sky = tim.sky
        hdr = tim.primhdr

        # print('Got PSF', psf)
        # print('Got sky', type(sky))
        # print('Got WCS', wcs)

        ccds.humidity[iccd] = hdr.get('HUMIDITY')
        ccds.outtemp[iccd] = hdr.get('OUTTEMP')

        ccds.sig1[iccd] = tim.sig1
        plvers.append(tim.plver)

        obj = hdr.get('OBJECT')
        # parse 'DECaLS_15150_r'
        words = obj.split('_')
        tile = None
        if len(words) == 3 and words[0] == 'DECaLS':
            try:
                tileid = int(words[1])
                tile = tiles[tileid - 1]
                if tile.tileid != tileid:
                    I = np.flatnonzero(tile.tileid == tileid)
                    tile = tiles[I[0]]
            except:
                pass

        if tile is not None:
            ccds.tileid[iccd] = tile.tileid
            ccds.tilepass[iccd] = tile.get('pass')
            ccds.tileebv[iccd] = tile.ebv_med

        # Instantiate PSF on a grid
        S = 32
        xx = np.linspace(1 + S, W - S, 5)
        yy = np.linspace(1 + S, H - S, 5)
        xx, yy = np.meshgrid(xx, yy)
        psfnorms = []
        galnorms = []
        for x, y in zip(xx.ravel(), yy.ravel()):
            p = im.psf_norm(tim, x=x, y=y)
            g = im.galaxy_norm(tim, x=x, y=y)
            psfnorms.append(p)
            galnorms.append(g)
        ccds.psfnorm_mean[iccd] = np.mean(psfnorms)
        ccds.psfnorm_std[iccd] = np.std(psfnorms)
        ccds.galnorm_mean[iccd] = np.mean(galnorms)
        ccds.galnorm_std[iccd] = np.std(galnorms)

        # PSF in center of field
        cx, cy = (W + 1) / 2., (H + 1) / 2.
        p = psf.getPointSourcePatch(cx, cy).patch
        ph, pw = p.shape
        px, py = np.meshgrid(np.arange(pw), np.arange(ph))
        psum = np.sum(p)
        # print('psum', psum)
        p /= psum
        # centroids
        cenx = np.sum(p * px)
        ceny = np.sum(p * py)
        # print('cenx,ceny', cenx,ceny)
        # second moments
        x2 = np.sum(p * (px - cenx)**2)
        y2 = np.sum(p * (py - ceny)**2)
        xy = np.sum(p * (px - cenx) * (py - ceny))
        # semi-major/minor axes and position angle
        theta = np.rad2deg(np.arctan2(2 * xy, x2 - y2) / 2.)
        theta = np.abs(theta) * np.sign(xy)
        s = np.sqrt(((x2 - y2) / 2.)**2 + xy**2)
        a = np.sqrt((x2 + y2) / 2. + s)
        b = np.sqrt((x2 + y2) / 2. - s)
        ell = 1. - b / a

        # print('PSF second moments', x2, y2, xy)
        # print('PSF position angle', theta)
        # print('PSF semi-axes', a, b)
        # print('PSF ellipticity', ell)

        ccds.psf_mx2[iccd] = x2
        ccds.psf_my2[iccd] = y2
        ccds.psf_mxy[iccd] = xy
        ccds.psf_a[iccd] = a
        ccds.psf_b[iccd] = b
        ccds.psf_theta[iccd] = theta
        ccds.psf_ell[iccd] = ell

        # Galaxy norm using Gaussian approximation of PSF.
        realpsf = tim.psf
        tim.psf = im.read_psf_model(0,
                                    0,
                                    gaussPsf=True,
                                    psf_sigma=tim.psf_sigma)
        gaussgalnorm[iccd] = im.galaxy_norm(tim, x=cx, y=cy)
        tim.psf = realpsf

        # Sky
        mod = np.zeros((ccd.height, ccd.width), np.float32)
        sky.addTo(mod)
        ccds.meansky[iccd] = np.mean(mod)
        ccds.stdsky[iccd] = np.std(mod)
        ccds.maxsky[iccd] = mod.max()
        ccds.minsky[iccd] = mod.min()

        # WCS
        ccds.ra0[iccd], ccds.dec0[iccd] = wcs.pixelxy2radec(1, 1)
        ccds.ra1[iccd], ccds.dec1[iccd] = wcs.pixelxy2radec(1, H)
        ccds.ra2[iccd], ccds.dec2[iccd] = wcs.pixelxy2radec(W, H)
        ccds.ra3[iccd], ccds.dec3[iccd] = wcs.pixelxy2radec(W, 1)

        midx, midy = (W + 1) / 2., (H + 1) / 2.
        rc, dc = wcs.pixelxy2radec(midx, midy)
        ra, dec = wcs.pixelxy2radec([1, W, midx, midx], [midy, midy, 1, H])
        ccds.dra[iccd] = max(
            degrees_between(ra, dc + np.zeros_like(ra), rc, dc))
        ccds.ddec[iccd] = max(
            degrees_between(rc + np.zeros_like(dec), dec, rc, dc))
        ccds.ra_center[iccd] = rc
        ccds.dec_center[iccd] = dc

        # Compute scale change across the chip
        # how many pixels to step
        step = 10
        xx = np.linspace(1 + step, W - step, 5)
        yy = np.linspace(1 + step, H - step, 5)
        xx, yy = np.meshgrid(xx, yy)
        pixscale = []
        for x, y in zip(xx.ravel(), yy.ravel()):
            sx = [x - step, x - step, x + step, x + step, x - step]
            sy = [y - step, y + step, y + step, y - step, y - step]
            sr, sd = wcs.pixelxy2radec(sx, sy)
            rc, dc = wcs.pixelxy2radec(x, y)
            # project around a tiny little TAN WCS at (x,y), with 1" pixels
            locwcs = Tan(rc, dc, 0., 0., 1. / 3600, 0., 0., 1. / 3600, 1., 1.)
            ok, lx, ly = locwcs.radec2pixelxy(sr, sd)
            #print('local x,y:', lx, ly)
            A = polygon_area((lx, ly))
            pixscale.append(np.sqrt(A / (2 * step)**2))
        # print('Pixel scales:', pixscale)
        ccds.pixscale_mean[iccd] = np.mean(pixscale)
        ccds.pixscale_min[iccd] = min(pixscale)
        ccds.pixscale_max[iccd] = max(pixscale)
        ccds.pixscale_std[iccd] = np.std(pixscale)

    ccds.plver = np.array(plvers)

    sfd = tractor.sfd.SFDMap()
    allbands = 'ugrizY'
    filts = ['%s %s' % ('DES', f) for f in allbands]
    wisebands = ['WISE W1', 'WISE W2', 'WISE W3', 'WISE W4']
    ebv, ext = sfd.extinction(filts + wisebands,
                              ccds.ra_center,
                              ccds.dec_center,
                              get_ebv=True)
    ext = ext.astype(np.float32)
    ccds.ebv = ebv.astype(np.float32)
    ccds.decam_extinction = ext[:, :len(allbands)]
    ccds.wise_extinction = ext[:, len(allbands):]

    # Depth
    detsig1 = ccds.sig1 / ccds.psfnorm_mean
    depth = 5. * detsig1
    # that's flux in nanomaggies -- convert to mag
    ccds.psfdepth = -2.5 * (np.log10(depth) - 9)

    detsig1 = ccds.sig1 / ccds.galnorm_mean
    depth = 5. * detsig1
    # that's flux in nanomaggies -- convert to mag
    ccds.galdepth = -2.5 * (np.log10(depth) - 9)

    # Depth using Gaussian FWHM.
    psf_sigma = ccds.fwhm / 2.35
    gnorm = 1. / (2. * np.sqrt(np.pi) * psf_sigma)
    detsig1 = ccds.sig1 / gnorm
    depth = 5. * detsig1
    # that's flux in nanomaggies -- convert to mag
    ccds.gausspsfdepth = -2.5 * (np.log10(depth) - 9)

    # Gaussian galaxy depth
    detsig1 = ccds.sig1 / gaussgalnorm
    depth = 5. * detsig1
    # that's flux in nanomaggies -- convert to mag
    ccds.gaussgaldepth = -2.5 * (np.log10(depth) - 9)

    ccds.writeto(outfn)
Ejemplo n.º 32
0
 def distanceFrom(self, pos):
     from astrometry.util.starutil_numpy import degrees_between
     return degrees_between(self.ra, self.dec, pos.ra, pos.dec)
Ejemplo n.º 33
0
def annotate(ccds, survey, mzls=False, normalizePsf=False):
    # File from the "observing" svn repo:
    if mzls:
        # https://desi.lbl.gov/svn/decam/code/mosaic3/trunk
        tiles = fits_table('mosaic-tiles_obstatus.fits')
    else:
        # https://desi.lbl.gov/svn/decam/code/observing/trunk
        tiles = fits_table('decam-tiles_obstatus.fits')

    # Map tile IDs back to index in the obstatus file.
    tileid_to_index = np.empty(max(tiles.tileid)+1, int)
    tileid_to_index[:] = -1
    tileid_to_index[tiles.tileid] = np.arange(len(tiles))

    #assert('ccd_cuts' in ccds.get_columns())

    gaussgalnorm = np.zeros(len(ccds), np.float32)

    for iccd,ccd in enumerate(ccds):
        print('Reading CCD %i of %i:' % (iccd+1, len(ccds)), 'file', ccd.image_filename, 'CCD', ccd.expnum, ccd.ccdname)
        try:
            im = survey.get_image_object(ccd)
        except:
            print('Failed to get_image_object()')
            import traceback
            traceback.print_exc()
            continue
        print('Reading CCD %i of %i:' % (iccd+1, len(ccds)), im, 'file', ccd.image_filename, 'CCD', ccd.ccdname)

        X = im.get_good_image_subregion()
        for i,x in enumerate(X):
            if x is not None:
                ccds.good_region[iccd,i] = x

        W,H = ccd.width, ccd.height

        kwargs = dict(pixPsf=True, splinesky=True, subsky=False,
                      pixels=False, dq=False, invvar=False,
                      normalizePsf=normalizePsf)

        psf = None
        wcs = None
        sky = None
        try:
            tim = im.get_tractor_image(**kwargs)

        except:
            print('Failed to get_tractor_image')
            import traceback
            traceback.print_exc()
            continue

        if tim is None:
            continue

        psf = tim.psf
        wcs = tim.wcs.wcs
        sky = tim.sky
        hdr = tim.primhdr

        # print('CCD fwhm:', ccd.fwhm)
        # print('im fwhm:', im.fwhm)
        # print('tim psf_fwhm', tim.psf_fwhm)
        # print('tim psf_sigma:', tim.psf_sigma)
        # print('Got PSF', psf)
        # print('Got sky', type(sky))
        # print('Got WCS', wcs)
        # print('sig1', tim.sig1)

        ccds.humidity[iccd] = hdr.get('HUMIDITY')
        ccds.outtemp[iccd]  = hdr.get('OUTTEMP')

        ccds.sig1[iccd] = tim.sig1
        ccds.plver[iccd] = tim.plver

        # parse 'DECaLS_15150_r' to get tile number
        obj = ccd.object.strip()
        words = obj.split('_')
        tile = None
        if len(words) == 3 and (
            ((not mzls) and (words[0] == 'DECaLS')) or
            (     mzls  and (words[0] in ['MzLS','MOSAIC']))):
            try:
                tileid = int(words[1])
                tile = tiles[tileid_to_index[tileid]]
                assert(tile.tileid == tileid)
            except:
                import traceback
                traceback.print_exc()
                pass

        if tile is not None:
            ccds.tileid  [iccd] = tile.tileid
            ccds.tilepass[iccd] = tile.get('pass')
            ccds.tileebv [iccd] = tile.ebv_med

        # Instantiate PSF on a grid
        S = 32
        xx = np.linspace(1+S, W-S, 5)
        yy = np.linspace(1+S, H-S, 5)
        xx,yy = np.meshgrid(xx, yy)
        psfnorms = []
        galnorms = []
        for x,y in zip(xx.ravel(), yy.ravel()):

            # HACK -- DR4 PSF sampling issue
            tim.psf = psf.constantPsfAt(x, y)

            p = im.psf_norm(tim, x=x, y=y)
            g = im.galaxy_norm(tim, x=x, y=y)
            psfnorms.append(p)
            galnorms.append(g)

        tim.psf = psf

        ccds.psfnorm_mean[iccd] = np.mean(psfnorms)
        ccds.psfnorm_std [iccd] = np.std (psfnorms)
        ccds.galnorm_mean[iccd] = np.mean(galnorms)
        ccds.galnorm_std [iccd] = np.std (galnorms)

        #print('psf norm', ccds.psfnorm_mean[iccd])
        #print('gal norm', ccds.galnorm_mean[iccd])

        # PSF in center of field
        cx,cy = (W+1)/2., (H+1)/2.
        p = psf.getPointSourcePatch(cx, cy).patch
        ph,pw = p.shape
        px,py = np.meshgrid(np.arange(pw), np.arange(ph))
        psum = np.sum(p)
        # print('psum', psum)
        p /= psum
        # centroids
        cenx = np.sum(p * px)
        ceny = np.sum(p * py)
        # print('cenx,ceny', cenx,ceny)
        # second moments
        x2 = np.sum(p * (px - cenx)**2)
        y2 = np.sum(p * (py - ceny)**2)
        xy = np.sum(p * (px - cenx)*(py - ceny))
        # semi-major/minor axes and position angle
        theta = np.rad2deg(np.arctan2(2 * xy, x2 - y2) / 2.)
        theta = np.abs(theta) * np.sign(xy)
        s = np.sqrt(((x2 - y2)/2.)**2 + xy**2)
        a = np.sqrt((x2 + y2) / 2. + s)
        b = np.sqrt((x2 + y2) / 2. - s)
        ell = 1. - b/a

        # print('PSF second moments', x2, y2, xy)
        # print('PSF position angle', theta)
        # print('PSF semi-axes', a, b)
        # print('PSF ellipticity', ell)

        ccds.psf_mx2[iccd] = x2
        ccds.psf_my2[iccd] = y2
        ccds.psf_mxy[iccd] = xy
        ccds.psf_a[iccd] = a
        ccds.psf_b[iccd] = b
        ccds.psf_theta[iccd] = theta
        ccds.psf_ell  [iccd] = ell

        #print('Computing Gaussian approximate PSF quantities...')
        # Galaxy norm using Gaussian approximation of PSF.
        realpsf = tim.psf

        #print('FWHM', ccds.fwhm[i])
        #print('-> sigma', ccds.fwhm[i] / 2.35)
        #print('tim.PSF sigma', tim.psf_sigma)

        tim.psf = im.read_psf_model(0, 0, gaussPsf=True,
                                    psf_sigma=tim.psf_sigma)
        gaussgalnorm[iccd] = im.galaxy_norm(tim, x=cx, y=cy)

        psfnorm = im.psf_norm(tim)
        pnorm = 1./(2. * np.sqrt(np.pi) * tim.psf_sigma)
        #print('Gaussian PSF norm:', psfnorm, 'vs analytic', pnorm)
        #print('Gaussian gal norm:', gaussgalnorm[iccd])

        tim.psf = realpsf
        
        has_skygrid = hasattr(sky, 'evaluateGrid')

        # Sky -- evaluate on a grid (every ~10th pixel)
        if has_skygrid:
            skygrid = sky.evaluateGrid(np.linspace(0, ccd.width-1,  int(1+ccd.width/10)),
                                       np.linspace(0, ccd.height-1, int(1+ccd.height/10)))
            ccds.meansky[iccd] = np.mean(skygrid)
            ccds.stdsky[iccd]  = np.std(skygrid)
            ccds.maxsky[iccd]  = skygrid.max()
            ccds.minsky[iccd]  = skygrid.min()
        else:
            skyval = sky.getConstant()
            ccds.meansky[iccd] = skyval
            ccds.stdsky[iccd]  = 0.
            ccds.maxsky[iccd]  = skyval
            ccds.minsky[iccd]  = skyval

        # WCS
        ccds.ra0[iccd],ccds.dec0[iccd] = wcs.pixelxy2radec(1, 1)
        ccds.ra1[iccd],ccds.dec1[iccd] = wcs.pixelxy2radec(1, H)
        ccds.ra2[iccd],ccds.dec2[iccd] = wcs.pixelxy2radec(W, H)
        ccds.ra3[iccd],ccds.dec3[iccd] = wcs.pixelxy2radec(W, 1)

        midx, midy = (W+1)/2., (H+1)/2.
        rc,dc  = wcs.pixelxy2radec(midx, midy)
        ra,dec = wcs.pixelxy2radec([1,W,midx,midx], [midy,midy,1,H])
        ccds.dra [iccd] = max(degrees_between(ra, dc+np.zeros_like(ra),
                                              rc, dc))
        ccds.ddec[iccd] = max(degrees_between(rc+np.zeros_like(dec), dec,
                                              rc, dc))
        ccds.ra_center [iccd] = rc
        ccds.dec_center[iccd] = dc

        # Compute scale change across the chip
        # how many pixels to step
        step = 10
        xx = np.linspace(1+step, W-step, 5)
        yy = np.linspace(1+step, H-step, 5)
        xx,yy = np.meshgrid(xx, yy)
        pixscale = []
        for x,y in zip(xx.ravel(), yy.ravel()):
            sx = [x-step, x-step, x+step, x+step, x-step]
            sy = [y-step, y+step, y+step, y-step, y-step]
            sr,sd = wcs.pixelxy2radec(sx, sy)
            rc,dc = wcs.pixelxy2radec(x, y)
            # project around a tiny little TAN WCS at (x,y), with 1" pixels
            locwcs = Tan(rc, dc, 0., 0., 1./3600, 0., 0., 1./3600, 1., 1.)
            ok,lx,ly = locwcs.radec2pixelxy(sr, sd)
            #print('local x,y:', lx, ly)
            A = polygon_area((lx, ly))
            pixscale.append(np.sqrt(A / (2*step)**2))
        # print('Pixel scales:', pixscale)
        ccds.pixscale_mean[iccd] = np.mean(pixscale)
        ccds.pixscale_min[iccd] = min(pixscale)
        ccds.pixscale_max[iccd] = max(pixscale)
        ccds.pixscale_std[iccd] = np.std(pixscale)

        ccds.annotated[iccd] = True

    sfd = tractor.sfd.SFDMap()
    allbands = 'ugrizY'
    filts = ['%s %s' % ('DES', f) for f in allbands]
    wisebands = ['WISE W1', 'WISE W2', 'WISE W3', 'WISE W4']
    ebv,ext = sfd.extinction(filts + wisebands, ccds.ra_center,
                             ccds.dec_center, get_ebv=True)

    ext[np.logical_not(ccds.annotated),:] = 0.
    ebv[np.logical_not(ccds.annotated)] = 0.

    ext = ext.astype(np.float32)
    ccds.ebv = ebv.astype(np.float32)
    ccds.decam_extinction = ext[:,:len(allbands)]
    ccds.wise_extinction = ext[:,len(allbands):]

    # Depth
    detsig1 = ccds.sig1 / ccds.psfnorm_mean
    depth = 5. * detsig1
    # that's flux in nanomaggies -- convert to mag
    ccds.psfdepth = -2.5 * (np.log10(depth) - 9)

    detsig1 = ccds.sig1 / ccds.galnorm_mean
    depth = 5. * detsig1
    # that's flux in nanomaggies -- convert to mag
    ccds.galdepth = -2.5 * (np.log10(depth) - 9)
    
    # Depth using Gaussian FWHM.
    psf_sigma = ccds.fwhm / 2.35
    gnorm = 1./(2. * np.sqrt(np.pi) * psf_sigma)
    detsig1 = ccds.sig1 / gnorm
    depth = 5. * detsig1
    # that's flux in nanomaggies -- convert to mag
    ccds.gausspsfdepth = -2.5 * (np.log10(depth) - 9)

    # Gaussian galaxy depth
    detsig1 = ccds.sig1 / gaussgalnorm
    depth = 5. * detsig1
    # that's flux in nanomaggies -- convert to mag
    ccds.gaussgaldepth = -2.5 * (np.log10(depth) - 9)

    # NaN depths -> 0
    for X in [ccds.psfdepth, ccds.galdepth, ccds.gausspsfdepth, ccds.gaussgaldepth]:
        X[np.logical_not(np.isfinite(X))] = 0.
Ejemplo n.º 34
0
def read_star_clusters(targetwcs):
    """
    Code to regenerate the NGC-star-clusters-fits catalog:

    wget https://raw.githubusercontent.com/mattiaverga/OpenNGC/master/NGC.csv

    import os
    import numpy as np
    import numpy.ma as ma
    from astropy.io import ascii
    from astrometry.util.starutil_numpy import hmsstring2ra, dmsstring2dec
    import desimodel.io
    import desimodel.footprint
        
    tiles = desimodel.io.load_tiles(onlydesi=True)
    
    names = ('name', 'type', 'ra_hms', 'dec_dms', 'const', 'majax', 'minax',
             'pa', 'bmag', 'vmag', 'jmag', 'hmag', 'kmag', 'sbrightn', 'hubble',
             'cstarumag', 'cstarbmag', 'cstarvmag', 'messier', 'ngc', 'ic',
             'cstarnames', 'identifiers', 'commonnames', 'nednotes', 'ongcnotes')
    NGC = ascii.read('NGC.csv', delimiter=';', names=names)
    NGC = NGC[(NGC['ra_hms'] != 'N/A')]
  
    ra, dec = [], []
    for _ra, _dec in zip(ma.getdata(NGC['ra_hms']), ma.getdata(NGC['dec_dms'])):
        ra.append(hmsstring2ra(_ra.replace('h', ':').replace('m', ':').replace('s','')))
        dec.append(dmsstring2dec(_dec.replace('d', ':').replace('m', ':').replace('s','')))
    NGC['ra'] = ra
    NGC['dec'] = dec
        
    objtype = np.char.strip(ma.getdata(NGC['type']))

    # Keep all globular clusters and planetary nebulae
    keeptype = ('PN', 'GCl')
    keep = np.zeros(len(NGC), dtype=bool)
    for otype in keeptype:
        ww = [otype == tt for tt in objtype]
        keep = np.logical_or(keep, ww)
    print(np.sum(keep))

    clusters = NGC[keep]

    # Fill missing major axes with a nominal 0.4 arcmin (roughly works
    # for NGC7009, which is the only missing PN in the footprint).
    ma.set_fill_value(clusters['majax'], 0.4)
    clusters['majax'] = ma.filled(clusters['majax'].data)
    
    indesi = desimodel.footprint.is_point_in_desi(tiles, ma.getdata(clusters['ra']),
                                                  ma.getdata(clusters['dec']))
    print(np.sum(indesi))
    bb = clusters[indesi]
    bb[np.argsort(bb['majax'])[::-1]]['name', 'ra', 'dec', 'majax', 'type']
    
    clusters.write('NGC-star-clusters.fits', overwrite=True)


    # Code to help visually check all open clusters that are in the DESI footprint.
    checktype = ('OCl', 'Cl+N')
    check = np.zeros(len(NGC), dtype=bool)
    for otype in checktype:
        ww = [otype == tt for tt in objtype]
        check = np.logical_or(check, ww)
    check_clusters = NGC[check] # 845 of them
    
    # Write out a catalog, load it into the viewer and look at each of them.
    check_clusters[['ra', 'dec', 'name']][indesi].write('check.fits', overwrite=True) # 25 of them
    
    """
    from pkg_resources import resource_filename
    from astrometry.util.starutil_numpy import degrees_between

    clusterfile = resource_filename('legacypipe',
                                    'data/NGC-star-clusters.fits')
    debug('Reading {}'.format(clusterfile))
    clusters = fits_table(clusterfile, columns=['ra', 'dec', 'majax', 'type'])
    clusters.ref_id = np.arange(len(clusters))

    radius = 1.
    rc, dc = targetwcs.radec_center()
    d = degrees_between(rc, dc, clusters.ra, clusters.dec)
    clusters.cut(d < radius)
    if len(clusters) == 0:
        return None

    debug('Cut to {} star cluster(s) within the brick'.format(len(clusters)))

    # For each cluster, add a single faint star at the same coordinates, but
    # set the isbright bit so we get all the brightstarinblob logic.
    #clusters.ref_cat = clusters.name
    clusters.ref_cat = np.array(['CL'] * len(clusters))
    clusters.mag = np.array([35] * len(clusters))

    # Radius in degrees (from "majax" in arcmin)
    clusters.radius = clusters.majax / 60.
    clusters.radius[np.logical_not(np.isfinite(clusters.radius))] = 1. / 60.

    # Set isbright=True
    clusters.isbright = np.zeros(len(clusters), bool)
    clusters.iscluster = np.ones(len(clusters), bool)

    return clusters
Ejemplo n.º 35
0
def map_decam_depth(req,
                    ver,
                    zoom,
                    x,
                    y,
                    savecache=False,
                    band=None,
                    ignoreCached=False):
    global Tdepth
    global Tdepthkd

    if band is None:
        band = req.GET.get('band')
    if not band in ['g', 'r', 'z']:
        raise RuntimeError('Invalid band')
    tag = 'decam-depth-%s' % band
    zoom = int(zoom)
    zoomscale = 2.**zoom
    x = int(x)
    y = int(y)
    if zoom < 0 or x < 0 or y < 0 or x >= zoomscale or y >= zoomscale:
        raise RuntimeError('Invalid zoom,x,y %i,%i,%i' % (zoom, x, y))
    ver = int(ver)
    if not ver in tileversions[tag]:
        raise RuntimeError('Invalid version %i for tag %s' % (ver, tag))

    basedir = settings.DATA_DIR
    tilefn = os.path.join(basedir, 'tiles', tag,
                          '%i/%i/%i/%i.jpg' % (ver, zoom, x, y))
    if os.path.exists(tilefn) and not ignoreCached:
        print('Cached:', tilefn)
        return send_file(tilefn,
                         'image/jpeg',
                         expires=oneyear,
                         modsince=req.META.get('HTTP_IF_MODIFIED_SINCE'))
    from astrometry.util.util import Tan
    from astrometry.libkd.spherematch import match_radec
    from astrometry.libkd.spherematch import tree_build_radec, tree_search_radec
    from astrometry.util.fits import fits_table
    from astrometry.util.starutil_numpy import degrees_between
    import numpy as np
    import fitsio
    try:
        wcs, W, H, zoomscale, zoom, x, y = get_tile_wcs(zoom, x, y)
    except RuntimeError as e:
        return HttpResponse(e.strerror)
    rlo, d = wcs.pixelxy2radec(W, H / 2)[-2:]
    rhi, d = wcs.pixelxy2radec(1, H / 2)[-2:]
    r, d1 = wcs.pixelxy2radec(W / 2, 1)[-2:]
    r, d2 = wcs.pixelxy2radec(W / 2, H)[-2:]

    r, d = wcs.pixelxy2radec(W / 2, H / 2)[-2:]
    rad = max(degrees_between(r, d, rlo, d1), degrees_between(r, d, rhi, d2))

    if Tdepth is None:
        T = fits_table(os.path.join(basedir, 'decals-zpt-nondecals.fits'),
                       columns=[
                           'ccdra', 'ccddec', 'arawgain', 'avsky', 'ccdzpt',
                           'filter', 'crpix1', 'crpix2', 'crval1', 'crval2',
                           'cd1_1', 'cd1_2', 'cd2_1', 'cd2_2', 'naxis1',
                           'naxis2', 'exptime', 'fwhm'
                       ])
        T.rename('ccdra', 'ra')
        T.rename('ccddec', 'dec')

        Tdepth = {}
        Tdepthkd = {}
        for b in ['g', 'r', 'z']:
            Tdepth[b] = T[T.filter == b]
            Tdepthkd[b] = tree_build_radec(Tdepth[b].ra, Tdepth[b].dec)

    T = Tdepth[band]
    Tkd = Tdepthkd[band]

    #I,J,d = match_radec(T.ra, T.dec, r, d, rad + 0.2)
    I = tree_search_radec(Tkd, r, d, rad + 0.2)
    print(len(I), 'CCDs in range')
    if len(I) == 0:
        from django.http import HttpResponseRedirect
        return HttpResponseRedirect(settings.STATIC_URL + 'blank.jpg')

    depthiv = np.zeros((H, W), np.float32)
    for t in T[I]:
        twcs = Tan(*[
            float(x) for x in [
                t.crval1, t.crval2, t.crpix1, t.crpix2, t.cd1_1, t.cd1_2,
                t.cd2_1, t.cd2_2, t.naxis1, t.naxis2
            ]
        ])
        w, h = t.naxis1, t.naxis2
        r, d = twcs.pixelxy2radec([1, 1, w, w], [1, h, h, 1])
        ok, x, y = wcs.radec2pixelxy(r, d)
        #print 'x,y coords of CCD:', x, y
        x0 = int(x.min())
        x1 = int(x.max())
        y0 = int(y.min())
        y1 = int(y.max())
        if y1 < 0 or x1 < 0 or x0 >= W or y0 >= H:
            continue

        readnoise = 10.  # e-; 7.0 to 15.0 according to DECam Data Handbook
        skysig = np.sqrt(t.avsky * t.arawgain + readnoise**2) / t.arawgain
        zpscale = 10.**((t.ccdzpt - 22.5) / 2.5) * t.exptime
        sig1 = skysig / zpscale
        psf_sigma = t.fwhm / 2.35
        # point-source depth
        psfnorm = 1. / (2. * np.sqrt(np.pi) * psf_sigma)
        detsig1 = sig1 / psfnorm

        #print '5-sigma point-source depth:', NanoMaggies.nanomaggiesToMag(detsig1 * 5.)

        div = 1 / detsig1**2
        depthiv[max(y0, 0):min(y1, H), max(x0, 0):min(x1, W)] += div

    ptsrc = -2.5 * (np.log10(np.sqrt(1. / depthiv) * 5) - 9)
    ptsrc[depthiv == 0] = 0.

    if savecache:
        trymakedirs(tilefn)
    else:
        import tempfile
        f, tilefn = tempfile.mkstemp(suffix='.jpg')
        os.close(f)

    import pylab as plt
    plt.imsave(tilefn, ptsrc, vmin=22., vmax=25., cmap='hot')  #nipy_spectral')

    return send_file(tilefn, 'image/jpeg', unlink=(not savecache))
Ejemplo n.º 36
0
def map_sdss(req, ver, zoom, x, y, savecache=None, tag='sdss',
             get_images=False,
             ignoreCached=False,
             wcs=None,
             forcecache=False,
             forcescale=None,
             **kwargs):
    from decals import settings

    if savecache is None:
        savecache = settings.SAVE_CACHE
    zoom = int(zoom)
    zoomscale = 2.**zoom
    x = int(x)
    y = int(y)
    if zoom < 0 or x < 0 or y < 0 or x >= zoomscale or y >= zoomscale:
        raise RuntimeError('Invalid zoom,x,y %i,%i,%i' % (zoom,x,y))
    ver = int(ver)

    if not ver in tileversions[tag]:
        raise RuntimeError('Invalid version %i for tag %s' % (ver, tag))

    basedir = settings.DATA_DIR
    tilefn = os.path.join(basedir, 'tiles', tag,
                          '%i/%i/%i/%i.jpg' % (ver, zoom, x, y))
    if os.path.exists(tilefn) and not ignoreCached:
        if get_images:
            return None
        return send_file(tilefn, 'image/jpeg', expires=oneyear,
                         modsince=req.META.get('HTTP_IF_MODIFIED_SINCE'))

    if not savecache:
        import tempfile
        f,tilefn = tempfile.mkstemp(suffix='.jpg')
        os.close(f)

    if wcs is None:
        try:
            wcs, W, H, zoomscale, zoom,x,y = get_tile_wcs(zoom, x, y)
        except RuntimeError as e:
            if get_images:
                return None
            return HttpResponse(e.strerror)
    else:
        W = wcs.get_width()
        H = wcs.get_height()

    from astrometry.util.fits import fits_table
    import numpy as np
    from astrometry.libkd.spherematch import tree_build_radec, tree_search_radec
    from astrometry.util.starutil_numpy import degrees_between, arcsec_between
    from astrometry.util.resample import resample_with_wcs, OverlapError
    from astrometry.util.util import Tan, Sip
    import fitsio

    print 'Tile wcs: center', wcs.radec_center(), 'pixel scale', wcs.pixel_scale()

    global w_flist
    global w_flist_tree
    if w_flist is None:
        w_flist = fits_table(os.path.join(settings.DATA_DIR, 'sdss',
                                          'window_flist.fits'),
                             columns=['run','rerun','camcol','field','ra','dec','score'])
        print 'Read', len(w_flist), 'window_flist entries'
        w_flist.cut(w_flist.rerun == '301')
        print 'Cut to', len(w_flist), 'in rerun 301'
        w_flist_tree = tree_build_radec(w_flist.ra, w_flist.dec)

    # SDSS field size
    radius = 1.01 * np.hypot(10., 14.)/2. / 60.

    # leaflet tile size
    ra,dec = wcs.pixelxy2radec(W/2., H/2.)[-2:]
    r0,d0 = wcs.pixelxy2radec(1, 1)[-2:]
    r1,d1 = wcs.pixelxy2radec(W, H)[-2:]
    radius = radius + max(degrees_between(ra,dec, r0,d0), degrees_between(ra,dec, r1,d1))

    J = tree_search_radec(w_flist_tree, ra, dec, radius)

    print len(J), 'overlapping SDSS fields found'
    if len(J) == 0:
        if get_images:
            return None
        if forcecache:
            # create symlink to blank.jpg!
            trymakedirs(tilefn)
            src = os.path.join(settings.STATIC_ROOT, 'blank.jpg')
            if os.path.exists(tilefn):
                os.unlink(tilefn)
            os.symlink(src, tilefn)
            print 'Symlinked', tilefn, '->', src
        from django.http import HttpResponseRedirect
        return HttpResponseRedirect(settings.STATIC_URL + 'blank.jpg')
    
    ww = [1, W*0.25, W*0.5, W*0.75, W]
    hh = [1, H*0.25, H*0.5, H*0.75, H]

    r,d = wcs.pixelxy2radec(
        [1]*len(hh) + ww          + [W]*len(hh) +        list(reversed(ww)),
        hh          + [1]*len(ww) + list(reversed(hh)) + [H]*len(ww))[-2:]

    scaled = 0
    scalepat = None
    scaledir = 'sdss'
    
    if zoom <= 13 and forcescale is None:
        # Get *actual* pixel scales at the top & bottom
        r1,d1 = wcs.pixelxy2radec(W/2., H)[-2:]
        r2,d2 = wcs.pixelxy2radec(W/2., H-1.)[-2:]
        r3,d3 = wcs.pixelxy2radec(W/2., 1.)[-2:]
        r4,d4 = wcs.pixelxy2radec(W/2., 2.)[-2:]
        # Take the min = most zoomed-in
        scale = min(arcsec_between(r1,d1, r2,d2), arcsec_between(r3,d3, r4,d4))
        
        native_scale = 0.396
        scaled = int(np.floor(np.log2(scale / native_scale)))
        print 'Zoom:', zoom, 'x,y', x,y, 'Tile pixel scale:', scale, 'Scale step:', scaled
        scaled = np.clip(scaled, 1, 7)
        dirnm = os.path.join(basedir, 'scaled', scaledir)
        scalepat = os.path.join(dirnm, '%(scale)i%(band)s', '%(rerun)s', '%(run)i', '%(camcol)i', 'sdss-%(run)i-%(camcol)i-%(field)i-%(band)s.fits')

    if forcescale is not None:
        scaled = forcescale

    bands = 'gri'
    rimgs = [np.zeros((H,W), np.float32) for band in bands]
    rns   = [np.zeros((H,W), np.float32)   for band in bands]

    from astrometry.sdss import AsTransWrapper, DR9
    sdss = DR9(basedir=settings.SDSS_DIR)
    sdss.saveUnzippedFiles(settings.SDSS_DIR)
    #sdss.setFitsioReadBZ2()
    if settings.SDSS_PHOTOOBJS:
        sdss.useLocalTree(photoObjs=settings.SDSS_PHOTOOBJS,
                          resolve=settings.SDSS_RESOLVE)

    for jnum,j in enumerate(J):
        print 'SDSS field', jnum, 'of', len(J), 'for zoom', zoom, 'x', x, 'y', y
        im = w_flist[j]

        if im.score >= 0.5:
            weight = 1.
        else:
            weight = 0.001


        for band,rimg,rn in zip(bands, rimgs, rns):
            if im.rerun != '301':
                continue
            tmpsuff = '.tmp%08i' % np.random.randint(100000000)
            basefn = sdss.retrieve('frame', im.run, im.camcol, field=im.field,
                                   band=band, rerun=im.rerun, tempsuffix=tmpsuff)
            if scaled > 0:
                fnargs = dict(band=band, rerun=im.rerun, run=im.run,
                              camcol=im.camcol, field=im.field)
                fn = get_scaled(scalepat, fnargs, scaled, basefn,
                                read_base_wcs=read_astrans, read_wcs=_read_sip_wcs)
                print 'get_scaled:', fn
            else:
                fn = basefn
            frame = None
            if fn == basefn:
                frame = sdss.readFrame(im.run, im.camcol, im.field, band,
                                       filename=fn)
                h,w = frame.getImageShape()
                # Trim off the overlapping top of the image
                # Wimp out and instead of trimming 128 pix, trim 124!
                trim = 124
                subh = h - trim
                astrans = frame.getAsTrans()
                fwcs = AsTransWrapper(astrans, w, subh)
                fullimg = frame.getImage()
                fullimg = fullimg[:-trim,:]
            else:
                fwcs = Sip(fn)
                fitsimg = fitsio.FITS(fn)[0]
                h,w = fitsimg.get_info()['dims']
                fullimg = fitsimg.read()

            try:
                #Yo,Xo,Yi,Xi,nil = resample_with_wcs(wcs, fwcs, [], 3)
                Yo,Xo,Yi,Xi,[resamp] = resample_with_wcs(wcs, fwcs, [fullimg], 2)
            except OverlapError:
                continue
            if len(Xi) == 0:
                #print 'No overlap'
                continue

            if sdssps is not None:
                x0 = Xi.min()
                x1 = Xi.max()
                y0 = Yi.min()
                y1 = Yi.max()
                slc = (slice(y0,y1+1), slice(x0,x1+1))
                if frame is not None:
                    img = frame.getImageSlice(slc)
                else:
                    img = fitsimg[slc]
            #rimg[Yo,Xo] += img[Yi-y0, Xi-x0]
            rimg[Yo,Xo] += resamp * weight

            rn  [Yo,Xo] += weight

            if sdssps is not None:
                # goodpix = np.ones(img.shape, bool)
                # fpM = sdss.readFpM(im.run, im.camcol, im.field, band)
                # for plane in [ 'INTERP', 'SATUR', 'CR', 'GHOST' ]:
                #     fpM.setMaskedPixels(plane, goodpix, False, roi=[x0,x1,y0,y1])
                plt.clf()
                #ima = dict(vmin=-0.05, vmax=0.5)
                #ima = dict(vmin=-0.5, vmax=2.)
                ima = dict(vmax=np.percentile(img, 99))
                plt.subplot(2,3,1)
                dimshow(img, ticks=False, **ima)
                plt.title('image')
                rthis = np.zeros_like(rimg)
                #rthis[Yo,Xo] += img[Yi-y0, Xi-x0]
                rthis[Yo,Xo] += resamp
                plt.subplot(2,3,2)
                dimshow(rthis, ticks=False, **ima)
                plt.title('resampled')
                # plt.subplot(2,3,3)
                # dimshow(goodpix, ticks=False, vmin=0, vmax=1)
                # plt.title('good pix')
                plt.subplot(2,3,4)
                dimshow(rimg / np.maximum(rn, 1), ticks=False, **ima)
                plt.title('coadd')
                plt.subplot(2,3,5)
                dimshow(rn, vmin=0, ticks=False)
                plt.title('coverage: max %i' % rn.max())
                plt.subplot(2,3,6)
                rgb = sdss_rgb([rimg/np.maximum(rn,1)
                                for rimg,rn in zip(rimgs,rns)], bands)
                dimshow(rgb)
                plt.suptitle('SDSS %s, R/C/F %i/%i/%i' % (band, im.run, im.camcol, im.field))
                sdssps.savefig()
                
    for rimg,rn in zip(rimgs, rns):
        rimg /= np.maximum(rn, 1e-3)
    del rns

    if get_images:
        return rimgs

    rgb = sdss_rgb(rimgs, bands)
    trymakedirs(tilefn)
    save_jpeg(tilefn, rgb)
    print 'Wrote', tilefn

    return send_file(tilefn, 'image/jpeg', unlink=(not savecache))
Ejemplo n.º 37
0
def map_decals_wl(req, ver, zoom, x, y):
    tag = 'decals-wl'
    ignoreCached = False
    filename = None
    forcecache = False

    from decals import settings
    savecache = settings.SAVE_CACHE

    zoom = int(zoom)
    zoomscale = 2.**zoom
    x = int(x)
    y = int(y)
    if zoom < 0 or x < 0 or y < 0 or x >= zoomscale or y >= zoomscale:
        raise RuntimeError('Invalid zoom,x,y %i,%i,%i' % (zoom, x, y))
    ver = int(ver)
    if not ver in tileversions[tag]:
        raise RuntimeError('Invalid version %i for tag %s' % (ver, tag))

    basedir = settings.DATA_DIR
    tilefn = os.path.join(basedir, 'tiles', tag,
                          '%i/%i/%i/%i.jpg' % (ver, zoom, x, y))
    if os.path.exists(tilefn) and not ignoreCached:
        print('Cached:', tilefn)
        return send_file(tilefn,
                         'image/jpeg',
                         expires=oneyear,
                         modsince=req.META.get('HTTP_IF_MODIFIED_SINCE'),
                         filename=filename)
    else:
        print('Tile image does not exist:', tilefn)
    from astrometry.util.resample import resample_with_wcs, OverlapError
    from astrometry.util.util import Tan
    from astrometry.libkd.spherematch import match_radec
    from astrometry.util.fits import fits_table
    from astrometry.util.starutil_numpy import degrees_between
    import numpy as np
    import fitsio

    try:
        wcs, W, H, zoomscale, zoom, x, y = get_tile_wcs(zoom, x, y)
    except RuntimeError as e:
        return HttpResponse(e.strerror)

    mydir = os.path.join(basedir, 'coadd', 'weak-lensing')

    rlo, d = wcs.pixelxy2radec(W, H / 2)[-2:]
    rhi, d = wcs.pixelxy2radec(1, H / 2)[-2:]
    r, d1 = wcs.pixelxy2radec(W / 2, 1)[-2:]
    r, d2 = wcs.pixelxy2radec(W / 2, H)[-2:]
    #dlo = min(d1, d2)
    #dhi = max(d1, d2)

    r, d = wcs.pixelxy2radec(W / 2, H / 2)[-2:]
    rad = degrees_between(r, d, rlo, d1)

    fn = os.path.join(mydir, 'index.fits')
    if not os.path.exists(fn):
        #
        ii, rr, dd = [], [], []
        for i in range(1, 52852 + 1):
            imgfn = os.path.join(mydir, 'map%i.fits' % i)
            hdr = fitsio.read_header(imgfn)
            r = hdr['CRVAL1']
            d = hdr['CRVAL2']
            ii.append(i)
            rr.append(r)
            dd.append(d)
        T = fits_table()
        T.ra = np.array(rr)
        T.dec = np.array(dd)
        T.i = np.array(ii)
        T.writeto(fn)

    T = fits_table(fn)
    I, J, d = match_radec(T.ra, T.dec, r, d, rad + 0.2)
    T.cut(I)
    print(len(T), 'weak-lensing maps in range')

    if len(I) == 0:
        from django.http import HttpResponseRedirect
        if forcecache:
            # create symlink to blank.jpg!
            trymakedirs(tilefn)
            src = os.path.join(settings.STATIC_ROOT, 'blank.jpg')
            if os.path.exists(tilefn):
                os.unlink(tilefn)
            os.symlink(src, tilefn)
            print('Symlinked', tilefn, '->', src)
        return HttpResponseRedirect(settings.STATIC_URL + 'blank.jpg')

    r, d = wcs.pixelxy2radec([1, 1, 1, W / 2, W, W, W, W / 2],
                             [1, H / 2, H, H, H, H / 2, 1, 1])[-2:]

    foundany = False
    rimg = np.zeros((H, W), np.float32)
    rn = np.zeros((H, W), np.uint8)
    for tilei in T.i:
        fn = os.path.join(mydir, 'map%i.fits' % tilei)
        try:
            bwcs = read_tan_wcs(fn, 0)
        except:
            print('Failed to read WCS:', fn)
            savecache = False
            import traceback
            import sys
            traceback.print_exc(None, sys.stdout)
            continue

        foundany = True
        print('Reading', fn)
        ok, xx, yy = bwcs.radec2pixelxy(r, d)
        xx = xx.astype(np.int)
        yy = yy.astype(np.int)
        imW, imH = int(bwcs.get_width()), int(bwcs.get_height())
        M = 10
        xlo = np.clip(xx.min() - M, 0, imW)
        xhi = np.clip(xx.max() + M, 0, imW)
        ylo = np.clip(yy.min() - M, 0, imH)
        yhi = np.clip(yy.max() + M, 0, imH)
        if xlo >= xhi or ylo >= yhi:
            continue

        subwcs = bwcs.get_subimage(xlo, ylo, xhi - xlo, yhi - ylo)
        slc = slice(ylo, yhi), slice(xlo, xhi)
        try:
            f = fitsio.FITS(fn)[0]
            img = f[slc]
            del f
        except:
            print('Failed to read image and WCS:', fn)
            savecache = False
            import traceback
            import sys
            traceback.print_exc(None, sys.stdout)
            continue

        try:
            Yo, Xo, Yi, Xi, nil = resample_with_wcs(wcs, subwcs, [], 3)
        except OverlapError:
            print('Resampling exception')
            continue

        rimg[Yo, Xo] += img[Yi, Xi]
        rn[Yo, Xo] += 1
    rimg /= np.maximum(rn, 1)

    if forcecache:
        savecache = True

    if savecache:
        trymakedirs(tilefn)
    else:
        import tempfile
        f, tilefn = tempfile.mkstemp(suffix='.jpg')
        os.close(f)

    import pylab as plt

    # S/N
    #lo,hi = 1.5, 5.0
    lo, hi = 0, 5.0
    rgb = plt.cm.hot((rimg - lo) / (hi - lo))
    plt.imsave(tilefn, rgb)
    print('Wrote', tilefn)

    return send_file(tilefn,
                     'image/jpeg',
                     unlink=(not savecache),
                     filename=filename)
Ejemplo n.º 38
0
def map_decam_depth(req, ver, zoom, x, y, savecache=False, band=None,
                    ignoreCached=False):
    global Tdepth
    global Tdepthkd

    if band is None:
        band = req.GET.get('band')
    if not band in ['g','r','z']:
        raise RuntimeError('Invalid band')
    tag = 'decam-depth-%s' % band
    zoom = int(zoom)
    zoomscale = 2.**zoom
    x = int(x)
    y = int(y)
    if zoom < 0 or x < 0 or y < 0 or x >= zoomscale or y >= zoomscale:
        raise RuntimeError('Invalid zoom,x,y %i,%i,%i' % (zoom,x,y))
    ver = int(ver)
    if not ver in tileversions[tag]:
        raise RuntimeError('Invalid version %i for tag %s' % (ver, tag))

    basedir = settings.DATA_DIR
    tilefn = os.path.join(basedir, 'tiles', tag,
                          '%i/%i/%i/%i.jpg' % (ver, zoom, x, y))
    if os.path.exists(tilefn) and not ignoreCached:
        print 'Cached:', tilefn
        return send_file(tilefn, 'image/jpeg', expires=oneyear,
                         modsince=req.META.get('HTTP_IF_MODIFIED_SINCE'))
    from astrometry.util.util import Tan
    from astrometry.libkd.spherematch import match_radec
    from astrometry.libkd.spherematch import tree_build_radec, tree_search_radec
    from astrometry.util.fits import fits_table
    from astrometry.util.starutil_numpy import degrees_between
    import numpy as np
    import fitsio
    try:
        wcs, W, H, zoomscale, zoom,x,y = get_tile_wcs(zoom, x, y)
    except RuntimeError as e:
        return HttpResponse(e.strerror)
    rlo,d = wcs.pixelxy2radec(W, H/2)[-2:]
    rhi,d = wcs.pixelxy2radec(1, H/2)[-2:]
    r,d1 = wcs.pixelxy2radec(W/2, 1)[-2:]
    r,d2 = wcs.pixelxy2radec(W/2, H)[-2:]

    r,d = wcs.pixelxy2radec(W/2, H/2)[-2:]
    rad = max(degrees_between(r, d, rlo, d1),
              degrees_between(r, d, rhi, d2))

    if Tdepth is None:
        T = fits_table(os.path.join(basedir, 'decals-zpt-nondecals.fits'),
                            columns=['ccdra','ccddec','arawgain', 'avsky',
                                     'ccdzpt', 'filter', 'crpix1','crpix2',
                                     'crval1','crval2','cd1_1','cd1_2',
                                     'cd2_1','cd2_2', 'naxis1', 'naxis2', 'exptime', 'fwhm'])
        T.rename('ccdra',  'ra')
        T.rename('ccddec', 'dec')

        Tdepth = {}
        Tdepthkd = {}
        for b in ['g','r','z']:
            Tdepth[b] = T[T.filter == b]
            Tdepthkd[b] = tree_build_radec(Tdepth[b].ra, Tdepth[b].dec)

    T = Tdepth[band]
    Tkd = Tdepthkd[band]

    #I,J,d = match_radec(T.ra, T.dec, r, d, rad + 0.2)
    I = tree_search_radec(Tkd, r, d, rad + 0.2)
    print len(I), 'CCDs in range'
    if len(I) == 0:
        from django.http import HttpResponseRedirect
        return HttpResponseRedirect(settings.STATIC_URL + 'blank.jpg')

    depthiv = np.zeros((H,W), np.float32)
    for t in T[I]:
        twcs = Tan(*[float(x) for x in [
            t.crval1, t.crval2, t.crpix1, t.crpix2,
            t.cd1_1, t.cd1_2, t.cd2_1, t.cd2_2, t.naxis1, t.naxis2]])
        w,h = t.naxis1, t.naxis2
        r,d = twcs.pixelxy2radec([1,1,w,w], [1,h,h,1])
        ok,x,y = wcs.radec2pixelxy(r, d)
        #print 'x,y coords of CCD:', x, y
        x0 = int(x.min())
        x1 = int(x.max())
        y0 = int(y.min())
        y1 = int(y.max())
        if y1 < 0 or x1 < 0 or x0 >= W or y0 >= H:
            continue

        readnoise = 10. # e-; 7.0 to 15.0 according to DECam Data Handbook
        skysig = np.sqrt(t.avsky * t.arawgain + readnoise**2) / t.arawgain
        zpscale = 10.**((t.ccdzpt - 22.5)/2.5) * t.exptime
        sig1 = skysig / zpscale
        psf_sigma = t.fwhm / 2.35
        # point-source depth
        psfnorm = 1./(2. * np.sqrt(np.pi) * psf_sigma)
        detsig1 = sig1 / psfnorm

        #print '5-sigma point-source depth:', NanoMaggies.nanomaggiesToMag(detsig1 * 5.)

        div = 1 / detsig1**2
        depthiv[max(y0,0):min(y1,H), max(x0,0):min(x1,W)] += div

    ptsrc = -2.5 * (np.log10(np.sqrt(1./depthiv) * 5) - 9)
    ptsrc[depthiv == 0] = 0.

    if savecache:
        trymakedirs(tilefn)
    else:
        import tempfile
        f,tilefn = tempfile.mkstemp(suffix='.jpg')
        os.close(f)

    import pylab as plt
    plt.imsave(tilefn, ptsrc, vmin=22., vmax=25., cmap='hot')#nipy_spectral')

    return send_file(tilefn, 'image/jpeg', unlink=(not savecache))