Example #1
0
def crossmatch_cartesian(coords_image, coords_ref, tolerance=None):
    """
    Crossmatch source coordinates with reference-star coordinates.

    Parameters
    ----------
    coords_image : array-like
        The coordinates of points to match
    coords_ref : array-like
        The coordinates of reference points to match
    tolerance : float
        Crossmatch distance in pixels (default: 5)

    """

    if tolerance is None:
        tolerance = 5.

    try:
        kdt = KDT(coords_ref, balanced_tree=False, compact_nodes=False)
    except TypeError:
        kdt = KDT(coords_ref)

    ds,ind_ref = kdt.query(coords_image, k=1, distance_upper_bound=tolerance)
    mask_xmatch = ds < tolerance
    ind_image = np.arange(len(coords_image))

    return ind_image[mask_xmatch], ind_ref[mask_xmatch], ds[mask_xmatch]
Example #2
0
def check_n_in_aper(radius_factor=1, k=100):

    for catfile in find_files(bcdphot_out_path, "*_combined_hdr_catalog.txt"):

        print
        print catfile
        names = open(catfile).readline().split()[1:]
        cat = np.recfromtxt(catfile, names=names)

        xscfile = catfile.replace('combined_hdr_catalog.txt', '2mass_xsc.tbl')
        print xscfile
        names = open(xscfile).read().split('\n')[76].split('|')[1:-1]
        xsc = np.recfromtxt(xscfile, skip_header=80, names=names)

        n_in_aper = []
        coords = radec_to_coords(cat.ra, cat.dec)
        kdt = KDT(coords)
        for i in range(xsc.size):
            r_deg = xsc.r_ext[i] / 3600.

            idx, ds = spherematch2(xsc.ra[i],
                                   xsc.dec[i],
                                   cat.ra,
                                   cat.dec,
                                   kdt,
                                   tolerance=radius_factor * r_deg,
                                   k=k)
            n_in_aper.append(ds.size)
        for i in [(i, n_in_aper.count(i)) for i in set(n_in_aper)]:
            print i
Example #3
0
def closest_pair(points):
    # Brute force
    # minDist = float('inf')
    # out = None
    # for pair in combinations(points, 2):
    #     d = dist(*pair)
    #     if d < minDist:
    #         minDist = d
    #         out = pair
    # return out

    # My KDTree
    # tree = kdtree(list(points))
    # minDist, pair = float('inf'), None
    # for point in points:
    #     newDist, newPoint = nearest(tree, point, 0, float('inf'), None, 0)
    #     if newDist < minDist:
    #         minDist = newDist
    #         pair = (newPoint, point)
    # return pair

    # Use scipy
    tree = KDT(points)
    dists, idxs = tree.query(points, k=2)
    dists, idxs = dists[:, 1], idxs[:, 1]
    minIdx = dists.argmin()
    return points[minIdx], points[idxs[minIdx]]
Example #4
0
def CartMatch(coord1, coord2, tol=None, nnearest=1):
    """
    Cartesian Coordinate mathcing
    """
    # sanitize
    coord1 = np.array(coord1, ndmin=1)
    coord2 = np.array(coord2, ndmin=1)

    # check the dimensions of the coordinate
    npairs1 = len(coord1)
    ndim1       =       1    if   len( np.shape(coord1) )  ==   1  else   \
                        np.shape(coord1)[1]
    npairs2 = len(coord2)
    ndim2       =       1    if   len( np.shape(coord2) )  ==   1  else   \
                        np.shape(coord2)[1]

    # check whether the coord1 and coord2 have the same shape
    if ndim1 != ndim2:
        raise RuntimeError("The dims of coord1/2 are not the same.")
    else:
        ndim = ndim1

    # make proper arrays if they are 1d arrays
    if ndim == 1:
        coord1 = np.array([coord1, np.zeros(len(coord1))]).T
        coord2 = np.array([coord2, np.zeros(len(coord2))]).T

    # kdtree the coord2
    kdt = KDT(coord2)
    if nnearest == 1:
        idxs2 = kdt.query(coord1)[1]
    elif nnearest > 1:
        idxs2 = kdt.query(coord1, nnearest)[1][:, -1]
    else:
        raise ValueError('invalid nnearest ' + str(nnearest))

    # distance - warning: this could be over float if the precision is not enough, we assume that case is beyond the distance of interest...
    ds = np.sqrt(np.sum((coord1 - coord2[idxs2])**2, axis=1))

    # index of coord1
    idxs1 = np.arange(npairs1)

    # distance filtering
    if tol is not None:
        msk = ds < tol
        idxs1 = idxs1[msk]
        idxs2 = idxs2[msk]
        ds = ds[msk]

    return idxs1, idxs2, ds
Example #5
0
def build_sp_kdtree(ra, dec, degree=False):
    """
    ra and dec are in radian, if not set degree to True
    """

    x, y, z = radec2xyz(ra, dec, degree=degree)
    coords = np.empty((x.size, 3))
    coords[:, 0] = x
    coords[:, 1] = y
    coords[:, 2] = z

    tree = KDT(coords, balanced_tree=False)

    return tree
Example #6
0
def measure_particleparticle(subhalostars,
                             emptybox,
                             boxx,
                             boxy,
                             boxz,
                             kneighbors=3,
                             maxNkernels=5,
                             pixelsizekpc=0.25,
                             distance=10.,
                             projection='None',
                             outtag=None):
    if verbose:
        print_verbose_string('Measuring particle-particle distances in 3D ...')

    'Choose which key to use for projection'
    if projection == 'None':
        projkey = 'CoordinatesOrigin'
    else:
        projkey = 'Coordinates' + projection

    'Put particle coordinates in physical units'
    ptclx = subhalostars[projkey][:, 0] * (a / h)
    ptcly = subhalostars[projkey][:, 1] * (a / h)
    ptclz = subhalostars[projkey][:, 2] * (a / h)
    ptcld2o = np.sqrt(ptclx**2 + ptcly**2 + ptclz**2)

    'Calculate distance to the kth nearest neighbor (star particles), and the physical extent of the smoothing'
    ptclcoords = zip(ptclx, ptcly, ptclz)
    ptclkdt = KDT(ptclcoords)
    ptcldistances_k, ids_k = ptclkdt.query(ptclcoords, k=kneighbors)
    rstell = ptcldistances_k[:, -1] + pixelsizekpc
    rstell[rstell > 30] = 30.
    maxrstell = maxNkernels * rstell

    'Plot kth nearest neighbor and smoothing extents for this galaxy'
    plot_kneighbors(ptclkdt, ptclcoords, outtag, pixelsizekpc)
    plot_smoothing_extent(maxrstell, outtag, pixelsizekpc)

    'Place each particle in its pixel bin'
    'NOTE: the xyz values in the box[xyz] arrays are *not* pixel centers -- they are the left edges of the pixels!'
    'digitize returns indices such that boxx[i-1] <= ptclx < boxx[i] .. but need to subtract 1 otherwise we have too much shifting'
    ptclx_indices = np.digitize(ptclx, boxx[:, 0, 0]) - 1
    ptcly_indices = np.digitize(ptcly, boxy[0, :, 0]) - 1
    ptclz_indices = np.digitize(ptclz, boxz[0, 0, :]) - 1

    return ptclx_indices, ptcly_indices, ptclz_indices, rstell, maxrstell, ptcld2o, ptclx, ptcly, ptclz
Example #7
0
def spherematch(ra1, dec1, ra2, dec2, tolerance=1 / 3600.):
    """
	Uses a k-d tree to efficiently match two pairs of coordinates in spherical
	geometry, with a tolerance in degrees.
	"""

    args = ra1, dec1, ra2, dec2
    ra1, dec1, ra2, dec2 = map(partial(np.array, copy=False), args)
    coords1 = radec_to_coords(ra1, dec1)
    coords2 = radec_to_coords(ra2, dec2)
    kdt = KDT(coords2)
    idx2 = kdt.query(coords1)[1]
    ds = great_circle_distance(ra1, dec1, ra2[idx2], dec2[idx2])
    idx1 = np.arange(ra1.size)
    msk = ds < tolerance
    idx1 = idx1[msk]
    idx2 = idx2[msk]
    ds = ds[msk]
    return idx1, idx2, ds
def comoving_neighbors(zcoord1, zcoord2, nthneighbor=1, maxscale=None):
    """
    """
    ccoord1 = radecz_to_comoving(zcoord1)
    ccoord2 = radecz_to_comoving(zcoord2)
    kdt = KDT(ccoord2)
    if nthneighbor == 1:
        indx2 = kdt.query(ccoord1)[1]
    elif nthneighbor > 1:
        indx2 = kdt.query(ccoord1, nthneighbor)[1][:, -1]
    else:
        raise ValueError('{0}th neighbor cannot be found'.format(nthneighbor))

    ds = np.linalg.norm(ccoord1-ccoord2[indx2,:], axis=1)
    indx1 = np.arange(ds.size)
    if maxscale != None:
       iselect = ds < maxscale
       indx1 = indx1[iselect]
       indx2 = indx2[iselect]
       ds = ds[iselect]

    return indx1, indx2, ds
