Target selection bits and bitmasks

Author: Adam D. Myers, University of Wyoming

This Notebook describes how to work with target selection bitmasks for DESI.

Setting up your environment

First, ensure that your environment matches a standard DESI environment. For example:

module unload desimodules
source /project/projectdirs/desi/software/desi_environment.sh 18.7

desitarget relies on desiutil and desimodel, so you may also need to set up a wider DESI environment, as detailed at:

https://desi.lbl.gov/trac/wiki/Pipeline/GettingStarted/Laptop/JuneMeeting

It may also be useful to set up some additional environment variables that are used in some versions of the desitarget code (you could also place these in your .bash_profile.ext file):

export DESIMODEL=$HOME/git/desimodel
export DUST_DIR=/project/projectdirs/desi/software/edison/dust/v0_1/maps
export GAIA_DIR=/project/projectdirs/desi/target/gaia_dr2

Here, I've set DESIMODEL to a reasonable location. For a more detailed description of checking out the desimodel data files from svn see:

https://desi.lbl.gov/trac/wiki/Pipeline/GettingStarted/Laptop/JuneMeeting#Datafilesfordesimodel

Understanding the desitarget bitmasks

Main Survey bitmasks

The critical values that select_targets produces are the DESI_TARGET, BGS_TARGET and MWS_TARGET bit masks, which contain the target bits for the DESI main (or "dark time") survey and the Bright Galaxy Survey and Milky Way Survey respectively. Let's examine the masks that correspond to these surveys.


In [91]:
from desitarget.targets import desi_mask, bgs_mask, mws_mask
print(desi_mask)


