def read_targets_in_box(hpdirname, radecbox=[0., 360., -90., 90.], columns=None): """Read in targets in an RA/Dec box. Parameters ---------- hpdirname : :class:`str` Full path to either a directory containing targets that have been partitioned by HEALPixel (i.e. as made by `select_targets` with the `bundle_files` option). Or the name of a single file of targets. radecbox : :class:`list`, defaults to the entire sky 4-entry list of coordinates [ramin, ramax, decmin, decmax] forming the edges of a box in RA/Dec (degrees). columns : :class:`list`, optional Only read in these target columns. Returns ------- :class:`~numpy.ndarray` An array of targets in the passed RA/Dec box. """ # ADM we'll need RA/Dec for final cuts, so ensure they're read. addedcols = [] columnscopy = None if columns is not None: # ADM make a copy of columns, as it's a kwarg we'll modify. columnscopy = columns.copy() for radec in ["RA", "DEC"]: if radec not in columnscopy: columnscopy.append(radec) addedcols.append(radec) # ADM if a directory was passed, do fancy HEALPixel parsing... if os.path.isdir(hpdirname): # ADM approximate nside for area of passed box. nside = pixarea2nside(box_area(radecbox)) # ADM HEALPixels that touch the box for that nside. pixlist = hp_in_box(nside, radecbox) # ADM read in targets in these HEALPixels. targets = read_targets_in_hp(hpdirname, nside, pixlist, columns=columnscopy) # ADM ...otherwise just read in the targets. else: targets = fitsio.read(hpdirname, columns=columnscopy) # ADM restrict only to targets in the requested RA/Dec box... ii = is_in_box(targets, radecbox) # ADM ...and remove RA/Dec columns if we added them. targets = rfn.drop_fields(targets[ii], addedcols) return targets
def test_targets_spatial(self): """Test applying RA/Dec/HEALpixel inputs to sweeps recovers same targets """ # ADM only test some of the galaxy cuts for speed. There's a # ADM full run through all classes in test_cuts_basic. tc = ["LRG", "ELG", "BGS"] infiles = self.sweepfiles[2] targets = cuts.select_targets(infiles, numproc=1, tcnames=tc) # ADM test the RA/Dec box input. radecbox = [ np.min(targets["RA"]) - 0.01, np.max(targets["RA"]) + 0.01, np.min(targets["DEC"]) - 0.01, np.max(targets["DEC"] + 0.01) ] t1 = cuts.select_targets(infiles, numproc=1, tcnames=tc, radecbox=radecbox) # ADM test the RA/Dec/radius cap input. centra, centdec = 0.5 * (radecbox[0] + radecbox[1]), 0.5 * ( radecbox[2] + radecbox[3]) # ADM 20 degrees should be a large enough radius for the sweeps. maxrad = 20. radecrad = centra, centdec, maxrad t2 = cuts.select_targets(infiles, numproc=1, tcnames=tc, radecrad=radecrad) # ADM test the pixel input. nside = pixarea2nside(box_area(radecbox)) pixlist = hp_in_box(nside, radecbox) t3 = cuts.select_targets(infiles, numproc=1, tcnames=tc, nside=nside, pixlist=pixlist) # ADM sort each set of targets on TARGETID to compare them. targets = targets[np.argsort(targets["TARGETID"])] t1 = t1[np.argsort(t1["TARGETID"])] t2 = t2[np.argsort(t2["TARGETID"])] t3 = t3[np.argsort(t3["TARGETID"])] # ADM test the same targets were recovered and that # ADM each recovered target has the same bits set. for targs in t1, t2, t3: for col in "TARGETID", "DESI_TARGET", "BGS_TARGET", "MWS_TARGET": self.assertTrue(np.all(targs[col] == targets[col]))
def randoms_in_a_brick_from_edges(ramin, ramax, decmin, decmax, density=100000, poisson=True): """For given brick edges, return random (RA/Dec) positions in the brick Parameters ---------- ramin : :class:`float` The minimum "edge" of the brick in Right Ascension. ramax : :class:`float` The maximum "edge" of the brick in Right Ascension. decmin : :class:`float` The minimum "edge" of the brick in Declination. decmax : :class:`float` The maximum "edge" of the brick in Declination. density : :class:`int`, optional, defaults to 100,000 The number of random points to return per sq. deg. As a typical brick is ~0.25 x 0.25 sq. deg. about (0.0625*density) points will be returned. poisson : :class:`boolean`, optional, defaults to True Modify the number of random points in the brick so that instead of simply being the brick area x the density, it is a number drawn from a Poisson distribution with the expectation being the brick area x the density. Returns ------- :class:`~numpy.array` Right Ascensions of random points in brick :class:`~numpy.array` Declinations of random points in brick """ # ADM create a unique random seed on the basis of the brick. # ADM note this is only unique for bricksize=0.25 for bricks # ADM that are more than 0.25 degrees from the poles. uniqseed = int(4 * ramin) * 1000 + int(4 * (decmin + 90)) np.random.seed(uniqseed) # ADM generate random points within the brick at the requested density # ADM guard against potential wraparound bugs (assuming bricks are typical # ADM sizes of 0.25 x 0.25 sq. deg., or not much larger than that if ramax - ramin > 350.: ramax -= 360. spharea = box_area([ramin, ramax, decmin, decmax]) if poisson: nrand = int(np.random.poisson(spharea * density)) else: nrand = int(spharea * density) # log.info('Full area covered by brick is {:.5f} sq. deg....t = {:.1f}s' # .format(spharea,time()-start)) ras = np.random.uniform(ramin, ramax, nrand) sindecmin, sindecmax = np.sin(np.radians(decmin)), np.sin( np.radians(decmax)) decs = np.degrees( np.arcsin(1. - np.random.uniform(1 - sindecmax, 1 - sindecmin, nrand))) nrand = len(ras) # log.info('Generated {} randoms in brick with bounds [{:.3f},{:.3f},{:.3f},{:.3f}]...t = {:.1f}s' # .format(nrand,ramin,ramax,decmin,decmax,time()-start)) return ras, decs
def randoms_in_a_brick_from_name(brickname, drdir, density=100000): """For a given brick name, return random (RA/Dec) positions in the brick. Parameters ---------- brickname : :class:`str` Name of brick in which to generate random points. drdir : :class:`str` The root directory pointing to a Data Release from the Legacy Surveys e.g. /global/project/projectdirs/cosmo/data/legacysurvey/dr7. density : :class:`int`, optional, defaults to 100,000 The number of random points to return per sq. deg. As a typical brick is ~0.25 x 0.25 sq. deg. about (0.0625*density) points will be returned. Returns ------- :class:`~numpy.array` Right Ascensions of random points in brick. :class:`~numpy.array` Declinations of random points in brick. Notes ----- - First version copied shamelessly from Anand Raichoor. """ # ADM read in the survey bricks file to determine the brick boundaries hdu = fits.open(drdir + 'survey-bricks.fits.gz') brickinfo = hdu[1].data wbrick = np.where(brickinfo['brickname'] == brickname)[0] if len(wbrick) == 0: log.error('Brick {} does not exist'.format(brickname)) # else: # log.info('Working on brick {}...t = {:.1f}s'.format(brickname,time()-start)) brick = brickinfo[wbrick][0] ramin, ramax, decmin, decmax = brick['ra1'], brick['ra2'], brick[ 'dec1'], brick['dec2'] # ADM create a unique random seed on the basis of the brick. # ADM note this is only unique for bricksize=0.25 for bricks # ADM that are more than 0.25 degrees from the poles. uniqseed = int(4 * ramin) * 1000 + int(4 * (decmin + 90)) np.random.seed(uniqseed) # ADM generate random points within the brick at the requested density # ADM guard against potential wraparound bugs if ramax - ramin > 350.: ramax -= 360. spharea = box_area([ramin, ramax, decmin, decmax]) nrand = int(spharea * density) # log.info('Full area covered by brick {} is {:.5f} sq. deg....t = {:.1f}s' # .format(brickname,spharea,time()-start)) ras = np.random.uniform(ramin, ramax, nrand) sindecmin, sindecmax = np.sin(np.radians(decmin)), np.sin( np.radians(decmax)) decs = np.degrees( np.arcsin(1. - np.random.uniform(1 - sindecmax, 1 - sindecmin, nrand))) nrand = len(ras) # log.info('Generated {} randoms in brick {} with bounds [{:.3f},{:.3f},{:.3f},{:.3f}]...t = {:.1f}s' # .format(nrand,brickname,ramin,ramax,decmin,decmax,time()-start)) return ras, decs