Example #9
0
def pix_match(targname, iter, catDir='./', matchtol=2):

    infileF606W = catDir + targname + '_F606W_cut_std_{0:d}.dat'.format(iter)
    infileF814W = catDir + targname + '_F814W_cut_std_{0:d}.dat'.format(iter)

    f606w = np.loadtxt(infileF606W, dtype='float')
    f814w = np.loadtxt(infileF814W, dtype='float')

    print('Length F606W', len(f606w))
    print('Length F814W', len(f814w))

    xt_f606w = np.vstack(
        (f606w[:, xt1], f606w[:, xt2], f606w[:, xt3], f606w[:, xt4]))
    xt_f814w = np.vstack(
        (f814w[:, xt1], f814w[:, xt2], f814w[:, xt3], f814w[:, xt4]))

    yt_f606w = np.vstack(
        (f606w[:, yt1], f606w[:, yt2], f606w[:, yt3], f606w[:, yt4]))
    yt_f814w = np.vstack(
        (f814w[:, yt1], f814w[:, yt2], f814w[:, yt3], f814w[:, yt4]))

    xm_606 = np.nanmean(xt_f606w, axis=0)
    xm_814 = np.nanmean(xt_f814w, axis=0)

    ym_606 = np.nanmean(yt_f606w, axis=0)
    ym_814 = np.nanmean(yt_f814w, axis=0)

    coords1 = np.empty((xm_606.size, 2))
    coords2 = np.empty((xm_814.size, 2))

    coords1[:, 0] = xm_606
    coords1[:, 1] = ym_606

    coords2[:, 0] = xm_814
    coords2[:, 1] = ym_814

    kdt = KDT(coords1)
    idxs2 = kdt.query(coords2)[1]

    ds = distArr(xm_814, ym_814, xm_606[idxs2], ym_606[idxs2])

    idxs1 = np.arange(xm_814.size)

    msk = ds < matchtol
    idxs1 = idxs1[msk]
    idxs2 = idxs2[msk]
    ds = ds[msk]

    # print(max(idxs1))
    # print(max(idxs2))

    outfile = catDir + targname + '-cut_F606W_match_{0:d}.dat'.format(iter)
    np.savetxt(outfile, idxs2, fmt='%4i')

    outfile = catDir + targname + '-cut_F814W_match_{0:d}.dat'.format(iter)
    np.savetxt(outfile, idxs1, fmt='%4i')

    outfile = catDir + targname + '-cut_ds_{0:d}.dat'.format(iter)
    np.savetxt(outfile, ds, fmt='%1.4f')

    return None
Example #10
0
def match(x1, y1, m1, x2, y2, m2, dr_tol, dm_tol=None):
    """
    Finds matches between two different catalogs. No transformations are done and it
    is assumed that the two catalogs are already on the same coordinate system
    and magnitude system.

    For two stars to be matched, they must be within a specified radius (dr_tol) and
    delta-magnitude (dm_tol). For stars with more than 1 neighbor (within the tolerances),
    if one is found that is the best match in both brightness and positional offsets
    (closest in both), then the match is made. Otherwise,
    their is a conflict and no match is returned for the star.
    
 
    Parameters
    x1 : array-like
        X coordinate in the first catalog
    y1 : array-like
        Y coordinate in the first catalog (shape of array must match `x1`)
    m1 : array-like
        Magnitude in the first catalog. Must have the same shape as x1.
    x2 : array-like
        X coordinate in the second catalog
    y2 : array-like
        Y coordinate in the second catalog (shape of array must match `x2`)
    m2 : array-like
        Magnitude in the second catalog. Must have the same shape as x2.
    dr_tol : float
        How close (in units of the first catalog) a match has to be to count as a match.
        For stars with more than one nearest neighbor, the delta-magnitude is checked
        and the closest in delta-mag is chosen.
    dm_tol : float or None, optional
        How close in delta-magnitude a match has to be to count as a match.
        If None, then any delta-magnitude is allowed.
 
    Returns
    -------
    idx1 : int array
        Indicies into the first catalog of the matches. Will never be
        larger than `x1`/`y1`.
    idx2 : int array
        Indicies into the second catalog of the matches. Will never be
        larger than `x1`/`y1`.
    dr : float array
        Distance between the matches.
    dm : float array
        Delta-mag between the matches. (m1 - m2)
 
    """

    x1 = np.array(x1, copy=False)
    y1 = np.array(y1, copy=False)
    m1 = np.array(m1, copy=False)
    x2 = np.array(x2, copy=False)
    y2 = np.array(y2, copy=False)
    m2 = np.array(m2, copy=False)

    if x1.shape != y1.shape:
        raise ValueError('x1 and y1 do not match!')
    if x2.shape != y2.shape:
        raise ValueError('x2 and y2 do not match!')

    # Setup coords1 pairs and coords 2 pairs
    # this is equivalent to, but faster than just doing np.array([x1, y1])
    coords1 = np.empty((x1.size, 2))
    coords1[:, 0] = x1
    coords1[:, 1] = y1

    # this is equivalent to, but faster than just doing np.array([x1, y1])
    coords2 = np.empty((x2.size, 2))
    coords2[:, 0] = x2
    coords2[:, 1] = y2

    # Utimately we will generate arrays of indices.
    # idxs1 is the indices for matches into catalog 1. This
    # is just a place holder for which stars actually
    # have matches.
    idxs1 = np.ones(x1.size, dtype=int) * -1
    idxs2 = np.ones(x1.size, dtype=int) * -1

    # The matching will be done using a KDTree.
    kdt = KDT(coords2)

    # This returns the number of neighbors within the specified
    # radius. We will use this to find those stars that have no or one
    # match and deal with them easily. The more complicated conflict
    # cases will be dealt with afterward.
    i2_match = kdt.query_ball_point(coords1, dr_tol)
    Nmatch = np.array([len(idxs) for idxs in i2_match])

    # What is the largest number of matches we have for a given star?
    Nmatch_max = Nmatch.max()

    # Loop through and handle all the different numbers of matches.
    # This turns out to be the most efficient so we can use numpy
    # array operations. Remember, skip the Nmatch=0 objects... they
    # already have indices set to -1.
    for nn in range(1, Nmatch_max + 1):
        i1_nn = np.where(Nmatch == nn)[0]

        if len(i1_nn) == 0:
            continue

        if nn == 1:
            i2_nn = np.array([i2_match[mm][0] for mm in i1_nn])
            if dm_tol != None:
                dm = np.abs(m1[i1_nn] - m2[i2_nn])
                keep = dm < dm_tol
                idxs1[i1_nn[keep]] = i1_nn[keep]
                idxs2[i1_nn[keep]] = i2_nn[keep]
            else:
                idxs1[i1_nn] = i1_nn
                idxs2[i1_nn] = i2_nn
        else:
            i2_tmp = np.array([i2_match[mm] for mm in i1_nn])

            # Repeat star list 1 positions and magnitudes
            # for nn times (tile then transpose)
            x1_nn = np.tile(x1[i1_nn], (nn, 1)).T
            y1_nn = np.tile(y1[i1_nn], (nn, 1)).T
            m1_nn = np.tile(m1[i1_nn], (nn, 1)).T

            # Get out star list 2 positions and magnitudes
            x2_nn = x2[i2_tmp]
            y2_nn = y2[i2_tmp]
            m2_nn = m2[i2_tmp]
            dr = np.abs(x1_nn - x2_nn, y1_nn - y2_nn)
            dm = np.abs(m1_nn - m2_nn)

            if dm_tol != None:
                # Don't even consider stars that exceed our
                # delta-mag threshold.
                dr_msk = np.ma.masked_where(dm > dm_tol, dr)
                dm_msk = np.ma.masked_where(dm > dm_tol, dm)

                # Remember that argmin on masked arrays can find
                # one of the masked array elements if ALL are masked.
                # But our subsequent "keep" check should get rid of all
                # of these.
                dm_min = dm_msk.argmin(axis=1)
                dr_min = dr_msk.argmin(axis=1)

                # Double check that "min" choice is still within our
                # detla-mag tolerence.
                dm_tmp = np.choose(dm_min, dm.T)

                keep = (dm_min == dr_min) & (dm_tmp < dm_tol)
            else:
                dm_min = dm.argmin(axis=1)
                dr_min = dr.argmin(axis=1)

                keep = (dm_min == dr_min)

            i2_keep_2D = i2_tmp[keep]
            dr_keep = dr_min[keep]  # which i2 star for a given i1 star
            ii_keep = np.arange(
                len(dr_keep))  # a running index for the i2 keeper stars.

            idxs1[i1_nn[keep]] = i1_nn[keep]
            idxs2[i1_nn[keep]] = i2_keep_2D[ii_keep, dr_keep]

    idxs1 = idxs1[idxs1 >= 0]
    idxs2 = idxs2[idxs2 >= 0]

    dr = np.hypot(x1[idxs1] - x2[idxs2], y1[idxs1] - y2[idxs2])
    dm = m1[idxs1] - m2[idxs2]

    # Deal with duplicates
    duplicates = [
        item for item, count in Counter(idxs2).iteritems() if count > 1
    ]
    print 'Found {0:d} out of {1:d} duplicates'.format(len(duplicates),
                                                       len(dm))
    # for dd in range(len(duplicates)):
    #     dups = np.where(idxs2 == duplicates[dd])[0]

    #     # Handle them in brightness order -- brightest first in the first starlist
    #     fsort = m1[dups].argsort()

    #     # For every duplicate, match to the star that is closest in space and
    #     # magnitude. HMMMM.... this doesn't seem like it will work optimally.

    return idxs1, idxs2, dr, dm
