def mosaicDistortionErrors(rootDir, ep, mosaicRoot, mosaicStarlist,
                           addResid=True, distResid=0.11):
    """
    Read in a maser mosaic and it's associated *.shifts file and
    calculate the distortion error contribution to each pixel in the 
    maser mosaic. This is done by using the NIRC2 single frame distortion
    error maps (X and Y) located here:

    /u/ghezgroup/code/python/gcreduce/nirc2dist_xerr.fits
    /u/ghezgroup/code/python/gcreduce/nirc2dist_yerr.fits

    For each independent dither position (where independent excludes any
    frame within 30 pixels of another frame), the distortion error map
    is shifted to the appropriate location in the final moasic and 
    added in quadrature as sqrt( err1^2 + err2^2 + ... + errN^2 ) / sqrt(N).
    The resulting distortion error maps for the mosaics are saved to FITS
    files with the name:
    
    <mosaicRoot>_xdisterr.fits
    <mosaicRoot>_ydisterr.fits

    Finally, <mosaicStarlist> is the existing positional errors are
    added in quadrature to the distortion error at the nearest pixel for
    each star. The final starlist is saved off to the following file in 
    the same directory as the input list:

    <mosaicStarlist_root>_rms_dist.lis

    Inputs:
    mosaicRoot - The root name of the maser mosaic fits file
                 (e.g. 'mag08maylgs1_msr_kp')

    mosaicStarlist - The full name of a maser starlist with positional 
                     errors (e.g. 'starfinder/mag08maylgs1_msr_kp_0.8_rms.lis')
    addResid - Set to True to add residual distortion error (0.11 pix) in
               quadrature to the centroiding and distortion errors
    distResid - Value of residual distortion in pixels, to be added to centroid
                and distortion errors in quadrature (def=0.11 pix).

    """
    # Read in the shifts file
    shiftsFile = mosaicRoot + '.shifts'
    print(shiftsFile)

    shiftsTable = asciidata.open(shiftsFile)
    singleFiles = shiftsTable[0]._data
    xshifts = shiftsTable[1].tonumpy()
    yshifts = shiftsTable[2].tonumpy()

    # Read in the mosaic fits file to get the size of the mosaic.
    # Then define coordinates for the mosaic.
    fitsFile = mosaicRoot + '.fits'
    fitsImg, fitsHdr = pyfits.getdata(fitsFile, header=True)
    mosaicSize = fitsImg.shape

    # Make the final distortion error map.
    # Also keep the number of frames that contributes to each pixel.
    xdistErrMap = np.zeros((mosaicSize[0], mosaicSize[1]), dtype=float)
    ydistErrMap = np.zeros((mosaicSize[0], mosaicSize[1]), dtype=float)
    distErrCnt = np.zeros((mosaicSize[0], mosaicSize[1]), dtype=int)

    # Read in the distortion errors map
    errorRoot = '/u/ghezgroup/code/python/gcreduce/nirc2dist'
    xerrOrig = pyfits.getdata(errorRoot + '_xerr.fits')
    yerrOrig = pyfits.getdata(errorRoot + '_yerr.fits')

    # Get the half-way points for both the mosaic and the single frame.
    # For zero-shift, the center of the single frame lies at the center of
    # the mosaic.
    mosaicHalfX = mosaicSize[1] / 2.0
    mosaicHalfY = mosaicSize[0] / 2.0
    singleHalfX = xerrOrig.shape[1] / 2.0
    singleHalfY = xerrOrig.shape[0] / 2.0
    print('Mosaic Size: ', mosaicSize)
    print('Mosaic Half: ', mosaicHalfX, mosaicHalfY)
    print('Single Half: ', singleHalfX, singleHalfY)

    # Loop through the individual frames and add them in 
    # quadrature to the final distortion error map. Remember that we
    # can only do this for independent dither positions. We will 
    # consider independent dither positions to be those that are
    # more than 30 pixel distant from any other ones.
    xshiftsUsed = np.array([])
    yshiftsUsed = np.array([])
    allowedSep = 30.0  # pixels

    for ii in range(len(singleFiles)):
        # Check to see if we should count this single file as
        # a new "independent" position by comparing to all 
        # shifts used so far.
        sep = np.hypot(xshifts[ii] - xshiftsUsed, yshifts[ii] - yshiftsUsed)
        idx = np.where(sep < allowedSep)[0]
        
        # If used before, skip
        if (len(idx) > 0):
            continue

        # This is a new independent dither position
        xshiftsUsed = np.append(xshiftsUsed, xshifts[ii])
        yshiftsUsed = np.append(yshiftsUsed, yshifts[ii])
        
        # Calculate the stop and start indices in the maser mosaic
        xlo = round(mosaicHalfX + xshifts[ii] - singleHalfX)
        xhi = round(mosaicHalfX + xshifts[ii] + singleHalfX)
        ylo = round(mosaicHalfY + yshifts[ii] - singleHalfY)
        yhi = round(mosaicHalfY + yshifts[ii] + singleHalfY)

        print(singleFiles[ii], xshifts[ii], yshifts[ii])
        print('  xrange = [%4d:%4d]  yrange = [%4d:%4d]' % (xlo, xhi, ylo, yhi))

        xdistErrMap[ylo:yhi,xlo:xhi] += xerrOrig**2
        ydistErrMap[ylo:yhi,xlo:xhi] += yerrOrig**2
        distErrCnt[ylo:yhi,xlo:xhi] += 1.0

    idx = np.where(distErrCnt != 0)
    xdistErrMap[idx] = np.sqrt(xdistErrMap[idx] / distErrCnt[idx])
    ydistErrMap[idx] = np.sqrt(ydistErrMap[idx] / distErrCnt[idx])

    # Save these to a FITS file
    xfits = pyfits.PrimaryHDU(xdistErrMap)
    gcutil.rmall([mosaicRoot + '_xdisterr.fits', mosaicRoot + '_ydisterr.fits'])
    pyfits.writeto(mosaicRoot + '_xdisterr.fits', xdistErrMap)
    pyfits.writeto(mosaicRoot + '_ydisterr.fits', ydistErrMap)
    

    ##########
    #
    # Read in starlist and apply distortion errors.
    #
    ##########
    starlist = asciidata.open(mosaicStarlist)
    
    # Check that this starlist properly has error columns
    if starlist.nrows < 11:
        print('Starlist does not have error columns: %s' % mosaicStarlist)

    # Now for each star, add the distortion errors in quadrature
    for rr in range(starlist.nrows):
        xpix = round(starlist[3][rr])
        ypix = round(starlist[4][rr])

        if addResid:
            xerr = math.sqrt(starlist[5][rr]**2 + xdistErrMap[ypix,xpix]**2 + \
                             distResid**2)
            yerr = math.sqrt(starlist[6][rr]**2 + ydistErrMap[ypix,xpix]**2 + \
                             distResid**2)
        else:
            xerr = math.sqrt(starlist[5][rr]**2 + xdistErrMap[ypix,xpix]**2)
            yerr = math.sqrt(starlist[6][rr]**2 + ydistErrMap[ypix,xpix]**2)

        starlist[5][rr] = xerr
        starlist[6][rr] = yerr

    # Reformat the columns so they get printed out nicely
    starlist[0].reformat('%-13s ')
    starlist[1].reformat('%6.3f ')
    starlist[2].reformat('%8.3f')
    starlist[3].reformat('%9.3f ')
    starlist[4].reformat('%9.3f ')
    starlist[5].reformat('%6.3f')
    starlist[6].reformat('%6.3f')
    starlist[7].reformat('%11.4f')
    starlist[8].reformat('%5.2f')
    starlist[9].reformat('%5d')
    starlist[10].reformat('%8.4f')

    # Write out the new starlist
    outroot = mosaicStarlist.replace('rms', 'rms_dist')
    starlist.writeto(outroot)