desi_mask:
  - [LRG,              0, "LRG", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 3200, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3200, 'MORE_ZGOOD': 3200}, 'numobs': 0}]
  - [ELG,              1, "ELG", {'obsconditions': 'DARK|GRAY', 'priorities': {'UNOBS': 3000, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3000, 'MORE_ZGOOD': 3000}, 'numobs': 1}]
  - [QSO,              2, "QSO", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 3400, 'MORE_ZGOOD': 3500, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3400}, 'numobs': 4}]
  - [LRG_1PASS,        3, "LRG to be observed once", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 3200, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3200, 'MORE_ZGOOD': 3200}, 'numobs': 1}]
  - [LRG_2PASS,        4, "LRG to be observed twice", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 3200, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3200, 'MORE_ZGOOD': 3200}, 'numobs': 2}]
  - [LRG_NORTH,        8, "LRG cuts tuned for Bok/Mosaic data", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0}, 'numobs': 0}]
  - [ELG_NORTH,        9, "ELG cuts tuned for Bok/Mosaic data", {'obsconditions': 'DARK|GRAY', 'priorities': {'UNOBS': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0}, 'numobs': 0}]
  - [QSO_NORTH,       10, "QSO cuts tuned for Bok/Mosaic data", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0}, 'numobs': 0}]
  - [LRG_SOUTH,       16, "LRG cuts tuned for DECam data", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0}, 'numobs': 0}]
  - [ELG_SOUTH,       17, "ELG cuts tuned for DECam data", {'obsconditions': 'DARK|GRAY', 'priorities': {'UNOBS': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0}, 'numobs': 0}]
  - [QSO_SOUTH,       18, "QSO cuts tuned for DECam data", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0}, 'numobs': 0}]
  - [LRG_1PASS_NORTH, 24, "LRG to be observed once tuned for Bok/Mosaic", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0}, 'numobs': 0}]
  - [LRG_2PASS_NORTH, 25, "LRG to be observed twice tuned for Bok/Mosaic", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0}, 'numobs': 0}]
  - [LRG_1PASS_SOUTH, 28, "LRG to be observed once tuned for DECam", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0}, 'numobs': 0}]
  - [LRG_2PASS_SOUTH, 29, "LRG to be observed twice tuned for DECam", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0}, 'numobs': 0}]
  - [SKY,             32, "Blank sky locations", {'obsconditions': 'DARK|GRAY|BRIGHT|POOR|TWILIGHT12|TWILIGHT18', 'priorities': {}, 'numobs': -1}]
  - [STD_FAINT,       33, "Standard stars for dark/gray conditions", {'obsconditions': 'DARK|GRAY', 'priorities': {}, 'numobs': -1}]
  - [STD_WD,          34, "White Dwarf stars", {'obsconditions': 'DARK|GRAY|BRIGHT', 'priorities': {}, 'numobs': -1}]
  - [STD_BRIGHT,      35, "Standard stars for BRIGHT conditions", {'obsconditions': 'BRIGHT', 'priorities': {}, 'numobs': -1}]
  - [BAD_SKY,         36, "Blank sky locations that are imperfect but still useable", {'obsconditions': 'DARK|GRAY|BRIGHT|POOR|TWILIGHT12|TWILIGHT18', 'priorities': {'UNOBS': 0, 'OBS': 0, 'DONE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0, 'DONOTOBSERVE': 1}, 'numobs': 0}]
  - [SUPP_SKY,        37, "SKY is based on Gaia-avoidance (SKY will be set, too)", {'obsconditions': 'DARK|GRAY|BRIGHT|POOR|TWILIGHT12|TWILIGHT18', 'priorities': {}, 'numobs': -1}]
  - [NO_TARGET,       49, "No known target at this location", {'obsconditions': 'DARK|GRAY|BRIGHT|POOR|TWILIGHT12|TWILIGHT18', 'priorities': {}, 'numobs': -1}]
  - [BRIGHT_OBJECT,   50, "Known bright object to avoid", {'obsconditions': 'APOCALYPSE', 'priorities': {}, 'numobs': -1}]
  - [IN_BRIGHT_OBJECT, 51, "Too near a bright object; DO NOT OBSERVE", {'obsconditions': 'APOCALYPSE', 'priorities': {}, 'numobs': -1}]
  - [NEAR_BRIGHT_OBJECT, 52, "Near a bright object but ok to observe", {'obsconditions': 'DARK|GRAY|BRIGHT|POOR|TWILIGHT12|TWILIGHT18', 'priorities': {}, 'numobs': -1}]
  - [BGS_ANY,         60, "Any BGS bit is set", {'obsconditions': 'BRIGHT', 'priorities': {}, 'numobs': -1}]
  - [MWS_ANY,         61, "Any MWS bit is set", {'obsconditions': 'BRIGHT', 'priorities': {}, 'numobs': -1}]
  - [SCND_ANY,        62, "Any secondary bit is set", {'obsconditions': 'DARK|GRAY|BRIGHT|POOR|TWILIGHT12|TWILIGHT18', 'priorities': {}, 'numobs': -1}]

The mask contains the name of the target bit (e.g. ELG) the bit value to which that name corresponds (e.g. 1, meaning 2-to-the-power-1), a description of the target (e.g. "ELG") and a dictionary of values that contain information for fiber assignment, such as the observing conditions allowed for the target, the initial priority with which the target class should be observed, and the initial number of observations for the target class. Note that these bits of information can be accessed individually in a number of ways:


In [92]:
desi_mask["QSO"], desi_mask.QSO # ADM different ways of accessing the bit values.


Out[92]:
(4, 4)

In [93]:
desi_mask.names() # ADM the names of each target type.


Out[93]:
['LRG',
 'ELG',
 'QSO',
 'LRG_1PASS',
 'LRG_2PASS',
 'LRG_NORTH',
 'ELG_NORTH',
 'QSO_NORTH',
 'LRG_SOUTH',
 'ELG_SOUTH',
 'QSO_SOUTH',
 'LRG_1PASS_NORTH',
 'LRG_2PASS_NORTH',
 'LRG_1PASS_SOUTH',
 'LRG_2PASS_SOUTH',
 'SKY',
 'STD_FAINT',
 'STD_WD',
 'STD_BRIGHT',
 'BAD_SKY',
 'SUPP_SKY',
 'NO_TARGET',
 'BRIGHT_OBJECT',
 'IN_BRIGHT_OBJECT',
 'NEAR_BRIGHT_OBJECT',
 'BGS_ANY',
 'MWS_ANY',
 'SCND_ANY']

In [94]:
desi_mask.names(7) # ADM the names of target classes that correspond to an integer value of 5.
# ADM note that 7 is 2**0 + 2**1 + 2**2.


Out[94]:
['LRG', 'ELG', 'QSO']

In [95]:
desi_mask.bitnum("SKY") # ADM the integer value that corresponds to the "SKY" bit.


Out[95]:
32

In [96]:
names = desi_mask.names()
bitnums = [desi_mask.bitnum(name) for name in names]
bitvals = [desi_mask[name] for name in names]
list(zip(names,bitnums,bitvals)) # ADM the bit and integer value for each defined name.


Out[96]:
[('LRG', 0, 1),
 ('ELG', 1, 2),
 ('QSO', 2, 4),
 ('LRG_1PASS', 3, 8),
 ('LRG_2PASS', 4, 16),
 ('LRG_NORTH', 8, 256),
 ('ELG_NORTH', 9, 512),
 ('QSO_NORTH', 10, 1024),
 ('LRG_SOUTH', 16, 65536),
 ('ELG_SOUTH', 17, 131072),
 ('QSO_SOUTH', 18, 262144),
 ('LRG_1PASS_NORTH', 24, 16777216),
 ('LRG_2PASS_NORTH', 25, 33554432),
 ('LRG_1PASS_SOUTH', 28, 268435456),
 ('LRG_2PASS_SOUTH', 29, 536870912),
 ('SKY', 32, 4294967296),
 ('STD_FAINT', 33, 8589934592),
 ('STD_WD', 34, 17179869184),
 ('STD_BRIGHT', 35, 34359738368),
 ('BAD_SKY', 36, 68719476736),
 ('SUPP_SKY', 37, 137438953472),
 ('NO_TARGET', 49, 562949953421312),
 ('BRIGHT_OBJECT', 50, 1125899906842624),
 ('IN_BRIGHT_OBJECT', 51, 2251799813685248),
 ('NEAR_BRIGHT_OBJECT', 52, 4503599627370496),
 ('BGS_ANY', 60, 1152921504606846976),
 ('MWS_ANY', 61, 2305843009213693952),
 ('SCND_ANY', 62, 4611686018427387904)]

In [97]:
desi_mask["LRG"].priorities # ADM a dictionary of initial priorities for the LRG target class.


Out[97]:
{'UNOBS': 3200,
 'DONE': 2,
 'OBS': 1,
 'DONOTOBSERVE': 0,
 'MORE_ZWARN': 3200,
 'MORE_ZGOOD': 3200}

In [98]:
desi_mask["LRG"].obsconditions, desi_mask["LRG"].numobs, desi_mask["LRG"].priorities["MORE_ZGOOD"]


Out[98]:
('DARK', 0, 3200)

There are corresponding masks for the BGS and MWS, which can be accessed in the same way, e.g.:


In [99]:
bgs_mask.names()


Out[99]:
['BGS_FAINT',
 'BGS_BRIGHT',
 'BGS_WISE',
 'BGS_FAINT_HIP',
 'BGS_FAINT_NORTH',
 'BGS_BRIGHT_NORTH',
 'BGS_WISE_NORTH',
 'BGS_FAINT_SOUTH',
 'BGS_BRIGHT_SOUTH',
 'BGS_WISE_SOUTH']

In [100]:
mws_mask.names()


Out[100]:
['MWS_BROAD',
 'MWS_WD',
 'MWS_NEARBY',
 'MWS_BROAD_NORTH',
 'MWS_BROAD_SOUTH',
 'MWS_MAIN_BLUE',
 'MWS_MAIN_BLUE_NORTH',
 'MWS_MAIN_BLUE_SOUTH',
 'MWS_MAIN_RED',
 'MWS_MAIN_RED_NORTH',
 'MWS_MAIN_RED_SOUTH']

The Commissioning and Survey Validation bitmasks

In addition to the DESI Main Survey, desitarget produces targets for Commissioning ("CMX") and Survey Validation ("SV"). The CMX and SV bitmasks can be obtained and examined as follows (other manipulation of these masks is similar to the previous sub-section, above):


In [101]:
from desitarget.cmx.cmx_targetmask import cmx_mask
print(cmx_mask)


cmx_mask:
  - [STD_GAIA,         0, "Gaia stars used for dithering tests", {'obsconditions': 'DARK|GRAY|BRIGHT', 'priorities': {'UNOBS': 2400, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 2400, 'MORE_ZGOOD': 2400}, 'numobs': 1}]
  - [SV0_STD_FAINT,    1, "SV-like STD_FAINT class is set (very early SV selection)", {'obsconditions': 'DARK|GRAY', 'priorities': {'UNOBS': 2600, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 2600, 'MORE_ZGOOD': 2600}, 'numobs': 1}]
  - [SV0_STD_BRIGHT,   2, "SV-like STD_BRIGHT class is set (very early SV selection)", {'obsconditions': 'BRIGHT', 'priorities': {'UNOBS': 2600, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 2600, 'MORE_ZGOOD': 2600}, 'numobs': 1}]
  - [STD_TEST,         3, "Very bright stars for early tests", {'obsconditions': 'DARK|GRAY|BRIGHT', 'priorities': {'UNOBS': 2800, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 2800, 'MORE_ZGOOD': 2800}, 'numobs': 1}]
  - [STD_CALSPEC,      4, "Matches to CALSPEC stars", {'obsconditions': 'DARK|GRAY|BRIGHT', 'priorities': {'UNOBS': 3000, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3000, 'MORE_ZGOOD': 3000}, 'numobs': 1}]
  - [SV0_BGS,          8, "SV-like BGS bit is set (very early SV selection)", {'obsconditions': 'BRIGHT', 'priorities': {'UNOBS': 2100, 'MORE_ZWARN': 2100, 'MORE_ZGOOD': 1000, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0}, 'numobs': 1}]
  - [SV0_MWS,          9, "SV-like MWS bit is set (very early SV selection)", {'obsconditions': 'BRIGHT', 'priorities': {'UNOBS': 1500, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 1500, 'MORE_ZGOOD': 1500}, 'numobs': 1}]
  - [SV0_LRG,         10, "SV-like LRG bit is set (very early SV selection)", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 3200, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3200, 'MORE_ZGOOD': 3200}, 'numobs': 2}]
  - [SV0_ELG,         11, "SV-like ELG bit is set (very early SV selection)", {'obsconditions': 'DARK|GRAY', 'priorities': {'UNOBS': 3000, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3000, 'MORE_ZGOOD': 3000}, 'numobs': 1}]
  - [SV0_QSO,         12, "SV-like QSO bit is set (very early SV/RF selection)", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 3400, 'MORE_ZGOOD': 3500, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3400}, 'numobs': 4}]
  - [SV0_WD,          13, "SV-like WD bit is set (very early MWS_WD selection)", {'obsconditions': 'BRIGHT', 'priorities': {'UNOBS': 2998, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 2998, 'MORE_ZGOOD': 2998}, 'numobs': 1}]
  - [SKY,             32, "Blank sky locations", {'obsconditions': 'DARK|GRAY|BRIGHT|POOR|TWILIGHT12|TWILIGHT18', 'priorities': {}, 'numobs': -1}]
  - [STD_FAINT,       33, "SV-like standard stars for dark/gray conditions", {'obsconditions': 'DARK|GRAY', 'priorities': {}, 'numobs': -1}]
  - [STD_BRIGHT,      35, "SV-like standard stars for BRIGHT conditions", {'obsconditions': 'BRIGHT', 'priorities': {}, 'numobs': -1}]
  - [BAD_SKY,         36, "Blank sky locations that are imperfect but still useable", {'obsconditions': 'DARK|GRAY|BRIGHT|POOR|TWILIGHT12|TWILIGHT18', 'priorities': {'UNOBS': 0, 'OBS': 0, 'DONE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0, 'DONOTOBSERVE': 1}, 'numobs': 0}]
  - [SUPP_SKY,        37, "SKY is based on Gaia-avoidance (SKY will be set, too)", {'obsconditions': 'DARK|GRAY|BRIGHT|POOR|TWILIGHT12|TWILIGHT18', 'priorities': {}, 'numobs': -1}]

In [102]:
from desitarget.sv1.sv1_targetmask import desi_mask, bgs_mask, mws_mask
desi_mask.names()


Out[102]:
['LRG',
 'ELG',
 'QSO',
 'LRG_INIT',
 'LRG_LOWZ',
 'LRG_HIGHZ',
 'LRG_RELAX',
 'LRG_SUPER',
 'ELG_FDR',
 'ELG_FDR_FAINT',
 'ELG_RZ_BLUE',
 'ELG_RZ_RED',
 'QSO_COLOR_4PASS',
 'QSO_RF_4PASS',
 'QSO_COLOR_8PASS',
 'QSO_RF_8PASS',
 'QSO_HZ_F',
 'LRG_NORTH',
 'ELG_NORTH',
 'QSO_NORTH',
 'LRG_SOUTH',
 'ELG_SOUTH',
 'QSO_SOUTH',
 'LRG_INIT_NORTH',
 'LRG_LOWZ_NORTH',
 'LRG_HIGHZ_NORTH',
 'LRG_RELAX_NORTH',
 'LRG_SUPER_NORTH',
 'LRG_INIT_SOUTH',
 'LRG_LOWZ_SOUTH',
 'LRG_HIGHZ_SOUTH',
 'LRG_RELAX_SOUTH',
 'SKY',
 'STD_FAINT',
 'STD_WD',
 'STD_BRIGHT',
 'BAD_SKY',
 'LRG_SUPER_SOUTH',
 'ELG_FDR_NORTH',
 'ELG_FDR_FAINT_NORTH',
 'ELG_RZ_BLUE_NORTH',
 'ELG_RZ_RED_NORTH',
 'ELG_FDR_SOUTH',
 'ELG_FDR_FAINT_SOUTH',
 'ELG_RZ_BLUE_SOUTH',
 'ELG_RZ_RED_SOUTH',
 'QSO_COLOR_4PASS_NORTH',
 'QSO_RF_4PASS_NORTH',
 'QSO_COLOR_8PASS_NORTH',
 'NO_TARGET',
 'BRIGHT_OBJECT',
 'IN_BRIGHT_OBJECT',
 'NEAR_BRIGHT_OBJECT',
 'QSO_RF_8PASS_NORTH',
 'QSO_HZ_F_NORTH',
 'QSO_COLOR_4PASS_SOUTH',
 'QSO_RF_4PASS_SOUTH',
 'QSO_COLOR_8PASS_SOUTH',
 'QSO_RF_8PASS_SOUTH',
 'QSO_HZ_F_SOUTH',
 'BGS_ANY',
 'MWS_ANY',
 'SCND_ANY']

Using the bitmasks to understand a file of targets

Important aside!!!

Target classes have evolved throughout the history of the desitarget code, and the bits that correspond to those targets have thus occasionally changed. It is therefore critical that you use the same version of desitarget when working with bits in a target file as was used to create that target file!

For example, say you are working with commissioning targets that were created with version 0.X.X of desitarget. The correct version of Git to use to study this file can be obtained via:

git checkout 0.X.X

and the corresponding .yaml file online on GitHub would be:

https://github.com/desihub/desitarget/blob/0.X.X/py/desitarget/cmx/data/cmx_targetmask.yaml

For example, for version 0.31.1 of desitarget issue:

git checkout 0.31.1

or look at:

https://github.com/desihub/desitarget/blob/0.31.1/py/desitarget/cmx/data/cmx_targetmask.yaml

Equivalently, for version 0.31.1 of desitarget for SV or the Main Survey:

https://github.com/desihub/desitarget/blob/0.31.1/py/desitarget/sv1/data/sv1_targetmask.yaml

https://github.com/desihub/desitarget/blob/0.31.1/py/desitarget/data/targetmask.yaml

Commissioning targeting bits are expected to be final as of version 0.32.0 of desitarget. SV and Main Survey bits may not yet be final.

Working with target files

The target files produced by select_targets contain many quantities from the Legacy Surveys data model sweeps files at, e.g.:

http://www.legacysurvey.org/dr7/files/#sweep-7-0-sweep-brickmin-brickmax-fits

The main columns added by select_targets are DESI_TARGET, BGS_TARGET and MWS_TARGET, which contain the output bitmasks from target selection. Let's take a closer look at how these columns can be used in conjunction with the bitmasks.

First, enter the Python prompt. Now, let's read in a file of targets. I'll assume you're working at NERSC, but set targdir, below, to wherever you have a targets- file.


In [125]:
import os
from glob import glob
from astropy.io.fits import getdata
import numpy as np
# ADM replace this with any directory you know of that holds targets.
targdir = "/project/projectdirs/desi/target/catalogs/examples"
# ADM replace this with the name of any target file.
targfile = 'targets.fits'
targfile = os.path.join(targdir, targfile)
targs = getdata(targfile)

Note that if you took the file from my the examples directory, then you're using an example file that only contains a subset of columns.


In [126]:
print(targs.dtype)


(numpy.record, [('RA', '>f8'), ('DEC', '>f8'), ('FLUX_G', '>f4'), ('FLUX_R', '>f4'), ('FLUX_Z', '>f4'), ('FLUX_W1', '>f4'), ('FLUX_W2', '>f4'), ('MW_TRANSMISSION_G', '>f4'), ('MW_TRANSMISSION_R', '>f4'), ('MW_TRANSMISSION_Z', '>f4'), ('MW_TRANSMISSION_W1', '>f4'), ('MW_TRANSMISSION_W2', '>f4'), ('PARALLAX', '>f4'), ('PMRA', '>f4'), ('PMDEC', '>f4'), ('DESI_TARGET', '>i8'), ('BGS_TARGET', '>i8'), ('MWS_TARGET', '>i8')])

Let's consider the value of DESI_TARGET for the forty-second target:


In [127]:
targ = targs[41]
print(targ["DESI_TARGET"])


394758

What does this number mean? Well, let's see which target classes are defined by this integer:


In [128]:
from desitarget.targets import desi_mask
desi_mask.names(targ["DESI_TARGET"])


Out[128]:
['ELG', 'QSO', 'ELG_NORTH', 'QSO_NORTH', 'ELG_SOUTH', 'QSO_SOUTH']

Now let's see what target classes are include for the first 10 targets:


In [129]:
bitnames = np.array(desi_mask.names())  # ADM note the array conversion to help manipulation.
bitvals = [desi_mask[name] for name in bitnames]
for targ in targs[:10]:
    w = np.where( (targ["DESI_TARGET"] & bitvals) != 0)[0]
    print(targ["DESI_TARGET"], bitnames[w])


1152921504606846976 ['BGS_ANY']
131586 ['ELG' 'ELG_NORTH' 'ELG_SOUTH']
1152921504606846976 ['BGS_ANY']
285278473 ['LRG' 'LRG_1PASS' 'LRG_NORTH' 'LRG_SOUTH' 'LRG_1PASS_NORTH'
 'LRG_1PASS_SOUTH']
131586 ['ELG' 'ELG_NORTH' 'ELG_SOUTH']
1152921504606846976 ['BGS_ANY']
131586 ['ELG' 'ELG_NORTH' 'ELG_SOUTH']
131074 ['ELG' 'ELG_SOUTH']
131586 ['ELG' 'ELG_NORTH' 'ELG_SOUTH']
131586 ['ELG' 'ELG_NORTH' 'ELG_SOUTH']

So far, we've looked at the target class for each target. Now, let's just extract target classes that correspond to a certain bit. For example, which of the first 10 targets have the 'BGS_ANY' bit set?


In [130]:
np.where((targs[:10]["DESI_TARGET"] & desi_mask["BGS_ANY"]) != 0)[0]


Out[130]:
array([0, 2, 5])

Which of all of the targets are both ELG and quasar targets?


In [131]:
isELG = (targs["DESI_TARGET"] & desi_mask["ELG"]) != 0
isQSO = (targs["DESI_TARGET"] & desi_mask["QSO"]) != 0
np.where(isELG & isQSO)[0]


Out[131]:
array([ 41, 265, 355, 535, 561, 753, 788, 804, 835, 937])

Alternatively, more compactly"


In [132]:
bitvalboth = desi_mask["ELG"] + desi_mask["QSO"]
np.where(targs["DESI_TARGET"] & bitvalboth == bitvalboth)[0]


Out[132]:
array([ 41, 265, 355, 535, 561, 753, 788, 804, 835, 937])

You should note that the forty-second target studied above pops up in these lists!

Note that desi_mask contains a couple of special bits that simply denote whether a target is a BGS or MWS target. These are called BGS_ANY and MWS_ANY. For example:


In [133]:
print((targs[:10]["DESI_TARGET"] & desi_mask["BGS_ANY"]) != 0)
print(targs[:10]["BGS_TARGET"] != 0)


[ True False  True False False  True False False False False]
[ True False  True False False  True False False False False]

Bits representing targets for the Bright Galaxy Survey and Milky Way Survey can be manipulated in the same way as previous examples in this section. The relevant columns and masks are BGS_TARGET and bgs_mask, and MWS_TARGET and mws_mask respectively. For example:


In [134]:
from desitarget.targets import bgs_mask, mws_mask
bitnames = np.array(bgs_mask.names())  # ADM note the array conversion to help manipulation.
bitvals = [bgs_mask[name] for name in bitnames]
for targ in targs[:10]:
    w = np.where( (targ["BGS_TARGET"] & bitvals) != 0)[0]
    print(targ["BGS_TARGET"], bitnames[w])


131586 ['BGS_BRIGHT' 'BGS_BRIGHT_NORTH' 'BGS_BRIGHT_SOUTH']
0 []
65793 ['BGS_FAINT' 'BGS_FAINT_NORTH' 'BGS_FAINT_SOUTH']
0 []
0 []
65793 ['BGS_FAINT' 'BGS_FAINT_NORTH' 'BGS_FAINT_SOUTH']
0 []
0 []
0 []
0 []

Working with target files for CMX or SV

As noted in the previous section, Commissioning and SV have different bitmasks. Conveniently, commissioning and SV also have different _TARGET column names, allowing a user to easily distinguish which "flavor" of file they are using:

Main Survey files have the columns DESI_TARGET, BGS_TARGET and MWS_TARGET.

Commissioning files have the column CMX_TARGET.

SV files have the columns SV1_DESI_TARGET, SV1_BGS_TARGET and SV1_MWS_TARGET.

A convenient utility is desitarget.targets.main_cmx_or_sv which will use the differing column names to load the appropriate mask or masks. For example, using our Main Survey example file:


In [147]:
import os, fitsio
# ADM replace this with any directory you know of that holds targets.
targdir = "/project/projectdirs/desi/target/catalogs/examples"
# ADM replace this with the name of any target file.
targfile = 'targets.fits'
targfile = os.path.join(targdir, targfile)
targs = fitsio.read(targfile)
# ADM load the convenient utility and use it.
from desitarget.targets import main_cmx_or_sv
[desi_target, bgs_target, mws_target], [desi_mask, bgs_mask, mws_mask], surv = main_cmx_or_sv(targs)
print(desi_target, mws_target)


DESI_TARGET MWS_TARGET

In [148]:
print(surv)


main

In [149]:
print(bgs_mask)


bgs_mask:
  - [BGS_FAINT,        0, "BGS faint targets", {'obsconditions': 'BRIGHT|GRAY|DARK', 'priorities': {'UNOBS': 2000, 'MORE_ZWARN': 2000, 'MORE_ZGOOD': 1000, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0}, 'numobs': 1}]
  - [BGS_BRIGHT,       1, "BGS bright targets", {'obsconditions': 'BRIGHT', 'priorities': {'UNOBS': 2100, 'MORE_ZWARN': 2100, 'MORE_ZGOOD': 1000, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0}, 'numobs': 1}]
  - [BGS_WISE,         2, "BGS wise targets", {'obsconditions': 'BRIGHT', 'priorities': {'UNOBS': 2000, 'MORE_ZWARN': 2000, 'MORE_ZGOOD': 1000, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0}, 'numobs': 1}]
  - [BGS_FAINT_HIP,    3, "BGS faint targets at bright priorty", {'obsconditions': 'BRIGHT', 'priorities': {'UNOBS': 2100, 'MORE_ZWARN': 2100, 'MORE_ZGOOD': 1000, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0}, 'numobs': 1}]
  - [BGS_FAINT_NORTH,  8, "BGS faint cuts tuned for Bok/Mosaic", {'obsconditions': 'BRIGHT|GRAY|DARK', 'priorities': {'UNOBS': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0}, 'numobs': 0}]
  - [BGS_BRIGHT_NORTH,  9, "BGS bright cuts tuned for Bok/Mosaic", {'obsconditions': 'BRIGHT', 'priorities': {'UNOBS': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0}, 'numobs': 0}]
  - [BGS_WISE_NORTH,  10, "BGS WISE cuts tuned for Bok/Mosaic", {'obsconditions': 'BRIGHT', 'priorities': {'UNOBS': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0}, 'numobs': 0}]
  - [BGS_FAINT_SOUTH, 16, "BGS faint cuts tuned for DECam", {'obsconditions': 'BRIGHT|GRAY|DARK', 'priorities': {'UNOBS': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0}, 'numobs': 0}]
  - [BGS_BRIGHT_SOUTH, 17, "BGS bright cuts tuned for DECam", {'obsconditions': 'BRIGHT', 'priorities': {'UNOBS': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0}, 'numobs': 0}]
  - [BGS_WISE_SOUTH,  18, "BGS WISE cuts tuned for DECam", {'obsconditions': 'BRIGHT', 'priorities': {'UNOBS': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0}, 'numobs': 0}]

Let's see what would happen if our targets file was actually an SV file:


In [150]:
import numpy.lib.recfunctions as rfn
for col in [desi_target, bgs_target, mws_target]:
    sv1_targs = rfn.rename_fields(targs, {col: 'SV1_'+col})
[desi_target, bgs_target, mws_target], [desi_mask, bgs_mask, mws_mask], surv = main_cmx_or_sv(sv1_targs)
print(bgs_target, mws_target)


SV1_BGS_TARGET SV1_MWS_TARGET

In [151]:
print(surv)


sv1

In [152]:
print(desi_mask)


sv1_desi_mask:
  - [LRG,              0, "LRG", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 3200, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3200, 'MORE_ZGOOD': 3200}, 'numobs': 2}]
  - [ELG,              1, "ELG", {'obsconditions': 'DARK|GRAY', 'priorities': {'UNOBS': 3000, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3000, 'MORE_ZGOOD': 3000}, 'numobs': 1}]
  - [QSO,              2, "QSO", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 3400, 'MORE_ZGOOD': 3500, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3400}, 'numobs': 4}]
  - [LRG_INIT,         3, "LRG using initial optical and IR cuts", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 3200, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3200, 'MORE_ZGOOD': 3200}, 'numobs': 2}]
  - [LRG_LOWZ,         4, "LRG with a low-z extension", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 3200, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3200, 'MORE_ZGOOD': 3200}, 'numobs': 2}]
  - [LRG_HIGHZ,        5, "LRG with a high-z extenstion", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 3200, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3200, 'MORE_ZGOOD': 3200}, 'numobs': 2}]
  - [LRG_RELAX,        6, "LRG with a relaxed set of cuts", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 3200, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3200, 'MORE_ZGOOD': 3200}, 'numobs': 2}]
  - [LRG_SUPER,        7, "LRG that is a superset of other cuts", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 3200, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3200, 'MORE_ZGOOD': 3200}, 'numobs': 2}]
  - [ELG_FDR,          8, "ELG using FDR cuts", {'obsconditions': 'DARK|GRAY', 'priorities': {'UNOBS': 3000, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3000, 'MORE_ZGOOD': 3000}, 'numobs': 1}]
  - [ELG_FDR_FAINT,    9, "ELG using fainter FDR cuts", {'obsconditions': 'DARK|GRAY', 'priorities': {'UNOBS': 3000, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3000, 'MORE_ZGOOD': 3000}, 'numobs': 1}]
  - [ELG_RZ_BLUE,     10, "ELG blue extension in rz color", {'obsconditions': 'DARK|GRAY', 'priorities': {'UNOBS': 3000, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3000, 'MORE_ZGOOD': 3000}, 'numobs': 1}]
  - [ELG_RZ_RED,      11, "ELG red extension in rz color", {'obsconditions': 'DARK|GRAY', 'priorities': {'UNOBS': 3000, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3000, 'MORE_ZGOOD': 3000}, 'numobs': 1}]
  - [QSO_COLOR_4PASS, 12, "Low-z (tracer) QSO using color cuts", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 3400, 'MORE_ZGOOD': 3500, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3400}, 'numobs': 4}]
  - [QSO_RF_4PASS,    13, "Low-z (tracer) QSO using random forest", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 3400, 'MORE_ZGOOD': 3500, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3400}, 'numobs': 4}]
  - [QSO_COLOR_8PASS, 14, "High-z (Lyman-Alpha) QSO using color cuts", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 3400, 'MORE_ZGOOD': 3500, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3400}, 'numobs': 8}]
  - [QSO_RF_8PASS,    15, "High-z (Lyman-Alpha) QSO using random forest", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 3400, 'MORE_ZGOOD': 3500, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3400}, 'numobs': 8}]
  - [QSO_HZ_F,        16, "QSO at high-redshift and faint", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 3400, 'MORE_ZGOOD': 3500, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3400}, 'numobs': 4}]
  - [LRG_NORTH,       17, "LRG cuts tuned for Bok/Mosaic data", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0}, 'numobs': 0}]
  - [ELG_NORTH,       18, "ELG cuts tuned for Bok/Mosaic data", {'obsconditions': 'DARK|GRAY', 'priorities': {'UNOBS': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0}, 'numobs': 0}]
  - [QSO_NORTH,       19, "QSO cuts tuned for Bok/Mosaic data", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 3400, 'MORE_ZGOOD': 3500, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3400}, 'numobs': 0}]
  - [LRG_SOUTH,       20, "LRG cuts tuned for DECam data", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0}, 'numobs': 0}]
  - [ELG_SOUTH,       21, "ELG cuts tuned for DECam data", {'obsconditions': 'DARK|GRAY', 'priorities': {'UNOBS': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0}, 'numobs': 0}]
  - [QSO_SOUTH,       22, "QSO cuts tuned for DECam data", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 3400, 'MORE_ZGOOD': 3500, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3400}, 'numobs': 0}]
  - [LRG_INIT_NORTH,  23, "LRG using initial optical and IR cuts tuned for Bok/Mosaic", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0}, 'numobs': 0}]
  - [LRG_LOWZ_NORTH,  24, "LRG with a low-z extension tuned for Bok/Mosaic", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0}, 'numobs': 0}]
  - [LRG_HIGHZ_NORTH, 25, "LRG with a high-z extenstion tuned for Bok/Mosaic", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0}, 'numobs': 0}]
  - [LRG_RELAX_NORTH, 26, "LRG with a relaxed set of cuts tuned for Bok/Mosaic", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0}, 'numobs': 0}]
  - [LRG_SUPER_NORTH, 27, "LRG that is a superset of other cuts tuned for Bok/Mosaic", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0}, 'numobs': 0}]
  - [LRG_INIT_SOUTH,  28, "LRG using initial optical and IR cuts tuned for DECam", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0}, 'numobs': 0}]
  - [LRG_LOWZ_SOUTH,  29, "LRG with a low-z extension tuned for DECam", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0}, 'numobs': 0}]
  - [LRG_HIGHZ_SOUTH, 30, "LRG with a high-z extenstion tuned for DECam", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0}, 'numobs': 0}]
  - [LRG_RELAX_SOUTH, 31, "LRG with a relaxed set of cuts tuned for DECam", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0}, 'numobs': 0}]
  - [SKY,             32, "Blank sky locations", {'obsconditions': 'DARK|GRAY|BRIGHT|POOR|TWILIGHT12|TWILIGHT18', 'priorities': {}, 'numobs': -1}]
  - [STD_FAINT,       33, "Standard stars for dark/gray conditions", {'obsconditions': 'DARK|GRAY', 'priorities': {}, 'numobs': -1}]
  - [STD_WD,          34, "White Dwarf stars", {'obsconditions': 'DARK|GRAY|BRIGHT', 'priorities': {}, 'numobs': -1}]
  - [STD_BRIGHT,      35, "Standard stars for BRIGHT conditions", {'obsconditions': 'BRIGHT', 'priorities': {}, 'numobs': -1}]
  - [BAD_SKY,         36, "Blank sky locations that are imperfect but still useable", {'obsconditions': 'DARK|GRAY|BRIGHT|POOR|TWILIGHT12|TWILIGHT18', 'priorities': {'UNOBS': 0, 'OBS': 0, 'DONE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0, 'DONOTOBSERVE': 1}, 'numobs': 0}]
  - [LRG_SUPER_SOUTH, 37, "LRG that is a superset of other cuts tuned for DECam", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0}, 'numobs': 0}]
  - [ELG_FDR_NORTH,   38, "ELG using FDR cuts tuned for Bok/Mosaic", {'obsconditions': 'DARK|GRAY', 'priorities': {'UNOBS': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0}, 'numobs': 0}]
  - [ELG_FDR_FAINT_NORTH, 39, "ELG using fainter FDR cuts tuned for Bok/Mosaic", {'obsconditions': 'DARK|GRAY', 'priorities': {'UNOBS': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0}, 'numobs': 0}]
  - [ELG_RZ_BLUE_NORTH, 40, "ELG blue extension in rz color tuned for Bok/Mosaic", {'obsconditions': 'DARK|GRAY', 'priorities': {'UNOBS': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0}, 'numobs': 0}]
  - [ELG_RZ_RED_NORTH, 41, "ELG red extension in rz color tuned for Bok/Mosaic", {'obsconditions': 'DARK|GRAY', 'priorities': {'UNOBS': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0}, 'numobs': 0}]
  - [ELG_FDR_SOUTH,   42, "ELG using FDR cuts tuned for DECam", {'obsconditions': 'DARK|GRAY', 'priorities': {'UNOBS': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0}, 'numobs': 0}]
  - [ELG_FDR_FAINT_SOUTH, 43, "ELG using fainter FDR tuned for DECam", {'obsconditions': 'DARK|GRAY', 'priorities': {'UNOBS': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0}, 'numobs': 0}]
  - [ELG_RZ_BLUE_SOUTH, 44, "ELG blue extension in rz color tuned for DECam", {'obsconditions': 'DARK|GRAY', 'priorities': {'UNOBS': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0}, 'numobs': 0}]
  - [ELG_RZ_RED_SOUTH, 45, "ELG red extension in rz color tuned for DECam", {'obsconditions': 'DARK|GRAY', 'priorities': {'UNOBS': 0, 'DONE': 0, 'OBS': 0, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 0, 'MORE_ZGOOD': 0}, 'numobs': 0}]
  - [QSO_COLOR_4PASS_NORTH, 46, "Low-z (tracer) QSO using color cuts tuned for Bok/Mosaic", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 3400, 'MORE_ZGOOD': 3500, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3400}, 'numobs': 0}]
  - [QSO_RF_4PASS_NORTH, 47, "Low-z (tracer) QSO using random forest tuned for Bok/Mosaic", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 3400, 'MORE_ZGOOD': 3500, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3400}, 'numobs': 0}]
  - [QSO_COLOR_8PASS_NORTH, 48, "High-z (Lyman-Alpha) QSO using color cuts tuned for Bok/Mosaic", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 3400, 'MORE_ZGOOD': 3500, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3400}, 'numobs': 0}]
  - [NO_TARGET,       49, "No known target at this location", {'obsconditions': 'DARK|GRAY|BRIGHT|POOR|TWILIGHT12|TWILIGHT18', 'priorities': {}, 'numobs': -1}]
  - [BRIGHT_OBJECT,   50, "Known bright object to avoid", {'obsconditions': 'APOCALYPSE', 'priorities': {}, 'numobs': -1}]
  - [IN_BRIGHT_OBJECT, 51, "Too near a bright object; DO NOT OBSERVE", {'obsconditions': 'APOCALYPSE', 'priorities': {}, 'numobs': -1}]
  - [NEAR_BRIGHT_OBJECT, 52, "Near a bright object but ok to observe", {'obsconditions': 'DARK|GRAY|BRIGHT|POOR|TWILIGHT12|TWILIGHT18', 'priorities': {}, 'numobs': -1}]
  - [QSO_RF_8PASS_NORTH, 53, "High-z (Lyman-Alpha) QSO using random forest tuned for Bok/Mosaic", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 3400, 'MORE_ZGOOD': 3500, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3400}, 'numobs': 0}]
  - [QSO_HZ_F_NORTH,  54, "QSO at high-redshift and faint tuned for Bok/Mosaic", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 3400, 'MORE_ZGOOD': 3500, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3400}, 'numobs': 0}]
  - [QSO_COLOR_4PASS_SOUTH, 55, "Low-z (tracer) QSO using color cuts tuned for DECam", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 3400, 'MORE_ZGOOD': 3500, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3400}, 'numobs': 0}]
  - [QSO_RF_4PASS_SOUTH, 56, "Low-z (tracer) QSO using random forest tuned for DECam", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 3400, 'MORE_ZGOOD': 3500, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3400}, 'numobs': 0}]
  - [QSO_COLOR_8PASS_SOUTH, 57, "High-z (Lyman-Alpha) QSO using color cuts tuned for DECam", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 3400, 'MORE_ZGOOD': 3500, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3400}, 'numobs': 0}]
  - [QSO_RF_8PASS_SOUTH, 58, "High-z (Lyman-Alpha) QSO using random forest tuned for DECam", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 3400, 'MORE_ZGOOD': 3500, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3400}, 'numobs': 0}]
  - [QSO_HZ_F_SOUTH,  59, "QSO at high-redshift and faint tuned for DECam", {'obsconditions': 'DARK', 'priorities': {'UNOBS': 3400, 'MORE_ZGOOD': 3500, 'DONE': 2, 'OBS': 1, 'DONOTOBSERVE': 0, 'MORE_ZWARN': 3400}, 'numobs': 0}]
  - [BGS_ANY,         60, "Any BGS bit is set", {'obsconditions': 'BRIGHT', 'priorities': {}, 'numobs': -1}]
  - [MWS_ANY,         61, "Any MWS bit is set", {'obsconditions': 'BRIGHT', 'priorities': {}, 'numobs': -1}]
  - [SCND_ANY,        62, "Any secondary bit is set", {'obsconditions': 'DARK|GRAY|BRIGHT|POOR|TWILIGHT12|TWILIGHT18', 'priorities': {}, 'numobs': -1}]