Example #11
0
def carte2d_and_z_match(x1, y1, z1, x2, y2, z2, ztol, stol):
    """
    Finds matches in one catalog to another.

    Parameters
    x1 : array-like
        Cartesian coordinate x of the first catalog
    y1 : array-like
        Cartesian coordinate y of the first catalog (shape of array must match `x1`)
    z1 : array-like
        Cartesian coordinate z of the first catalog (shape of array must match `x1`)
    x2 : array-like
        Cartesian coordinate x of the second catalog
    y2 : array-like
        Cartesian coordinate y of the second catalog (shape of array must match `x2`)
    z2 : array-like
        Cartesian coordinate z of the second catalog (shape of array must match `x2`)
    ztol: float or array-like
        The tolarance in z direction. Its shape must match to `x1` if it is an array.
    stol: float or None, optional
        How close (in the unit of the cartesian coordinate) a match has to be to count as a match.  If None,
        all nearest neighbors for the first catalog will be returned.
    nnearest : int, optional
        The nth neighbor to find.  E.g., 1 for the nearest nearby, 2 for the
        second nearest neighbor, etc.  Particularly useful if you want to get
        the nearest *non-self* neighbor of a catalog.  To do this, use:
        ``carte2dmatch(x, y, x, y, nnearest=2)``

    Returns
    -------
    idx1 : int array
        Indecies into the first catalog of the matches. Will never be
        larger than `x1`/`y1`.
    idx2 : int array
        Indecies into the second catalog of the matches. Will never be
        larger than `x1`/`y1`.
    ds : float array
        Distance (in the unit of the cartesian coordinate) between the matches
    dz : float array
        Distance (in the unit of the cartesian coordinate) between the matches


    """
    # sanitize
    x1 = np.array(x1, copy=False)
    y1 = np.array(y1, copy=False)
    z1 = np.array(z1, copy=False)
    x2 = np.array(x2, copy=False)
    y2 = np.array(y2, copy=False)
    z2 = np.array(z2, copy=False)

    # check
    if x1.shape != y1.shape or x1.shape != z1.shape:
        raise ValueError('x1 and y1/z1 do not match!')
    if x2.shape != y2.shape or x2.shape != z2.shape:
        raise ValueError('x2 and y2/z2 do not match!')

    # this is equivalent to, but faster than just doing np.array([x1, y1])
    coords1 = np.empty((x1.size, 2))
    coords1[:, 0] = x1
    coords1[:, 1] = y1

    # this is equivalent to, but faster than just doing np.array([x1, y1])
    coords2 = np.empty((x2.size, 2))
    coords2[:, 0] = x2
    coords2[:, 1] = y2

    # set kdt for coord2
    kdt = KDT(coords2)

    # ---
    # Match using kdt
    # ---
    idxs2_within_balls = kdt.query_ball_point(
        coords1, stol)  # find the neighbors within a ball
    n_within_ball = np.array(map(len, idxs2_within_balls),
                             dtype=np.int)  # counts within each ball
    zero_within_ball = np.where(
        n_within_ball == 0)[0]  # find which one does not have neighbors
    nonzero_within_ball = np.where(
        n_within_ball > 0)[0]  # find which one has neighbors

    # declare the distance / idxs2 for each element in nonzero_within_ball
    # I use no-brain looping here, slow but seems to be acceptable
    dz_within_ball = []  # the distance
    idxs2 = []
    for i in nonzero_within_ball:
        #print i, len(idxs2_within_balls[i]), z1[i], z2[ idxs2_within_balls[i] ]
        # Another sub-kdt within a ball, but this times we use kdt.query to find the nearest one
        dz_temp, matched_id_temp = KDT(
            np.transpose([z2[idxs2_within_balls[i]]
                          ])).query(np.transpose([z1[i]]))
        matched_id_temp = idxs2_within_balls[i][matched_id_temp]
        # append
        dz_within_ball.append(
            dz_temp)  # the distance of the nearest neighbor within the ball
        idxs2.append(
            matched_id_temp
        )  # the index in array2 of the nearest neighbor within the ball

    # index for coord1 - only using the object with non-zero neighbor in the ball
    idxs1 = np.arange(x1.size)[nonzero_within_ball]
    idxs2 = np.array(idxs2, dtype=np.int)
    dz_within_ball = np.array(dz_within_ball, dtype=np.float)

    # clean
    del dz_temp, matched_id_temp

    # msk to clean the object with dz > ztol
    ztol = np.array(ztol, ndmin=1)
    if len(ztol) == 1:
        msk = (dz_within_ball < ztol)
    elif len(ztol) == len(x1):
        msk = (dz_within_ball < ztol[nonzero_within_ball])
    else:
        raise ValueError(
            "The length of ztol has to be 1 (float) or as the same as input x1/y1. len(ztol):",
            len(ztol))

    # only keep the matches which have dz < ztol
    idxs1 = idxs1[msk]
    idxs2 = idxs2[msk]
    ds = np.hypot(x1[idxs1] - x2[idxs2], y1[idxs1] - y2[idxs2])
    dz = dz_within_ball[msk]

    return idxs1, idxs2, ds, dz
Example #12
0
def carte2dmatch(x1, y1, x2, y2, tol=None, nnearest=1):
    """
    Finds matches in one catalog to another.

    Parameters
    x1 : array-like
        Cartesian coordinate x of the first catalog
    y1 : array-like
        Cartesian coordinate y of the first catalog (shape of array must match `x1`)
    x2 : array-like
        Cartesian coordinate x of the second catalog
    y2 : array-like
        Cartesian coordinate y of the second catalog (shape of array must match `x2`)
    tol : float or None, optional
        How close (in the unit of the cartesian coordinate) a match has to be to count as a match.  If None,
        all nearest neighbors for the first catalog will be returned.
    nnearest : int, optional
        The nth neighbor to find.  E.g., 1 for the nearest nearby, 2 for the
        second nearest neighbor, etc.  Particularly useful if you want to get
        the nearest *non-self* neighbor of a catalog.  To do this, use:
        ``carte2dmatch(x, y, x, y, nnearest=2)``

    Returns
    -------
    idx1 : int array
        Indecies into the first catalog of the matches. Will never be
        larger than `x1`/`y1`.
    idx2 : int array
        Indecies into the second catalog of the matches. Will never be
        larger than `x1`/`y1`.
    ds : float array
        Distance (in the unit of the cartesian coordinate) between the matches



    """
    # sanitize
    x1 = np.array(x1, copy=False)
    y1 = np.array(y1, copy=False)
    x2 = np.array(x2, copy=False)
    y2 = np.array(y2, copy=False)

    # check
    if x1.shape != y1.shape:
        raise ValueError('x1 and y1 do not match!')
    if x2.shape != y2.shape:
        raise ValueError('x2 and y2 do not match!')

    # this is equivalent to, but faster than just doing np.array([x1, y1, z1])
    coords1 = np.empty((x1.size, 2))
    coords1[:, 0] = x1
    coords1[:, 1] = y1

    # this is equivalent to, but faster than just doing np.array([x1, y1, z1])
    coords2 = np.empty((x2.size, 2))
    coords2[:, 0] = x2
    coords2[:, 1] = y2

    # set kdt for coord2
    kdt = KDT(coords2)
    if nnearest == 1:
        idxs2 = kdt.query(coords1)[1]
    elif nnearest > 1:
        idxs2 = kdt.query(coords1, nnearest)[1][:, -1]
    else:
        raise ValueError('invalid nnearest ' + str(nnearest))

    # calc the distance
    ds = np.hypot(x1 - x2[idxs2], y1 - y2[idxs2])

    # index for coord1
    idxs1 = np.arange(x1.size)

    if tol is not None:
        msk = ds < tol
        idxs1 = idxs1[msk]
        idxs2 = idxs2[msk]
        ds = ds[msk]

    return idxs1, idxs2, ds
