def decode_targetid(targetid): """break a DESI TARGETID into its constituent parts. Parameters ---------- :class:`int` or :class:`~numpy.ndarray` The TARGETID for DESI, encoded according to the bits listed in :meth:`desitarget.targetid_mask`. Returns ------- :class:`int` or :class:`~numpy.ndarray` The OBJID from Legacy Surveys imaging or the row within a Gaia HEALPixel file in $GAIA_DIR/healpix if `gaia` is not ``None``. :class:`int` or :class:`~numpy.ndarray` The BRICKID from Legacy Surveys imaging. or the Gaia HEALPixel chunk number for files in $GAIA_DIR/healpix if `gaia` is not ``None``. :class:`int` or :class:`~numpy.ndarray` The RELEASE from Legacy Surveys imaging. Or, if < 1000, the secondary target class bit flag number from 'data/targetmask.yaml'. Or, if < 1000 and `sky` is not ``None``, the HEALPixel processing number for SUPP_SKIES. :class:`int` or :class:`~numpy.ndarray` 1 if this object is a mock object (generated from mocks, not from real survey data), 0 otherwise :class:`int` or :class:`~numpy.ndarray` 1 if this object is a blank sky object, 0 otherwise :class:`int` or :class:`~numpy.ndarray` The Gaia Data Release number (e.g. will be 2 for Gaia DR2). A value of 1 does NOT mean DR1. Rather it has the specific meaning of a DESI first-light commissioning target. Notes ----- - if a 1-D array is passed, then an integer is returned. Otherwise an array is returned. - see also `DocDB 2348`_. """ # ADM the names of the bits with RESERVED removed. bitnames = targetid_mask.names() if "RESERVED" in bitnames: bitnames.remove("RESERVED") # ADM retrieve each value by left-shifting by the number of bits # ADM that comprise the value, to the left-end of the value, and # ADM then right-shifting to the right-end. outputs = [] for bitname in bitnames: bitnum = targetid_mask[bitname].bitnum val = (targetid & (2**targetid_mask[bitname].nbits - 1 << targetid_mask[bitname].bitnum)) >> bitnum outputs.append(val) return outputs
def encode_targetid(objid=None, brickid=None, release=None, mock=None, sky=None, gaiadr=None): """Create the DESI TARGETID from input source and imaging info. Parameters ---------- objid : :class:`int` or :class:`~numpy.ndarray`, optional The OBJID from Legacy Surveys imaging or the row within a Gaia HEALPixel file in $GAIA_DIR/healpix if `gaia` is not ``None``. brickid : :class:`int` or :class:`~numpy.ndarray`, optional The BRICKID from Legacy Surveys imaging. or the Gaia HEALPixel chunk number for files in $GAIA_DIR/healpix if `gaia` is not ``None``. release : :class:`int` or :class:`~numpy.ndarray`, optional The RELEASE from Legacy Surveys imaging. Or, if < 1000, the secondary target class bit flag number from 'data/targetmask.yaml'. Or, if < 1000 and `sky` is not ``None``, the HEALPixel processing number for SUPP_SKIES. mock : :class:`int` or :class:`~numpy.ndarray`, optional 1 if this object is a mock object (generated from mocks, not from real survey data), 0 otherwise sky : :class:`int` or :class:`~numpy.ndarray`, optional 1 if this object is a blank sky object, 0 otherwise gaiadr : :class:`int` or :class:`~numpy.ndarray`, optional The Gaia Data Release number (e.g. send 2 for Gaia DR2). A value of 1 does NOT mean DR1. Rather it has the specific meaning of a DESI first-light commissioning target. Returns ------- :class:`int` or `~numpy.ndarray` The TARGETID for DESI, encoded according to the bits listed in :meth:`desitarget.targetid_mask`. If an integer is passed, then an integer is returned, otherwise an array is returned. Notes ----- - Has maximum flexibility so that mixes of integers and arrays can be passed, in case some value like BRICKID or SKY is the same for a set of objects. Consider, e.g.: print( targets.decode_targetid( targets.encode_targetid(objid=np.array([234,12]), brickid=np.array([234,12]), release=4000, sky=[1,0])) ) (array([234,12]), array([234,12]), array([4000,4000]), array([0,0]), array([1,0])) - See also `DocDB 2348`_. """ # ADM a flag that tracks whether the main inputs were integers. intpassed = True # ADM the names of the bits with RESERVED removed. bitnames = targetid_mask.names() if "RESERVED" in bitnames: bitnames.remove("RESERVED") # ADM determine the length of passed values that aren't None. # ADM default to an integer (length 1). nobjs = 1 inputs = [objid, brickid, release, mock, sky, gaiadr] goodpar = [param is not None for param in inputs] firstgoodpar = np.where(goodpar)[0][0] if isinstance(inputs[firstgoodpar], np.ndarray): nobjs = len(inputs[firstgoodpar]) intpassed = False # ADM set parameters that weren't passed to zerod arrays # ADM set integers that were passed to at least 1D arrays for i, param in enumerate(inputs): if param is None: inputs[i] = np.zeros(nobjs, dtype='int64') else: inputs[i] = np.atleast_1d(param) # ADM check passed parameters don't exceed their bit-allowance. for param, bitname in zip(inputs, bitnames): if not np.all(param < 2**targetid_mask[bitname].nbits): msg = 'Invalid range when making targetid: {} '.format(bitname) msg += 'cannot exceed {}'.format(2**targetid_mask[bitname].nbits - 1) log.critical(msg) raise IOError(msg) # ADM set up targetid as an array of 64-bit integers. targetid = np.zeros(nobjs, ('int64')) # ADM populate TARGETID. Shift to type integer 64 to avoid casting. for param, bitname in zip(inputs, bitnames): targetid |= param.astype('int64') << targetid_mask[bitname].bitnum # ADM if the main inputs were integers, return an integer. if intpassed: return targetid[0] return targetid