An advanced example

As a challenge, let's try to find all quasar targets that are close to an LRG target using our example file of targets.

First, let's retrieve all LRG and QSO targets from our file.


In [153]:
from desitarget.targets import desi_mask
isLRG = (targs["DESI_TARGET"] & desi_mask["LRG"]) != 0
isQSO = (targs["DESI_TARGET"] & desi_mask["QSO"]) != 0
lrgs, qsos = targs[isLRG], targs[isQSO]

In [154]:
# ADM a sanity check.
for qso in qsos[:10]:
    print(desi_mask.names(qso["DESI_TARGET"]))


['ELG', 'QSO', 'ELG_NORTH', 'QSO_NORTH', 'ELG_SOUTH', 'QSO_SOUTH']
['QSO', 'QSO_NORTH', 'QSO_SOUTH']
['QSO', 'QSO_NORTH', 'QSO_SOUTH']
['QSO', 'QSO_NORTH', 'QSO_SOUTH']
['QSO', 'QSO_NORTH', 'QSO_SOUTH']
['QSO', 'QSO_NORTH', 'QSO_SOUTH']
['QSO', 'QSO_NORTH', 'QSO_SOUTH']
['QSO', 'QSO_NORTH', 'QSO_SOUTH']
['QSO', 'QSO_NORTH', 'QSO_SOUTH']
['QSO', 'QSO_NORTH', 'QSO_SOUTH']