Example #13
0
def run_xsc_phot(bcdphot_out_path, mosaic_path):
    replaced = {}
    for cat in find_files(bcdphot_out_path, "*_combined_hdr_catalog.txt"):

        print("\n======================================================")
        print("\nadjusting photometry in: {}".format(cat.split('/')[-1]))
        print("------------------------------------------------------")
        outpath = cat.replace('combined_hdr_catalog.txt', '2mass_xsc.tbl')

        # retrieve 2mass data if file doesn't already exist (from previous run)
        if not os.path.isfile(outpath):
            # get url and retrieve data
            url = query_2mass_xsc_polygon(*get_region_corners(cat))
            print("\ndownloading 2MASS photometry from: {}".format(url))
            text = urllib2.urlopen(url).read()
            # write to disk
            with open(outpath, 'w') as f:
                f.write(text)
            print("\ncreated file: {}".format(outpath))

        # read back in as recarray
        print("\nreading: {}".format(outpath))
        names = open(outpath).read().split('\n')[76].split('|')[1:-1]
        da = np.recfromtxt(outpath, skip_header=80, names=names)

        # write input file for xsc_phot.pro
        infile_outpath = '/'.join(cat.split('/')[:-1]) + '/xsc.txt'
        with open(infile_outpath, 'w') as w:
            for i in range(da.shape[0]):
                w.write("{} {} {} {}\n".format(da.designation[i], da.ra[i],
                                               da.dec[i], da.r_ext[i]))
        print(
            "\ncreated input file for xsc_phot.pro: {}".format(infile_outpath))

        # locate the FITS mosaic file for xsc_phot.pro to do photometry on
        reg, ch = cat.split('/')[-1].split('_')[:2]
        mosaicfile = filter(lambda x: 'dirbe{}/ch{}/long/full/Combine'\
         .format(reg,ch) in x, find_files(mosaic_path, '*mosaic.fits'))[0]
        print("\nfound mosaic file: {}".format(mosaicfile))

        # spawn IDL subprocess running xsc_phot.pro and catch stdout in file
        outpath = infile_outpath.replace('xsc.txt', 'xsc_phot_out.txt')
        if not os.path.isfile(outpath):
            outfile = open(outpath, 'w')
            print("\nspawning xsc_phot.pro IDL subprocess")
            cmd = "xsc_phot,'" + mosaicfile + "','" + infile_outpath + "','long'"
            rc = subprocess.call(
                ['/usr/local/itt/idl71/bin/idl', '-quiet', '-e', cmd],
                stderr=subprocess.PIPE,
                stdout=outfile)
            outfile.close()

        # read in output to recarray
        print("\nreading: {}".format(outpath))
        phot = np.recfromtxt(outpath,
                             names=['id', 'flux', 'unc', 'sky', 'skyunc'])

        # make sure rows are aligned
        assert (da.designation == phot.id).all()

        # ignore xsc sources we got a NaN or negative flux for
        bad = np.isnan(phot.flux) | (phot.flux < 0)
        print("\naper.pro returned NaN or negative flux for {} sources".format(
            bad.sum()))
        if bad.sum() > 0:
            for i in phot[bad].id:
                print(i)
            outpath = cat.replace('combined_hdr_catalog.txt',
                                  'xsc_nan_phot.csv')
            with open(outpath, 'w') as f:
                w = csv.writer(f)
                w.writerow(da.dtype.names)
                w.writerows(da[bad].tolist())
            print('\ncreated file: {}'.format(outpath))
        phot = phot[~bad]
        da = da[~bad]

        # read in pipeline catalog
        print("\nreading: {}".format(cat))
        names = open(cat).readline().split()[1:]
        c = np.recfromtxt(cat, names=names)

        # loop through xsc sources and find matches in pipeline catalog
        print(
            "\nfinding records associated with XSC sources in pipeline catalog"
        )
        c_flux_total = []
        n_in_aper = []
        c_idx = []
        coords = radec_to_coords(c.ra, c.dec)
        kdt = KDT(coords)
        for i in range(phot.size):
            radius = da.r_ext[i] / 3600.
            # idx1, idx2, ds = spherematch(da.ra[i], da.dec[i],
            # 	c.ra, c.dec, tolerance=radius)
            idx, ds = spherematch2(da.ra[i],
                                   da.dec[i],
                                   c.ra,
                                   c.dec,
                                   kdt,
                                   tolerance=radius,
                                   k=500)
            # c_flux_total.append(c.flux[idx2].sum())
            # n_in_aper.append(c.flux[idx2].size)
            # c_idx.append(idx2.tolist())
            c_flux_total.append(c.flux[idx].sum())
            n_in_aper.append(ds.size)
            c_idx.append(idx.tolist())
        print("\nhistogram of source counts in r_ext aperture")
        for i in [(i, n_in_aper.count(i)) for i in set(n_in_aper)]:
            print i

        # create new version of catalog file with xsc-associated entries replaced
        c_idx = np.array(flatten(c_idx))
        print("\nremoving {}, adding {}".format(c_idx.size, phot.size))
        replaced[cat] = {'old': c_idx.size, 'new': phot.size}
        replaced[cat]['hist'] = [(i, n_in_aper.count(i))
                                 for i in set(n_in_aper)]
        c = np.delete(c, c_idx)
        newrows = np.rec.array([(-i, da.ra[i], da.dec[i],
         phot.flux[i], phot.unc[i], 1) for i in \
         range(phot.size)], dtype=c.dtype)
        newcat = np.hstack((c, newrows))

        # write new version of catalog to disk
        fmt = ['%i'] + ['%0.8f'] * 2 + ['%.4e'] * 2 + ['%i']
        outpath = cat.replace('catalog.txt', 'catalog_xsc_cor.txt')
        np.savetxt(outpath, newcat, fmt=fmt, header=' '.join(names))
        print('\ncreated file: {}'.format(outpath))

        # make plot of total old vs. new flux
        plt.scatter(c_flux_total, phot.flux)
        ylim = plt.gca().get_ylim()
        plt.xlim(*ylim)
        max_y = ylim[1]
        plt.plot(ylim, ylim, 'r-')
        plt.xlabel('old flux [mJy]')
        plt.ylabel('new flux [mJy]')
        name = ' '.join(cat.split('/')[-1].split('_')[:2])
        plt.title(name)
        outpath = cat.replace('combined_hdr_catalog.txt',
                              'xsc_new_vs_old_phot.png')
        plt.savefig(outpath, dpi=200)
        plt.close()
        print('\ncreated file: {}'.format(outpath))

    outfile = 'xsc_replaced.json'
    json.dump(replaced, open(outfile, 'w'))
    print("\ncreated file: {}".format(outfile))
    print("\nremoved / added")
    for k, v in replaced.iteritems():
        print k.split('/')[-1], v['old'], v['new']
    m = np.mean([i['old'] / float(i['new']) for i in replaced.values()])
    print("average ratio: {}".format(m))
    print("\nK mag and r_ext of sources with NaN photometry:")
    for i in find_files(bcdphot_out_path, "*xsc_nan_phot.csv"):
        reg = i.split('/')[-1]
        rec = np.recfromcsv(i)
        bad_id = rec.designation.tolist()
        bad_k = rec.k_m_k20fe.tolist()
        bad_r_ext = rec.r_ext.tolist()
        print reg
        print("\tid\t\t\tKmag\tr_ext")
        if type(bad_id) is list:
            seq = sorted(zip(bad_id, bad_k, bad_r_ext), key=lambda x: x[0])
            for j, k, l in seq:
                print("\t{}\t{}\t{}".format(j, k, l))
        else:
            print("\t{}\t{}\t{}".format(bad_id, bad_k, bad_r_ext))