Esempio n. 2
0
def lgsAnimate(redoImages=False):
    dataRoot = "/u/ghezgroup/data/gc/"

    imgRoots = ["05jullgs", "06maylgs1", "06junlgs", "06jullgs", "07maylgs", "07auglgs", "08maylgs1"]

    workRoot = "/u/ghezgroup/public_html/gc/images/media/image_anim/"
    alignRoot = workRoot + "align/align"

    s = starset.StarSet(alignRoot)
    names = s.getArray("name")
    idx = names.index("SgrA")

    sgraxOrig = s.stars[idx].getArrayAllEpochs("xorig")
    sgrayOrig = s.stars[idx].getArrayAllEpochs("yorig")
    sgrax = s.stars[idx].getArrayAllEpochs("xpix")
    sgray = s.stars[idx].getArrayAllEpochs("ypix")
    print sgraxOrig
    print sgrax
    print sgrayOrig
    print sgray

    sgrax = array([602.831, 600.688, 600.9547, 601.239, 601.118, 601.5432, 600.7679])
    sgray = array([689.024, 686.918, 687.0692, 686.7293, 686.971, 686.8857, 687.4686])
    # Color Ranges for Images - Log Scale
    vmin = array([2.55, 2.52, 2.45, 2.48, 2.5, 2.55, 2.5])
    vmax = array([3.4, 3.33, 3.38, 3.35, 3.4, 3.25, 3.25])

    # Image plate scale
    scale = 0.00996

    if len(imgRoots) != len(sgrax):
        print "Problem... images and align do not match. Compare to align.list"
        print imgRoots

    import gcutil, nirc2

    if redoImages:
        # Need to rotate images
        from pyraf import iraf as ir

        ir.unlearn("rotate")
        ir.rotate.boundary = "constant"
        ir.rotate.constant = 0
        ir.rotate.interpolant = "spline3"

    # Need to plot images
    pylab.clf()
    for i in range(len(imgRoots)):
        imgIn = dataRoot + imgRoots[i] + "/combo/mag" + imgRoots[i] + "_kp.fits"
        imgOut = "images/mag" + imgRoots[i] + "_rot.fits"

        trans = objects.Transform()
        trans.loadFromAbsolute(root=workRoot, align="align/align.trans", idx=i)
        trans.linearToSpherical(override=False)

        hdr = pyfits.getheader(imgIn)
        # phi = nirc2.getPA(hdr)
        phi = math.degrees(trans.angle)
        if phi != 0:
            phi *= -1

        if redoImages:
            gcutil.rmall([imgOut])
            ir.rotate.xin = sgraxOrig[i]
            ir.rotate.yin = sgrayOrig[i]
            ir.rotate.xout = sgrax[i]
            ir.rotate.yout = sgray[i]
            ir.rotate(imgIn, imgOut, phi)

        img = pyfits.getdata(imgOut)

        xax = arange(0, img.shape[0])
        yax = arange(0, img.shape[1])

        xax = (xax - sgrax[1]) * -scale
        yax = (yax - sgray[1]) * scale
        pylab.imshow(log10(img), extent=[xax[0], xax[-1], yax[0], yax[-1]], vmin=vmin[i], vmax=vmax[i])
        pylab.plot([0], [0], "k+")
        # pylab.axis([0.5, -0.5, -0.5, 0.5])
        pylab.axis([0.8, -0.8, -0.8, 0.8])
        # pylab.axis([3, -3, -3, 3])
        pylab.xlabel("RA Offset from Sgr A* (arcsec)")
        pylab.ylabel("RA Offset from Sgr A* (arcsec)")
        pylab.title(imgRoots[i])

        pylab.savefig("frame%d.png" % i)
