def __call__(self, ra, dec, spherematch=True, radius=0, contains=False): T = self.tab # HACK - magic 13x9 +1 arcmin. if radius == 0: radius = sqrt(14.**2 + 10.**2) / 2. d2 = arcmin2distsq(radius) if self.sdssxyz is None: self.sdssxyz = radectoxyz(T.ra, T.dec) if not spherematch: rcfs = [] for r, d in broadcast(ra, dec): xyz = radectoxyz(r, d) dist2s = sum((xyz - self.sdssxyz)**2, axis=1) I = flatnonzero(dist2s < d2) rcfs.append( zip(T[I].run, T[I].camcol, T[I].field, T[I].ra, T[I].dec)) else: from astrometry.libkd import spherematch from astrometry.libkd import spherematch_c if self.kd is None: self.kd = spherematch_c.kdtree_build(self.sdssxyz) rds = array([x for x in broadcast(ra, dec)]) xyz = radectoxyz(rds[:, 0], rds[:, 1]).astype(double) kd2 = spherematch_c.kdtree_build(xyz) notself = False inds, D = spherematch_c.match(self.kd, kd2, np.sqrt(d2), notself, True) if len(inds) == 0: return [] spherematch_c.kdtree_free(kd2) I = np.argsort(D[:, 0]) inds = inds[I] rcfs = [[] for i in range(len(rds))] cols = T.columns() gotem = False if contains: if ('ramin' in cols and 'ramax' in cols and 'decmin' in cols and 'decmax' in cols): gotem = True for j, i in inds: (r, d) = rds[i] if (r >= T.ramin[j] and r <= T.ramax[j] and d >= T.decmin[j] and d <= T.decmax[j]): rcfs[i].append((T.run[j], T.camcol[j], T.field[j], T.ra[j], T.dec[j])) #print '%i fields contain the first query RA,Dec' % len(rcfs[0]) else: print 'you requested fields *containing* the query RA,Dec,' print 'but the fields list file \"%s\" doesn\'t contain RAMIN,RAMAX,DECMIN, and DECMAX columns' % tablefn if not gotem: for j, i in inds: rcfs[i].append( (T.run[j], T.camcol[j], T.field[j], T.ra[j], T.dec[j])) if isscalar(ra) and isscalar(dec): return rcfs[0] return rcfs
def __call__(self, ra, dec, spherematch=True, radius=0, contains=False): T = self.tab # HACK - magic 13x9 arcmin. if radius == 0: radius = sqrt(13.**2 + 9.**2)/2. d2 = arcmin2distsq(radius) if self.sdssxyz is None: self.sdssxyz = radectoxyz(T.ra, T.dec) if not spherematch: rcfs = [] for r,d in broadcast(ra,dec): xyz = radectoxyz(r,d) dist2s = sum((xyz - self.sdssxyz)**2, axis=1) I = flatnonzero(dist2s < d2) rcfs.append(zip(T[I].run, T[I].camcol, T[I].field, T[I].ra, T[I].dec)) else: from astrometry.libkd import spherematch from astrometry.libkd import spherematch_c if self.kd is None: self.kd = spherematch_c.kdtree_build(self.sdssxyz) rds = array([x for x in broadcast(ra,dec)]) xyz = radectoxyz(rds[:,0], rds[:,1]).astype(double) kd2 = spherematch_c.kdtree_build(xyz) notself = False inds,D = spherematch_c.match(self.kd, kd2, np.sqrt(d2), notself) if len(inds) == 0: return [] spherematch_c.kdtree_free(kd2) I = np.argsort(D[:,0]) inds = inds[I] rcfs = [[] for i in range(len(rds))] cols = T.columns() gotem = False if contains: if ('ramin' in cols and 'ramax' in cols and 'decmin' in cols and 'decmax' in cols): gotem = True for j,i in inds: (r,d) = rds[i] if (r >= T.ramin[j] and r <= T.ramax[j] and d >= T.decmin[j] and d <= T.decmax[j]): rcfs[i].append((T.run[j], T.camcol[j], T.field[j], T.ra[j], T.dec[j])) #print '%i fields contain the first query RA,Dec' % len(rcfs[0]) else: print 'you requested fields *containing* the query RA,Dec,' print 'but the fields list file \"%s\" doesn\'t contain RAMIN,RAMAX,DECMIN, and DECMAX columns' % tablefn if not gotem: for j,i in inds: rcfs[i].append((T.run[j], T.camcol[j], T.field[j], T.ra[j], T.dec[j])) if isscalar(ra) and isscalar(dec): return rcfs[0] return rcfs
def trees_match(kd1, kd2, radius, nearest=False, notself=False, permuted=True, count=False): ''' Runs rangesearch or nearest-neighbour matching on given kdtrees. 'radius' is Euclidean distance. If 'nearest'=True, returns the nearest neighbour of each point in "kd1"; ie, "I" will NOT contain duplicates, but "J" may. If 'count'=True, also counts the number of objects within range as well as returning the nearest neighbor of each point in "kd1"; the return value becomes I,J,d,counts , counts a numpy array of ints. Returns (I, J, d), where I are indices into kd1 J are indices into kd2 d are distances-squared [counts is number of sources in range] >>> import numpy as np >>> X = np.array([[1, 2, 3, 6]]).T.astype(float) >>> Y = np.array([[1, 4, 4]]).T.astype(float) >>> kd1 = tree_build(X) >>> kd2 = tree_build(Y) >>> I,J,d = trees_match(kd1, kd2, 1.1, nearest=True) >>> print I [0 1 2] >>> print J [0 0 2] >>> print d [ 0. 60. 60.] >>> I,J,d,count = trees_match(kd1, kd2, 1.1, nearest=True, count=True) >>> print I [0 1 2] >>> print J [0 0 2] >>> print d [ 0. 60. 60.] >>> print count [1 1 2] ''' rtn = None if nearest: rtn = spherematch_c.nearest2(kd2, kd1, radius, notself, count) # J,I,d,[count] rtn = (rtn[1], rtn[0], np.sqrt(rtn[2])) + rtn[3:] #distsq2deg(rtn[2]), else: (inds,dists) = spherematch_c.match(kd1, kd2, radius, notself, permuted) #d = dist2deg(dists[:,0]) d = dists[:,0] I,J = inds[:,0], inds[:,1] rtn = (I,J,d) return rtn
def trees_match(kd1, kd2, radius, nearest=False, notself=False, permuted=True): ''' Runs rangesearch or nearest-neighbour matching on given kdtrees. 'radius' is Euclidean distance. If nearest=True, returns the nearest neighbour of each point in "kd1"; ie, "I" will NOT contain duplicates, but "J" may. Returns (I, J, d), where I are indices into kd1 J are indices into kd2 d are distances-squared >>> import numpy as np >>> X = np.array([[1, 2, 3, 6]]).T.astype(float) >>> Y = np.array([[1, 4, 4]]).T.astype(float) >>> kd1 = tree_build(X) >>> kd2 = tree_build(Y) >>> I,J,d = trees_match(kd1, kd2, 1.1, nearest=True) >>> print I [0 1 2] >>> print J [0 0 2] >>> print d [ 0. 60. 60.] ''' if nearest: J,I,d = spherematch_c.nearest2(kd2, kd1, radius, notself) d = distsq2deg(d) else: (inds,dists) = spherematch_c.match(kd1, kd2, radius, notself, permuted) d = dist2deg(dists[:,0]) I,J = inds[:,0], inds[:,1] return I,J,d
def match(x1, x2, radius, notself=False): ''' (indices,dists) = match(x1, x2, radius): Given an N1 x D1 array x1, and an N2 x D2 array x2, and radius: Returns the indices (Nx2 int array) and distances (Nx1 float array) between points in "x1" and "x2" that are within "radius" Euclidean distance of each other. "x1" is N1xD and "x2" is N2xD. "x1" and "x2" can be the same array. Dimensions D above 5-10 will probably not run faster than naive. Despite the name of this package, the arrays x1 and x2 need not be celestial positions; in particular, there is no RA wrapping at 0, and no special handling at the poles. If you want to match celestial coordinates like RA,Dec, see the match_radec function. The "indices" return value has a row for each match; the matched points are: x1[indices[:,0],:] and x2[indices[:,1],:] This function doesn\'t know about spherical coordinates -- it just searches for matches in n-dimensional space. >>> from astrometry.util.starutil_numpy import * >>> from astrometry.libkd import spherematch # RA,Dec in degrees >>> ra1 = array([ 0, 1, 2, 3, 4, 359,360]) >>> dec1 = array([-90,-89,-1, 0, 1, 89, 90]) # xyz: N x 3 array: unit vectors >>> xyz1 = radectoxyz(ra1, dec1) >>> ra2 = array([ 45, 1, 4, 4, 4, 0, 1]) >>> dec2 = array([-89, -88, -1, 0, 2, 89, 89]) >>> xyz2 = radectoxyz(ra2, dec2) # The \'radius\' is now distance between points on the unit sphere -- # for small angles, this is ~ angular distance in radians. You can use # the function: >>> radius_in_deg = 2. >>> r = sqrt(deg2distsq(radius_in_deg)) >>> (inds,dists) = spherematch.match(xyz1, xyz2, r) # Now "inds" is an Mx2 array of the matching indices, # and "dists" the distances between them: # eg, sqrt(sum((xyz1[inds[:,0],:] - xyz2[inds[:,1],:])**2, axis=1)) = dists >>> print inds [[0 0] [1 0] [1 1] [2 2] [3 2] [3 3] [4 3] [4 4] [5 5] [6 5] [5 6] [6 6]] >>> print sqrt(sum((xyz1[inds[:,0],:] - xyz2[inds[:,1],:])**2, axis=1)) [ 0.01745307 0.01307557 0.01745307 0.0348995 0.02468143 0.01745307 0.01745307 0.01745307 0.0003046 0.01745307 0.00060917 0.01745307] >>> print dists[:,0] [ 0.01745307 0.01307557 0.01745307 0.0348995 0.02468143 0.01745307 0.01745307 0.01745307 0.0003046 0.01745307 0.00060917 0.01745307] >>> print vstack((ra1[inds[:,0]], dec1[inds[:,0]], ra2[inds[:,1]], dec2[inds[:,1]])).T [[ 0 -90 45 -89] [ 1 -89 45 -89] [ 1 -89 1 -88] [ 2 -1 4 -1] [ 3 0 4 -1] [ 3 0 4 0] [ 4 1 4 0] [ 4 1 4 2] [359 89 0 89] [360 90 0 89] [359 89 1 89] [360 90 1 89]] ''' (kd1,kd2) = _buildtrees(x1, x2) #print 'spherematch.match: notself=', notself (inds,dists) = spherematch_c.match(kd1, kd2, radius, notself) _freetrees(kd1, kd2) return (inds,dists)
def match(x1, x2, radius, notself=False, permuted=True, indexlist=False): ''' (indices,dists) = match(x1, x2, radius): Given an N1 x D1 array x1, and an N2 x D2 array x2, and radius: Returns the indices (Nx2 int array) and distances (Nx1 float array) between points in "x1" and "x2" that are within "radius" Euclidean distance of each other. "x1" is N1xD and "x2" is N2xD. "x1" and "x2" can be the same array. Dimensions D above 5-10 will probably not run faster than naive. Despite the name of this package, the arrays x1 and x2 need not be celestial positions; in particular, there is no RA wrapping at 0, and no special handling at the poles. If you want to match celestial coordinates like RA,Dec, see the match_radec function. The "indices" return value has a row for each match; the matched points are: x1[indices[:,0],:] and x2[indices[:,1],:] This function doesn\'t know about spherical coordinates -- it just searches for matches in n-dimensional space. >>> from astrometry.util.starutil_numpy import * >>> from astrometry.libkd import spherematch # RA,Dec in degrees >>> ra1 = array([ 0, 1, 2, 3, 4, 359,360]) >>> dec1 = array([-90,-89,-1, 0, 1, 89, 90]) # xyz: N x 3 array: unit vectors >>> xyz1 = radectoxyz(ra1, dec1) >>> ra2 = array([ 45, 1, 4, 4, 4, 0, 1]) >>> dec2 = array([-89, -88, -1, 0, 2, 89, 89]) >>> xyz2 = radectoxyz(ra2, dec2) # The \'radius\' is now distance between points on the unit sphere -- # for small angles, this is ~ angular distance in radians. You can use # the function: >>> radius_in_deg = 2. >>> r = sqrt(deg2distsq(radius_in_deg)) >>> (inds,dists) = spherematch.match(xyz1, xyz2, r) # Now "inds" is an Mx2 array of the matching indices, # and "dists" the distances between them: # eg, sqrt(sum((xyz1[inds[:,0],:] - xyz2[inds[:,1],:])**2, axis=1)) = dists >>> print inds [[0 0] [1 0] [1 1] [2 2] [3 2] [3 3] [4 3] [4 4] [5 5] [6 5] [5 6] [6 6]] >>> print sqrt(sum((xyz1[inds[:,0],:] - xyz2[inds[:,1],:])**2, axis=1)) [ 0.01745307 0.01307557 0.01745307 0.0348995 0.02468143 0.01745307 0.01745307 0.01745307 0.0003046 0.01745307 0.00060917 0.01745307] >>> print dists[:,0] [ 0.01745307 0.01307557 0.01745307 0.0348995 0.02468143 0.01745307 0.01745307 0.01745307 0.0003046 0.01745307 0.00060917 0.01745307] >>> print vstack((ra1[inds[:,0]], dec1[inds[:,0]], ra2[inds[:,1]], dec2[inds[:,1]])).T [[ 0 -90 45 -89] [ 1 -89 45 -89] [ 1 -89 1 -88] [ 2 -1 4 -1] [ 3 0 4 -1] [ 3 0 4 0] [ 4 1 4 0] [ 4 1 4 2] [359 89 0 89] [360 90 0 89] [359 89 1 89] [360 90 1 89]] ''' (kd1,kd2) = _buildtrees(x1, x2) if indexlist: inds = spherematch_c.match2(kd1, kd2, radius, notself, permuted) else: (inds,dists) = spherematch_c.match(kd1, kd2, radius, notself, permuted) _freetrees(kd1, kd2) if indexlist: return inds return (inds,dists)
def match(x1, x2, radius, notself=False, permuted=True, indexlist=False): ''' :: (indices,dists) = match(x1, x2, radius): Or:: inds = match(x1, x2, radius, indexlist=True): Returns the indices (Nx2 int array) and distances (Nx1 float array) between points in *x1* and *x2* that are within *radius* Euclidean distance of each other. *x1* is N1xD and *x2* is N2xD. *x1* and *x2* can be the same array. Dimensions D above 5-10 will probably not run faster than naive. Despite the name of this package, the arrays x1 and x2 need not be celestial positions; in particular, there is no RA wrapping at 0, and no special handling at the poles. If you want to match celestial coordinates like RA,Dec, see the match_radec function. If *indexlist* is True, the return value is a python list with one element per data point in the first tree; that element is a python list containing the indices of points matched in the second tree. The *indices* return value has a row for each match; the matched points are: x1[indices[:,0],:] and x2[indices[:,1],:] This function doesn\'t know about spherical coordinates -- it just searches for matches in n-dimensional space. >>> from astrometry.util.starutil_numpy import * >>> from astrometry.libkd import spherematch >>> # RA,Dec in degrees >>> ra1 = array([ 0, 1, 2, 3, 4, 359,360]) >>> dec1 = array([-90,-89,-1, 0, 1, 89, 90]) >>> # xyz: N x 3 array: unit vectors >>> xyz1 = radectoxyz(ra1, dec1) >>> ra2 = array([ 45, 1, 4, 4, 4, 0, 1]) >>> dec2 = array([-89, -88, -1, 0, 2, 89, 89]) >>> xyz2 = radectoxyz(ra2, dec2) >>> # The \'radius\' is now distance between points on the unit sphere -- >>> # for small angles, this is ~ angular distance in radians. You can use >>> # the function: >>> radius_in_deg = 2. >>> r = sqrt(deg2distsq(radius_in_deg)) >>> (inds,dists) = spherematch.match(xyz1, xyz2, r) >>> # Now *inds* is an Mx2 array of the matching indices, >>> # and *dists* the distances between them: >>> # eg, sqrt(sum((xyz1[inds[:,0],:] - xyz2[inds[:,1],:])**2, axis=1)) = dists >>> print inds [[0 0] [1 0] [1 1] [2 2] [3 2] [3 3] [4 3] [4 4] [5 5] [6 5] [5 6] [6 6]] >>> print sqrt(sum((xyz1[inds[:,0],:] - xyz2[inds[:,1],:])**2, axis=1)) [ 0.01745307 0.01307557 0.01745307 0.0348995 0.02468143 0.01745307 0.01745307 0.01745307 0.0003046 0.01745307 0.00060917 0.01745307] >>> print dists[:,0] [ 0.01745307 0.01307557 0.01745307 0.0348995 0.02468143 0.01745307 0.01745307 0.01745307 0.0003046 0.01745307 0.00060917 0.01745307] >>> print vstack((ra1[inds[:,0]], dec1[inds[:,0]], ra2[inds[:,1]], dec2[inds[:,1]])).T [[ 0 -90 45 -89] [ 1 -89 45 -89] [ 1 -89 1 -88] [ 2 -1 4 -1] [ 3 0 4 -1] [ 3 0 4 0] [ 4 1 4 0] [ 4 1 4 2] [359 89 0 89] [360 90 0 89] [359 89 1 89] [360 90 1 89]] Parameters ---------- x1 : numpy array, float, shape N1 x D First array of points to match x2 : numpy array, float, shape N2 x D Second array of points to match radius : float Scalar Euclidean distance to match Returns ------- indices : numpy array, integers, shape M x 2, for M matches The array of matching indices; *indices[:,0]* are indices in *x1*, *indices[:,1]* are indices in *x2*. dists : numpy array, floats, length M, for M matches The distances between matched points. If *indexlist* is *True*: indices : list of ints of integers The list of matching indices. One list element per *x1* element, containing a list of matching indices in *x2*. ''' (kd1,kd2) = _buildtrees(x1, x2) if indexlist: inds = spherematch_c.match2(kd1, kd2, radius, notself, permuted) else: (inds,dists) = spherematch_c.match(kd1, kd2, radius, notself, permuted) if indexlist: return inds return (inds,dists)