Example #14
0
def spherematch(ra1, dec1, ra2, dec2, tol=None, nnearest=1, nthreads=1):
    """
    Determines the matches between two catalogues of sources with 
    <ra, dec> coordinates.

    Parameters
    ----------
    ra1, dec1 : array_like
        Right ascension and declination of the 1st catalogue.
        Units are in `degrees`.

    ra2, dec2 : array_like
        Right ascension and declination of the 2nd catalogue.
        Units are in `degrees`.

    tol : float or None, optional
        How close (in degrees) a match has to be to count as a match.
        If None, all nearest neighbors for the 1st catalogue will be returned.

    nnearest : int, optional
        The nth neighbor to find. E.g. 1 for the nearest nearby, 2 for the 
        second nearest neighbor, etc. Partcularly useful if you want to get
        the nearest *non-self* neighbor of a catalogue.
        To do this use::

        ``spherematch(ra, dec, ra, dec, nnearest=2)``

        if `nnearest == 0`, all matches are returned.

    nthreads : int, optional
        Number of threads to use for calculation. This variable is set to 
        1 by default. Must be larger than 1.

    Returns
    ----------
    idx1 : int `numpy.ndarray`
        Indices of the 1st catalogue of the matches. Will never be larger 
        than `ra1`/`dec1`.

    idx2 : int `numpy.ndarray`
        Indices of the 2nd catalogue of the matches. Will never be larger
        than `ra1`/`dec1`.

    ds : float `numpy.ndarray`
        Distance (in degrees) between the matches.
    """
    file_msg = fd.Program_Msg(__file__)
    ## Checking input arguments
    valid_types = (list, np.ndarray)
    # `ra1`
    if not (isinstance(ra1, valid_types)):
        msg = '{0} `ra1` ({1}) is not a valid type!'.format(file_msg, type(ra1))
        raise LSSUtils_Error(msg)
    # `dec1`
    if not (isinstance(dec1, valid_types)):
        msg = '{0} `dec1` ({1}) is not a valid type!'.format(file_msg, type(dec1))
        raise LSSUtils_Error(msg)
    # `ra2`
    if not (isinstance(ra2, valid_types)):
        msg = '{0} `ra2` ({1}) is not a valid type!'.format(file_msg, type(ra2))
        raise LSSUtils_Error(msg)
    # `dec2`
    if not (isinstance(dec2, valid_types)):
        msg = '{0} `dec2` ({1}) is not a valid type!'.format(file_msg, type(dec2))
        raise LSSUtils_Error(msg)
    # `nnearest`
    if nnearest < 0:
        msg = '{0} `nnearest` ({1}) must be larger than `0`!'.format(file_msg,
            nnearest)
        raise LSSUtils_Error(msg)
    # `threads`
    if nthreads < 1:
        msg = '{0} `nthreads` ({1}) must be larger than `1`!'.format(file_msg,
            nthreads)
        raise LSSUtils_Error(msg)
    ##
    ## Converting arguments into arrays for ease of use
    ra1  = np.array(ra1 , copy=False)
    dec1 = np.array(dec1, copy=False)
    ra2  = np.array(ra2 , copy=False)
    dec2 = np.array(dec2, copy=False)
    ## Checking shape
    # 1st catalogue
    if ra1.shape != dec1.shape:
        msg = '{0} The shape of `ra1` ({1}) does not mathc that of `dec1` ({2}).'
        msg = msg.format(file_msg, ra1.shape, dec1.shape)
        raise LSSUtils_Error(msg)
    # 2nd catalogue
    if ra2.shape != dec2.shape:
        msg = '{0} The shape of `ra2` ({1}) does not mathc that of `dec2` ({2}).'
        msg = msg.format(file_msg, ra2.shape, dec2.shape)
        raise LSSUtils_Error(msg)
    ##
    ## Converting spherical coordinates into cartesian coordinates
    # 1st catalogue
    x1, y1, z1 = _spherical_to_cartesian_fast(  ra1.ravel(),
                                                dec1.ravel(),
                                                nthreads)
    coords1 = np.empty((x1.size,3))
    coords1[:, 0] = x1
    coords1[:, 1] = y1
    coords1[:, 2] = z1
    # 2nd catalogue
    x2, y2, z2 = _spherical_to_cartesian_fast(  ra2.ravel(),
                                                dec2.ravel(),
                                                nthreads)
    coords2 = np.empty((x2.size,3))
    coords2[:, 0] = x2
    coords2[:, 1] = y2
    coords2[:, 2] = z2
    ##
    ## Finding nearest neighbors
    kdt = KDT(coords2)
    # Finding neighbors
    if nnearest == 1:
        idx_s2 = kdt.query(coords1)[1]
    elif (nnearest == 0) and (tol is not None): # if you want ALL matches!
        p1_x, p1_y, p1_z = _spherical_to_cartesian_fast(90., 0  , nthreads)
        p2_x, p2_y, p2_z = _spherical_to_cartesian_fast(90., tol, nthreads)
        # Converting to floats
        p1_x   = float(p1_x)
        p1_y   = float(p1_y)
        p1_z   = float(p1_z)
        p2_x   = float(p2_x)
        p2_y   = float(p2_y)
        p2_z   = float(p2_z)
        r      = np.sqrt((p2_x - p1_x)**2 + (p2_y - p1_y)**2 + (p2_z - p1_z)**2)
        idx_s2 = kdt.query_ball_point(coords1, r)[0]
    elif nnearest > 1:
        idx_s2 = kdt.query(coords1, nnearest)[1][:, -1]
    else:
        msg = '{0} Invalid `nnearest` ({1})!'.format(file_msg, nnearest)
        raise LSSUtils_Error(msg)
    ##
    ## Calculating distance between matches
    ds = _great_circle_distance_fast(   ra1         ,
                                        dec1        ,
                                        ra2[idx_s2] ,
                                        dec2[idx_s2],
                                        nthreads    )
    ##
    ## If `tol` is None, then all objects will have a match.
    idx_s1 = np.arange(ra1.size)
    ##
    ## Remove matches that are `beyond` the tolerance separation
    if (tol is not None) and (nnearest != 0):
        mask   = ds < tol
        idx_s1 = idx_s1[mask]
        idx_s2 = idx_s2[mask]
        ds     = ds    [mask]

    return idx_s1, idx_s2, ds
Example #15
0
def get_bcd_list(metadata):
    """
	Metadata is a dict with keys:
		name, radecfile, data_dir, out_dir, work_dir, aors, channel,
		bcd_dict_path, max_cov
	"""

    radecfile = metadata['radecfile']
    work_dir = metadata['work_dir']
    aors = metadata['aors']
    max_cov = metadata['max_cov']

    # split the RA/Dec into two arrays
    radec = np.genfromtxt(radecfile)
    ra = radec[:, 0]
    dec = radec[:, 1]

    # read the region/ch/hdr specific bcd_dict in the work_dir for efficiency
    bcd_dict = json.load(open(metadata['bcd_dict_path']))
    filenames, filepaths = [np.array(i) for i in unzip(bcd_dict.items())]

    # extract center pixel coordinates
    files_ra = np.zeros(filepaths.size)
    files_dec = np.zeros(filepaths.size)
    for i, fp in enumerate(filepaths):
        hdr = pyfits.getheader(fp)
        files_ra[i] = hdr['CRVAL1']
        files_dec[i] = hdr['CRVAL2']

    # make array of coordinates and grow the tree
    kdt = KDT(radec_to_coords(files_ra, files_dec))

    # spawn processes using multiprocessing to check for images containing,
    # the source, using the tree to find only the closest BCDs to check
    ncpus = multiprocessing.cpu_count()
    pool = multiprocessing.Pool(processes=ncpus)
    # print "using %i CPUs" % ncpus

    max_num_images = 0
    sources = []
    for i in range(len(ra)):

        # create internal source ID and associate with each RA/Dec pair
        d = {'id': i, 'ra': ra[i], 'dec': dec[i]}
        message = 'finding files associated with source {} at ({}, {})'
        print(message.format(i, ra[i], dec[i]))

        # get the subset of BCDs to search
        idx = get_k_closest_bcd_idx(ra[i], dec[i], kdt, k=max_cov)
        n_files = filepaths[idx].size
        filepaths_subset = filepaths[idx]
        filenames_subset = filenames[idx]
        argslist = zip([ra[i]] * n_files, [dec[i]] * n_files, filepaths_subset)

        # send jobs to the pool
        results = pool.map(source_in_image, argslist)

        # unzip the results and extract the boolean array and pixel coordinates
        results_unzipped = unzip(results)
        bool_arr = np.array(results_unzipped[0])

        # if none found, continue to next source
        if np.sum(bool_arr) == 0:
            continue

        x = results_unzipped[1]
        y = results_unzipped[2]
        pix_coord = np.array(zip(x, y))[bool_arr].tolist()

        # get the names of the files associated with the source
        good_bcds = filenames_subset[bool_arr].tolist()

        # compare the number of associated images to the previous maximum
        num_images = len(good_bcds)
        print('\t{} images'.format(num_images))
        if num_images > max_num_images:
            max_num_images = num_images

        # store results in source dict and append to source list
        d['files'] = good_bcds
        d['pixels'] = pix_coord
        sources.append(d)

    outfile = 'bcd_list.json'
    outfilepath = '/'.join([work_dir, outfile])
    with open(outfilepath, 'w') as w:
        json.dump(sources, w, indent=4 * ' ')

    print('created file: {}'.format(outfilepath))
    message = 'maximum number of images associated with a source: {}'
    print(message.format(max_num_images))
Example #16
0
coordsP[:, 0] = x_psf
coordsP[:, 1] = y_psf
coordsP[:, 2] = z_psf

coordsF[:, 0] = x_flc
coordsF[:, 1] = y_flc
coordsF[:, 2] = z_flc

########################################################################

# kdt = KDT(coordsF)
# idxsF = kdt.query(coordsP)[1]
# ds = distArr(x_psf,y_psf,z_psf,x_flc[idxsF],y_flc[idxsF],z_flc[idxsF])

kdt = KDT(coordsP)
idxsP = kdt.query(coordsF)[1]

ds = distArr(x_flc, y_flc, z_flc, x_psf[idxsP], y_psf[idxsP], z_psf[idxsP])

# print(len(ds))

idxsF = np.arange(x_flc.size)

msk = ds < matchtol
idxsF = idxsF[msk]
idxsP = idxsP[msk]
ds = ds[msk]