def lgsAnimate(redoImages=False):
    dataRoot = '/u/ghezgroup/data/gc/'

    imgRoots = [
        '05jullgs', '06maylgs1', '06junlgs', '06jullgs', '07maylgs',
        '07auglgs', '08maylgs1'
    ]

    workRoot = '/u/ghezgroup/public_html/gc/images/media/image_anim/'
    alignRoot = workRoot + 'align/align'

    s = starset.StarSet(alignRoot)
    names = s.getArray('name')
    idx = names.index('SgrA')

    sgraxOrig = s.stars[idx].getArrayAllEpochs('xorig')
    sgrayOrig = s.stars[idx].getArrayAllEpochs('yorig')
    sgrax = s.stars[idx].getArrayAllEpochs('xpix')
    sgray = s.stars[idx].getArrayAllEpochs('ypix')
    print sgraxOrig
    print sgrax
    print sgrayOrig
    print sgray

    sgrax = array(
        [602.831, 600.688, 600.9547, 601.239, 601.118, 601.5432, 600.7679])
    sgray = array(
        [689.024, 686.918, 687.0692, 686.7293, 686.971, 686.8857, 687.4686])
    # Color Ranges for Images - Log Scale
    vmin = array([2.55, 2.52, 2.45, 2.48, 2.5, 2.55, 2.5])
    vmax = array([3.4, 3.33, 3.38, 3.35, 3.4, 3.25, 3.25])

    # Image plate scale
    scale = 0.00996

    if (len(imgRoots) != len(sgrax)):
        print 'Problem... images and align do not match. Compare to align.list'
        print imgRoots

    import gcutil, nirc2

    if (redoImages):
        # Need to rotate images
        from pyraf import iraf as ir
        ir.unlearn('rotate')
        ir.rotate.boundary = 'constant'
        ir.rotate.constant = 0
        ir.rotate.interpolant = 'spline3'

    # Need to plot images
    pylab.clf()
    for i in range(len(imgRoots)):
        imgIn = dataRoot + imgRoots[i] + '/combo/mag' + imgRoots[i] + '_kp.fits'
        imgOut = 'images/mag' + imgRoots[i] + '_rot.fits'

        trans = objects.Transform()
        trans.loadFromAbsolute(root=workRoot, align='align/align.trans', idx=i)
        trans.linearToSpherical(override=False)

        hdr = pyfits.getheader(imgIn)
        #phi = nirc2.getPA(hdr)
        phi = math.degrees(trans.angle)
        if (phi != 0):
            phi *= -1

        if (redoImages):
            gcutil.rmall([imgOut])
            ir.rotate.xin = sgraxOrig[i]
            ir.rotate.yin = sgrayOrig[i]
            ir.rotate.xout = sgrax[i]
            ir.rotate.yout = sgray[i]
            ir.rotate(imgIn, imgOut, phi)

        img = pyfits.getdata(imgOut)

        xax = arange(0, img.shape[0])
        yax = arange(0, img.shape[1])

        xax = (xax - sgrax[1]) * -scale
        yax = (yax - sgray[1]) * scale
        pylab.imshow(log10(img),
                     extent=[xax[0], xax[-1], yax[0], yax[-1]],
                     vmin=vmin[i],
                     vmax=vmax[i])
        pylab.plot([0], [0], 'k+')
        #pylab.axis([0.5, -0.5, -0.5, 0.5])
        pylab.axis([0.8, -0.8, -0.8, 0.8])
        #pylab.axis([3, -3, -3, 3])
        pylab.xlabel('RA Offset from Sgr A* (arcsec)')
        pylab.ylabel('RA Offset from Sgr A* (arcsec)')
        pylab.title(imgRoots[i])

        pylab.savefig('frame%d.png' % i)