We'll need the astropy spatial matching functions:


In [155]:
from astropy.coordinates import SkyCoord
from astropy import units as u

Convert the lrgs and quasars to SkyCoord objects:


In [156]:
clrgs = SkyCoord(lrgs["RA"], lrgs["DEC"], unit='degree')
cqsos = SkyCoord(qsos["RA"], qsos["DEC"], unit='degree')

Perform the match. Let's choose a radius of 1 arcminute:


In [157]:
matchrad = 20*u.arcsec
idlrgs, idqsos, sep, _ = cqsos.search_around_sky(clrgs, matchrad)

Finally, write out the matching lrgs and quasars, and the distance between them:


In [158]:
lrgmatch, qsomatch = lrgs[idlrgs], qsos[idqsos]
for i in range(len(lrgmatch)):
    print("LRG coordinates: {:.4f} deg, {:.4f} deg".format(lrgmatch[i]["RA"], lrgmatch[i]["DEC"]))
    print("QSO coordinates: {:.4f} deg, {:.4f} deg".format(qsomatch[i]["RA"], qsomatch[i]["DEC"]))
    print("Angular separation: {:.4f} arcsec".format(sep.value[i]*3600))


LRG coordinates: 338.9023 deg, -0.3676 deg
QSO coordinates: 338.9003 deg, -0.3627 deg
Angular separation: 18.8160 arcsec
LRG coordinates: 338.9433 deg, -0.3250 deg
QSO coordinates: 338.9396 deg, -0.3270 deg
Angular separation: 15.2783 arcsec

So, there are a couple of LRG targets within 20 arcseconds of a quasar target.