# print(len(idxs1))
    filter = filters[ff]
    x_drc_low = low_x[ff]
    y_drc_low = low_y[ff]
    xm_flc_low = flc_all['xdrc_low_'+filter]
    ym_flc_low = flc_all['ydrc_low_'+filter]

    coords1low = np.empty((xm_flc_low.size,2))
    coords2low = np.empty((x_drc_low.size,2))

    coords1low[:,0] = xm_flc_low
    coords1low[:,1] = ym_flc_low

    coords2low[:,0] = x_drc_low
    coords2low[:,1] = y_drc_low

    kdt = KDT(coords2low)
    idxs2 = kdt.query(coords1low)[1]

    ds = distArr(xm_flc_low,ym_flc_low,x_drc_low[idxs2],y_drc_low[idxs2])

    idxs1 = np.arange(xm_flc_low.size)

    msk = ds < matchtol
    idxs1 = idxs1[msk]
    idxs2 = idxs2[msk]
    ds = ds[msk]

    outfile = outDir+'hor-I-cut_drc_low_'+filter+'_tol1.txt'
    np.savetxt(outfile, idxs2, fmt='%4i')

    outfile = outDir+'hor-I-cut_flc_low_'+filter+'_tol1.txt'
Example #18
0
def xymatch(x1, y1, x2, y2, tol=None, nnearest=1):
    """
    Finds matches in one catalog to another.

    Parameters
    x1 : array-like
        X-coordinates of first catalog
    y1 : array-like
        Y-coordinates of first catalog
    x2 : array-like
        X-coordinates of second catalog
    y2 : array-like
        Y-coordinates of second catalog
    tol : float or None, optional
        How close a match has to be to count as a match.  If None,
        all nearest neighbors for the first catalog will be returned.
    nnearest : int, optional
        The nth neighbor to find.  E.g., 1 for the nearest nearby, 2 for the
        second nearest neighbor, etc.  Particularly useful if you want to get
        the nearest *non-self* neighbor of a catalog.  To do this, use:
        ``spherematch(x, y, x, y, nnearest=2)``

    Returns
    -------
    idx1 : int array
        Indecies into the first catalog of the matches. Will never be
        larger than `x1`/`y1`.
    idx2 : int array
        Indecies into the second catalog of the matches. Will never be
        larger than `x1`/`y1`.
    ds : float array
        Distance between the matches

    """

    x1 = np.array(x1, copy=False)
    y1 = np.array(y1, copy=False)
    x2 = np.array(x2, copy=False)
    y2 = np.array(y2, copy=False)

    if x1.shape != y1.shape:
        raise ValueError('x1 and y1 do not match!')
    if x2.shape != y2.shape:
        raise ValueError('x2 and y2 do not match!')

    # this is equivalent to, but faster than just doing np.array([x1, y1])
    coords1 = np.empty((x1.size, 2))
    coords1[:, 0] = x1
    coords1[:, 1] = y1

    # this is equivalent to, but faster than just doing np.array([x2, y2])
    coords2 = np.empty((x2.size, 2))
    coords2[:, 0] = x2
    coords2[:, 1] = y2

    kdt = KDT(coords2)
    if nnearest == 1:
        ds,idxs2 = kdt.query(coords1)
    elif nnearest > 1:
        retval = kdt.query(coords1, nnearest)
        ds = retval[0]
        idxs2 = retval[1][:, -1]
    else:
        raise ValueError('invalid nnearest ' + str(nnearest))

    idxs1 = np.arange(x1.size)

    if tol is not None:
        msk = ds < tol
        idxs1 = idxs1[msk]
        idxs2 = idxs2[msk]
        ds = ds[msk]

    return idxs1, idxs2, ds
Example #19
0
    def crossmatch_gaia(self, plate_solution=None, star_catalog=None):
        """
        Crossmatch sources with Gaia objects, considering multiple solutions.

        Parameters:
        -----------
        plate_solution : :class:`solve.PlateSolution`
            Plate solution with one or more astrometric solutions
        star_catalog : :class:`catalog.StarCatalog`
            External star catalog with Gaia data

        """

        from .solve import PlateSolution
        from .catalog import StarCatalog

        self.log.write('Crossmatching sources with Gaia objects',
                       level=3, event=44)

        if plate_solution is None or plate_solution.num_solutions == 0:
            self.log.write('Cannot crossmatch sources with Gaia objects '
                           'due to missing astrometric solutions!',
                           level=2, event=44)
            return

        if star_catalog is None:
            self.log.write('Cannot crossmatch sources with Gaia objects '
                           'due to missing Gaia catalog data!',
                           level=2, event=44)
            return

        assert isinstance(plate_solution, PlateSolution)
        assert isinstance(star_catalog, StarCatalog)

        # Take parameters from plate_solution
        num_solutions = plate_solution.num_solutions
        solutions = plate_solution.solutions
        mean_pixscale = plate_solution.mean_pixel_scale

        # Number of Gaia stars
        num_gaia = len(star_catalog)

        self.log.write('Number of Gaia stars: {:d}'.format(num_gaia), 
                       level=4, event=44, double_newline=False)

        # Calculate RA and Dec for the plate epoch
        ra_ref = (star_catalog['ra']
                  + (self.plate_epoch - star_catalog['ref_epoch'])
                  * star_catalog['pmra']
                  / np.cos(star_catalog['dec'] * np.pi / 180.) / 3600000.)
        dec_ref = (star_catalog['dec']
                   + (self.plate_epoch - star_catalog['ref_epoch'])
                   * star_catalog['pmdec'] / 3600000.)
        #catalog = SkyCoord(ra_ref, dec_ref, frame='icrs')
        xy_ref = np.empty((0, 2))
        sol_ref = np.empty((0,), dtype=np.int8)
        index_ref = np.empty((0,), dtype=np.int32)

        # Build a list of Gaia stars in image coordinates
        for i in np.arange(plate_solution.num_solutions):
            solution = solutions[i]

            # If there is a column named 'solution_num', then take only
            # reference stars with the current solution number
            if 'solution_num' in star_catalog.columns:
                mask_sol = star_catalog['solution_num'] == i + 1
            else:
                mask_sol = np.full(num_gaia, True)

            w = wcs.WCS(solution['header_wcs'])

            try:
                xr,yr = w.all_world2pix(ra_ref[mask_sol], dec_ref[mask_sol], 1)
            except wcs.NoConvergence as e:
                self.log.write('Failed to convert sky coordinates to '
                               'pixel coordinates for solution {:d}: {}'
                               .format(i + 1, e))
                continue

            mask_inside = ((xr > 0.5) & (xr < plate_solution.imwidth) &
                           (yr > 0.5) & (yr < plate_solution.imheight))
            num_inside = mask_inside.sum()
            xyr = np.vstack((xr[mask_inside], yr[mask_inside])).T
            xy_ref = np.vstack((xy_ref, xyr))
            sol_ref = np.hstack((sol_ref, np.full(num_inside, i + 1)))
            index_ref = np.hstack((index_ref,
                                   np.arange(num_gaia)[mask_sol][mask_inside]))

        # Calculate mean astrometric error
        sigma1 = u.Quantity([sol['scamp_sigma_1'] for sol in solutions
                             if sol['scamp_sigma_1'] is not None])
        sigma2 = u.Quantity([sol['scamp_sigma_2'] for sol in solutions
                             if sol['scamp_sigma_2'] is not None])

        if len(sigma1) > 0 and len(sigma2) > 0:
            mean_scamp_sigma = np.sqrt(sigma1.mean()**2 + sigma2.mean()**2)
        else:
            mean_scamp_sigma = 2. * u.arcsec

        # Crossmatch sources and Gaia stars
        coords_plate = np.vstack((self['x_source'], self['y_source'])).T
        tolerance = ((5. * mean_scamp_sigma / mean_pixscale)
                     .to(u.pixel).value)

        #if (5. * mean_scamp_sigma) < 2 * u.arcsec:
        #    tolerance = ((2 * u.arcsec / mean_pixscale)
        #                 .to(u.pixel).value)

        tolerance_arcsec = (5. * mean_scamp_sigma).to(u.arcsec).value
        self.log.write('Crossmatch tolerance: {:.2f} arcsec ({:.2f} pixels)'
                       .format(tolerance_arcsec, tolerance), level=4, event=44,
                       double_newline=False)

        ind_plate, ind_ref, ds = crossmatch_cartesian(coords_plate, xy_ref, 
                                                      tolerance=tolerance)
        dist_arcsec = (ds * u.pixel * mean_pixscale).to(u.arcsec).value
        ind_gaia = index_ref[ind_ref]
        self['solution_num'][ind_plate] = sol_ref[ind_ref]
        self['match_radius'][ind_plate] = tolerance_arcsec
        self['gaiaedr3_id'][ind_plate] = star_catalog['source_id'][ind_gaia]
        self['gaiaedr3_gmag'][ind_plate] = star_catalog['mag'][ind_gaia]
        self['gaiaedr3_bpmag'][ind_plate] = star_catalog['mag1'][ind_gaia]
        self['gaiaedr3_rpmag'][ind_plate] = star_catalog['mag2'][ind_gaia]
        self['gaiaedr3_bp_rp'][ind_plate] = star_catalog['color_index'][ind_gaia]
        self['gaiaedr3_dist'][ind_plate] = dist_arcsec
        self.num_crossmatch_gaia = len(ind_plate)

        # Mask nan values in listed columns
        for col in ['gaiaedr3_gmag', 'gaiaedr3_bpmag', 'gaiaedr3_rpmag',
                    'gaiaedr3_bp_rp', 'gaiaedr3_dist']:
            self[col] = MaskedColumn(self[col], mask=np.isnan(self[col]))

        # Mask zeros in the ID column
        col = 'gaiaedr3_id'
        self[col] = MaskedColumn(self[col], mask=(self[col] == 0))

        # Store number of crossmatched sources to each solution
        grp = self.group_by('solution_num').groups
        tab_grp = Table(grp.aggregate(len)['solution_num', 'source_num'])
        tab_grp.rename_column('source_num', 'num_gaia_edr3')

        for i in np.arange(plate_solution.num_solutions):
            solution = solutions[i]
            m = tab_grp['solution_num'] == i + 1

            if m.sum() > 0:
                num_gaia_edr3 = tab_grp['num_gaia_edr3'][m].data[0]
                solution['num_gaia_edr3'] = num_gaia_edr3
            else:
                solution['num_gaia_edr3'] = 0

        # Crossmatch: find all neighbours for sources
        kdt_ref = KDT(xy_ref)
        kdt_plate = KDT(coords_plate)
        max_distance = ((20. * mean_scamp_sigma / mean_pixscale)
                        .to(u.pixel).value)

        if (20. * mean_scamp_sigma) < 5 * u.arcsec:
            max_distance = (5 * u.arcsec / mean_pixscale).to(u.pixel).value

        max_dist_arcsec = (max_distance * u.pixel * mean_pixscale).to(u.arcsec).value
        self.log.write('Finding all reference stars around sources within '
                       'the radius of {:.2f} arcsec ({:.2f} pixels)'
                       .format(max_dist_arcsec, max_distance),
                       level=4, event=44)

        mtrx = kdt_plate.sparse_distance_matrix(kdt_ref, max_distance)
        mtrx_keys = np.array([a for a in mtrx.keys()])

        # Check if there are neighbors at all
        if len(mtrx_keys) > 0:
            k_plate = mtrx_keys[:,0]
            k_ref = mtrx_keys[:,1]
            dist = np.fromiter(mtrx.values(), dtype=float) * u.pixel

            # Construct neighbors table
            nbs = Table()
            nbs['source_num'] = self['source_num'][k_plate]
            nbs['gaiaedr3_id'] = star_catalog['source_id'][index_ref[k_ref]]
            nbs['dist'] = dist
            nbs['solution_num'] = sol_ref[k_ref]
            nbs['x_gaia'] = xy_ref[k_ref,0]
            nbs['y_gaia'] = xy_ref[k_ref,1]

            # Create the flag_xmatch column by joining the neighbors table
            # with the source table
            tab = Table()
            tab['source_num'] = self['source_num']
            tab['gaiaedr3_id'] = MaskedColumn(self['gaiaedr3_id']).filled(0)
            tab['flag_xmatch'] = np.int8(1)
            jtab = join(nbs, tab, keys=('source_num', 'gaiaedr3_id'),
                        join_type='left')
            jtab['flag_xmatch'] = MaskedColumn(jtab['flag_xmatch']).filled(0)
            self.neighbors_gaia = jtab

            # Calculate neighbor counts
            source_num, cnt = np.unique(nbs['source_num'].data, return_counts=True)
            mask = np.isin(self['source_num'], source_num)
            ind_mask = np.where(mask)[0]
            self['gaiaedr3_neighbors'][ind_mask] = cnt
        else:
            # Create empty neighbors table
            nbs = Table(names=('source_num', 'gaiaedr3_id', 'dist',
                               'solution_num', 'x_gaia', 'y_gaia',
                               'flag_xmatch'),
                        dtype=('i4', 'i8', 'f4', 'i2', 'f8', 'f8', 'i1'))
            self.neighbors_gaia = nbs

        # Process coordinates again, because solution_num assignments may have changed
        self.process_coordinates(plate_solution=plate_solution)
