Everything should work fine using a DESI kernel loaded from NERSC's jupyter-dev server. See the instuctions under Getting Started at:
https://github.com/desihub/tutorials/blob/master/Intro_to_DESI_spectra.ipynb
If you're running locally on your own machine, you may also need to set up your own development kernel as described here:
https://desi.lbl.gov/trac/wiki/Computing/JupyterAtNERSC
under defining your own kernel.
Now, retrieve a sample of the sweeps files, say, everything in DR5 that starts sweep-150. I'll assume you put this in your $CSCRATCH directory at NERSC, as follows:
mkdir $CSCRATCH/sweep150
cp /global/project/projectdirs/cosmo/data/legacysurvey/dr5/sweep/5.0/sweep-150* $CSCRATCH/sweep150
To create a bright source mask by scraping bright sources (of all types) from the sweeps:
make_bright_mask $CSCRATCH/sweep150 $CSCRATCH/sourcemask150.fits
this mask will use default settings and create masks for everything that is brighter than 10th magnitude in each of the g, r and z bands. This took just under 1.5 minutes, for me, on edison, and returned the following informative message:
INFO:make_bright_mask:48:<module>: wrote a file of 1292 masks to $CSCRATCH/sourcemask150.fits
You can also customize the limiting magnitude of source to be masked, e.g.:
make_bright_mask $CSCRATCH/sweep150 --bands GZ --maglim 9,10 $CSCRATCH/blat.fits
will mask any source that is brighter than g < 9 or z < 10.
This took about 1.5 minutes for me on edison and returned the following message:
INFO:make_bright_mask:48:<module>: wrote a file of 1164 masks to $CSCRATCH/blat.fits
Let's examine the mask and plot it. Note that NEAR_RADIUS
is a warning that you're near a mask (which could be useful for large-scale structure analyses) whereas IN_RADIUS
is the radius to which DESI will certainly not place any fibers (for fear of saturating adjacent sources).
In [1]:
%matplotlib inline
import matplotlib.pyplot as plt
import os
import numpy as np
import fitsio
from desitarget import desi_mask, brightmask
You may have to set up your $CSCRATCH
environment variable so that Python
can find it, e.g.:
In [2]:
os.environ["CSCRATCH"] = '/global/cscratch1/sd/adamyers'
In [3]:
sourcemask = fitsio.read("$CSCRATCH/sourcemask150.fits")
In [4]:
brightmask.plot_mask(sourcemask,limits=[151,150,1,2])
In [5]:
brightmask.plot_mask(sourcemask,limits=[151,150,1,2],radius="NEAR_RADIUS")
These are some circular regions that could be masked, but let's check the capability also for elliptical regions:
In [6]:
from desitarget.brightmask import _rexlike
from desitarget.cuts import _psflike
rex_or_psf = _rexlike(sourcemask["TYPE"]) | _psflike(sourcemask["TYPE"])
wcircle = np.where(rex_or_psf)
wellipse = np.where(~rex_or_psf)
sourcemask[wcircle][20:25]
Out[6]:
In [7]:
sourcemask[wellipse][20:25]
Out[7]:
Note that the ellipticity components, here, which are defined at the bottom of the page at, e.g., http://legacysurvey.org/dr5/catalogs/ are 0.0 for circular masks.
Let's plot a region that has a mix of circular and elliptical masks:
In [8]:
brightmask.plot_mask(sourcemask,limits=[155.1,154.8,19.7,20.0],radius="NEAR_RADIUS")
Now let's compile a file of targets from the same set of sweeps. Again, I'll dump the targets file in your $CSCRATCH directory. This took just under 4 minutes, for me:
select_targets $CSCRATCH/sweep150 $CSCRATCH/targs150.fits
and informed me that:
INFO:select_targets:73:<module>: 1741104 targets written to /global/cscratch1/sd/adamyers/targs150.fits
Note that at NERSC, the whole masking procedure can be applied to the targets in one line of code via, e.g.:
select_targets $CSCRATCH/sweep150 $CSCRATCH/targsblat150.fits --mask $CSCRATCH/sourcemask150.fits
BADSKY
("SAFE") locationsFirst, let's generate BADSKY
("SAFE") locations around the periphery of each mask and plot them against the backdrop of the mask. Note that drstring
, if set, is used to assign the Data Release (DR) bit to BADSKY
targets and to assign BADSKY
targets an OBJID
that is higher than any target in a given brick of that DR. (That's the part that requires a DR survey-brick
file, though).
In [9]:
targs = fitsio.read("$CSCRATCH/targs150.fits")
print(len(targs))
print(len(np.where( (targs["DESI_TARGET"] & desi_mask.BADSKY) != 0 )[0]))
In [10]:
targs = brightmask.append_safe_targets(targs,sourcemask)
print(len(targs))
print(len(np.where( (targs["DESI_TARGET"] & desi_mask.BADSKY) != 0 )[0]))
In [11]:
w = np.where( (targs["DESI_TARGET"] & desi_mask.BADSKY) != 0 )
badskies= targs[w]
In [12]:
brightmask.plot_mask(sourcemask,show=False)
plt.axis([155.1,154.8,19.7,20.0])
plt.plot(badskies["RA"],badskies["DEC"],'k,')
plt.xlabel('RA (o)')
plt.ylabel('Dec (o)')
plt.show()
In [13]:
desi_mask
Out[13]:
In [14]:
dt = brightmask.set_target_bits(targs,sourcemask)
inmask = np.where( (dt & desi_mask.IN_BRIGHT_OBJECT) != 0)
masked = targs[inmask]
notinmask = np.where( (dt & desi_mask.IN_BRIGHT_OBJECT) == 0)
unmasked = targs[notinmask]
Let's plot which objects are in masks and which are not, against the backdrop of the mask (in a small region of the sky):
In [15]:
brightmask.plot_mask(sourcemask,show=False)
plt.axis([155.1,154.8,19.7,20.0])
plt.xlabel('RA (o)')
plt.ylabel('Dec (o)')
plt.plot(masked["RA"],masked["DEC"],'kx')
plt.plot(unmasked["RA"],unmasked["DEC"],'r.')
plt.show()
Note that the BADSKY
locations are just outside the perimeter of the masks, and are quite obvious in the plot.
The brightmask.set_target_bits()
function wraps the main masking code in brightmask
, called is_in_bright_mask()
. The is_in_bright_mask()
function can be used to compare coordinate locations to a mask and return which objects are in the mask (within the IN_RADIUS
of the mask) and which objects are close to the mask (within the NEAR_RADIUS
of the mask).
Let's create a random catalog over the small area of sky that we've been considering (154.8o < RA < 155.1o) and (19.7o < Dec < 20.0o):
In [16]:
from numpy.random import random
Nran = 100000
rancat = np.zeros(Nran, dtype=[('RA', '>f8'), ('DEC', '>f8')])
rancat["RA"] = 154.8+0.3*(random(Nran))
rancat["DEC"] = np.degrees(np.arcsin(np.sin(np.radians(20))-random(Nran)*0.05))
Now let's mask that random catalog:
In [17]:
inmask, nearmask = brightmask.is_in_bright_mask(rancat,sourcemask)
masked = rancat[np.where(inmask)]
notmasked = rancat[np.where(~inmask)]
near = rancat[np.where(nearmask)]
notnear = rancat[np.where(~nearmask)]
and plot the random points that are and are not in the mask, both for the IN_RADIUS
and the NEAR_RADIUS
:
In [18]:
brightmask.plot_mask(sourcemask,show=False)
plt.axis([155.1,154.8,19.7,20.0])
plt.xlabel('RA (o)')
plt.ylabel('Dec (o)')
plt.plot(masked["RA"],masked["DEC"],'r.')
plt.plot(notmasked["RA"],notmasked["DEC"],'g,')
plt.show()
In [19]:
brightmask.plot_mask(sourcemask,show=False,radius="NEAR_RADIUS")
plt.axis([155.1,154.8,19.7,20.0])
plt.xlabel('RA (o)')
plt.ylabel('Dec (o)')
plt.plot(near["RA"],near["DEC"],'r.')
plt.plot(notnear["RA"],notnear["DEC"],'g,')
plt.show()