Example #20
0
def runPixMatch(outpre, filter):

    if filter == 'f606w':
        let = 'v'
    else:
        let = 'i'

    if outpre == 'lower':
        x_drc_low = drc_low['x_' + let]
        y_drc_low = drc_low['y_' + let]

        xm_flc_low = flc_all['xdrc_low_' + filter]
        ym_flc_low = flc_all['ydrc_low_' + filter]

        coords1low = np.empty((xm_flc_low.size, 2))
        coords2low = np.empty((x_drc_low.size, 2))

        coords1low[:, 0] = xm_flc_low
        coords1low[:, 1] = ym_flc_low

        coords2low[:, 0] = x_drc_low
        coords2low[:, 1] = y_drc_low

        kdt = KDT(coords2low)
        idxs2 = kdt.query(coords1low)[1]

        ds = distArr(xm_flc_low, ym_flc_low, x_drc_low[idxs2],
                     y_drc_low[idxs2])

        idxs1 = np.arange(xm_flc_low.size)

        msk = ds < matchtol
        idxs1 = idxs1[msk]
        idxs2 = idxs2[msk]
        ds = ds[msk]

    else:
        x_drc_up = drc_up['x_' + let]
        y_drc_up = drc_up['y_' + let]

        xm_flc_up = flc_all['xdrc_up_' + filter]
        ym_flc_up = flc_all['ydrc_up_' + filter]

        coords1up = np.empty((xm_flc_up.size, 2))
        coords2up = np.empty((x_drc_up.size, 2))

        coords1up[:, 0] = xm_flc_up
        coords1up[:, 1] = ym_flc_up

        coords2up[:, 0] = x_drc_up
        coords2up[:, 1] = y_drc_up

        kdt = KDT(coords2up)
        idxs2 = kdt.query(coords1up)[1]

        ds = distArr(xm_flc_up, ym_flc_up, x_drc_up[idxs2], y_drc_up[idxs2])

        idxs1 = np.arange(xm_flc_up.size)

        msk = ds < matchtol
        idxs1 = idxs1[msk]
        idxs2 = idxs2[msk]
        ds = ds[msk]

    print(len(idxs1))

    outfile = main_dir + 'hor-I-cut_drc_' + outpre + '_' + filter + '_tol{0}_magCuts.txt'.format(
        matchtol)
    np.savetxt(outfile, idxs2, fmt='%4i')

    outfile = main_dir + 'hor-I-cut_flc_' + outpre + '_' + filter + '_tol{0}_magCuts.txt'.format(
        matchtol)
    np.savetxt(outfile, idxs1, fmt='%4i')

    # outfile = main_dir+'hor-I-cut_ds_'+outpre+'_'+filter+'_tol{0}.txt'.format(matchtol)
    # np.savetxt(outfile, ds, fmt='%1.4f')

    return None
Example #21
0
def spherematch(ra1, dec1, ra2, dec2, tol=None, nnearest=1, threads=1):
    """
    Determines the matches between two catalogues of sources with ra,dec coordinates
 
    Parameters
    ra1 : array-like
        Right Ascension in degrees of the first catalog
    dec1 : array-like
        Declination in degrees of the first catalog (shape of array must match `ra1`)
    ra2 : array-like
        Right Ascension in degrees of the second catalog
    dec2 : array-like
        Declination in degrees of the second catalog (shape of array must match `ra2`)
    tol : float or None, optional
        How close (in degrees) a match has to be to count as a match.  If None,
        all nearest neighbors for the first catalog will be returned.
    nnearest : int, optional
        The nth neighbor to find.  E.g., 1 for the nearest nearby, 2 for the
        second nearest neighbor, etc.  Particularly useful if you want to get
        the nearest *non-self* neighbor of a catalog.  To do this, use:
        ``spherematch(ra, dec, ra, dec, nnearest=2)``
        if nnearest==0, all matches are returned
 
    Returns
    idx1 : int array
        Indecies into the first catalog of the matches. Will never be
        larger than `ra1`/`dec1`.
    idx2 : int array
        Indecies into the second catalog of the matches. Will never be
        larger than `ra1`/`dec1`.
    ds : float array
        Distance (in degrees) between the matches
    """

    #convert arguments into arrays for ease of use
    ra1 = np.array(ra1, copy=False)
    dec1 = np.array(dec1, copy=False)
    ra2 = np.array(ra2, copy=False)
    dec2 = np.array(dec2, copy=False)

    #check to see if arguments are consistent
    if ra1.shape != dec1.shape:
        raise ValueError('ra1 and dec1 do not match!')
    if ra2.shape != dec2.shape:
        raise ValueError('ra2 and dec2 do not match!')

    #convert spherical coordinates into cartesian coordinates
    x1, y1, z1 = _spherical_to_cartesian_fast(ra1.ravel(), dec1.ravel(),
                                              threads)

    # this is equivalent to, but faster than just doing np.array([x1, y1, z1])
    coords1 = np.empty((x1.size, 3))
    coords1[:, 0] = x1
    coords1[:, 1] = y1
    coords1[:, 2] = z1

    #convert spherical coordinates into cartesian coordinates
    x2, y2, z2 = _spherical_to_cartesian_fast(ra2.ravel(), dec2.ravel(),
                                              threads)

    # this is equivalent to, but faster than just doing np.array([x1, y1, z1])
    coords2 = np.empty((x2.size, 3))
    coords2[:, 0] = x2
    coords2[:, 1] = y2
    coords2[:, 2] = z2

    #create tree structure
    kdt = KDT(coords2)
    #find neighbors
    if nnearest == 1:
        idxs2 = kdt.query(coords1)[1]
    elif nnearest == 0 and (tol is not None):  #if you want all matches
        p1x, p1y, p1z = _spherical_to_cartesian_fast(90, 0, threads)
        p2x, p2y, p2z = _spherical_to_cartesian_fast(90, tol, threads)
        p1x = float(p1x)
        p2x = float(p2x)
        p1y = float(p1y)
        p2y = float(p2y)
        p1z = float(p1z)
        p2z = float(p2z)
        r = np.sqrt(
            (p2x - p1x)**2 + (p2y - p1y)**2 + (p2z - p1z)**2)  #cartesian tol
        idxs2 = kdt.query_ball_point(coords1, r)[0]
    elif nnearest > 1:
        idxs2 = kdt.query(coords1, nnearest)[1][:, -1]
    else:
        raise ValueError('invalid nnearest ' + str(nnearest))

    #calculate distances between matches
    ds = _great_circle_distance_fast(ra1, dec1, ra2[idxs2], dec2[idxs2],
                                     threads)

    #if tolerance is None, then all objects will have a match
    idxs1 = np.arange(ra1.size)

    #remove matches that are beyond the tolerance seperation
    if (tol is not None) and nnearest != 0:
        msk = ds < tol
        idxs1 = idxs1[msk]
        idxs2 = idxs2[msk]
        ds = ds[msk]

    return idxs1, idxs2, ds
Example #22
0
def spherematch(ra1, dec1, ra2, dec2, tol=None, nnearest=1):
    """
    Finds matches in one catalog to another.

    Parameters
    ra1 : array-like
        Right Ascension in degrees of the first catalog
    dec1 : array-like
        Declination in degrees of the first catalog (shape of array must match `ra1`)
    ra2 : array-like
        Right Ascension in degrees of the second catalog
    dec2 : array-like
        Declination in degrees of the second catalog (shape of array must match `ra2`)
    tol : float or None, optional
        How close (in degrees) a match has to be to count as a match.  If None,
        all nearest neighbors for the first catalog will be returned.
    nnearest : int, optional
        The nth neighbor to find.  E.g., 1 for the nearest nearby, 2 for the
        second nearest neighbor, etc.  Particularly useful if you want to get
        the nearest *non-self* neighbor of a catalog.  To do this, use:
        ``spherematch(ra, dec, ra, dec, nnearest=2)``

    Returns
    -------
    idx1 : int array
        Indecies into the first catalog of the matches. Will never be
        larger than `ra1`/`dec1`.
    idx2 : int array
        Indecies into the second catalog of the matches. Will never be
        larger than `ra1`/`dec1`.
    ds : float array
        Distance (in degrees) between the matches



    """

    ra1 = np.array(ra1, copy=False)
    dec1 = np.array(dec1, copy=False)
    ra2 = np.array(ra2, copy=False)
    dec2 = np.array(dec2, copy=False)

    if ra1.shape != dec1.shape:
        raise ValueError('ra1 and dec1 do not match!')
    if ra2.shape != dec2.shape:
        raise ValueError('ra2 and dec2 do not match!')

    x1, y1, z1 = _spherical_to_cartesian(ra1.ravel(), dec1.ravel())

    # this is equivalent to, but faster than just doing np.array([x1, y1, z1])
    coords1 = np.empty((x1.size, 3))
    coords1[:, 0] = x1
    coords1[:, 1] = y1
    coords1[:, 2] = z1

    x2, y2, z2 = _spherical_to_cartesian(ra2.ravel(), dec2.ravel())

    # this is equivalent to, but faster than just doing np.array([x1, y1, z1])
    coords2 = np.empty((x2.size, 3))
    coords2[:, 0] = x2
    coords2[:, 1] = y2
    coords2[:, 2] = z2

    kdt = KDT(coords2)
    if nnearest == 1:
        idxs2 = kdt.query(coords1)[1]
    elif nnearest > 1:
        idxs2 = kdt.query(coords1, nnearest)[1][:, -1]
    else:
        raise ValueError('invalid nnearest ' + str(nnearest))

    ds = _great_circle_distance(ra1, dec1, ra2[idxs2], dec2[idxs2])

    idxs1 = np.arange(ra1.size)

    if tol is not None:
        msk = ds < tol
        idxs1 = idxs1[msk]
        idxs2 = idxs2[msk]
        ds = ds[msk]

    return idxs1, idxs2, ds
Example #23
0
def spherematch(ra1, dec1, ra2, dec2, logger, tol=None, nnearest=1):
    """
    Finds matches in one catalog to another.
 
    Parameters
    ra1 : array-like
        Right Ascension in degrees of the first catalog
    dec1 : array-like
        Declination in degrees of the first catalog (shape of array must match `ra1`)
    ra2 : array-like
        Right Ascension in degrees of the second catalog
    dec2 : array-like
        Declination in degrees of the second catalog (shape of array must match `ra2`)
    tol : float or None, optional
        How close (in degrees) a match has to be to count as a match.  If None,
        all nearest neighbors for the first catalog will be returned.
    nnearest : int, optional
        The nth neighbor to find.  E.g., 1 for the nearest nearby, 2 for the
        second nearest neighbor, etc.  Particularly useful if you want to get
        the nearest *non-self* neighbor of a catalog.  To do this, use:
        ``spherematch(ra, dec, ra, dec, nnearest=2)``
 
    Returns
    -------
    idx1 : int array
        Indecies into the first catalog of the matches. Will never be
        larger than `ra1`/`dec1`.
    idx2 : int array
        Indecies into the second catalog of the matches. Will never be
        larger than `ra1`/`dec1`.
    ds : float array
        Distance (in degrees) between the matches
    """

    ra1 = np.array(ra1, copy=False)
    dec1 = np.array(dec1, copy=False)
    ra2 = np.array(ra2, copy=False)
    dec2 = np.array(dec2, copy=False)

    if ra1.shape != dec1.shape:
        raise ValueError('ra1 and dec1 do not match!')
    if ra2.shape != dec2.shape:
        raise ValueError('ra2 and dec2 do not match!')

    x1, y1, z1 = _spherical_to_cartesian(ra1.ravel(), dec1.ravel())

    # this is equivalent to, but faster than just doing np.array([x1, y1, z1])
    coords1 = np.empty((x1.size, 3))
    coords1[:, 0] = x1
    coords1[:, 1] = y1
    coords1[:, 2] = z1

    x2, y2, z2 = _spherical_to_cartesian(ra2.ravel(), dec2.ravel())

    # this is equivalent to, but faster than just doing np.array([x1, y1, z1])
    coords2 = np.empty((x2.size, 3))
    coords2[:, 0] = x2
    coords2[:, 1] = y2
    coords2[:, 2] = z2

    kdt = KDT(coords2)
    if nnearest == 1:
        idxs2 = kdt.query(coords1)[1]
    elif nnearest > 1:
        idxs2 = kdt.query(coords1, nnearest)[1][:, -1]
    else:
        raise ValueError('invalid nnearest ' + str(nnearest))

    ds = _great_circle_distance(ra1, dec1, ra2[idxs2], dec2[idxs2])

    idxs1 = np.arange(ra1.size)

    if tol is not None:
        msk = ds < tol
        idxs1 = idxs1[msk]
        idxs2 = idxs2[msk]
        ds = ds[msk]

        # The following removes duplicates, but with no distinction of merit
        '''c = len(idxs1)
        idxs2, idxs2_unique_indexes = np.unique(idxs2, return_index=True)
        idxs1 = idxs1[idxs2_unique_indexes]
        logger.info("(pipeline._XMatchSources.spherematch) Found " + str(c - len(idxs1)) + " duplicate(s) in spherematch")'''

        # The following removes duplicates, only preserving the nearest match
        c = len(idxs1)
        for i in Counter(idxs2).most_common(
        ):  # returns ([idx_that_is_the_duplicate, count), ..])
            if i[1] < 2:  # no more duplicates here
                break
            else:
                duplicate_idxs = np.where(idxs2 == i[0])[
                    0]  # what are the indexes of the duplicate entry in idxs2
                duplicate_idxs_dist = ds[
                    duplicate_idxs]  # find the corresponding distances
                duplicate_idx_min = np.argmin(
                    duplicate_idxs_dist
                )  # find the index of the minimum of the above
                keep = duplicate_idxs[
                    duplicate_idx_min]  # this the index in duplicate_idxs to be retained
                for d in duplicate_idxs:  # delete all but "keep" index
                    if d == keep:
                        continue
                    else:
                        idxs1 = np.delete(idxs1, d)
                        idxs2 = np.delete(idxs2, d)
                        ds = np.delete(ds, d)
        logger.info("(pipeline._XMatchSources.spherematch) Found " +
                    str(c - len(idxs1)) + " duplicate(s) in spherematch")

    return idxs1, idxs2, ds