예제 #1
0
    def test_cmx_priorities(self):
        """Test that priority calculation can handle commissioning files.
        """
        t = self.targets.copy()
        z = self.zcat

        # ADM restructure the table to look like a commissioning table.
        t.rename_column('DESI_TARGET', 'CMX_TARGET')
        t.remove_column('BGS_TARGET')
        t.remove_column('MWS_TARGET')

        # - No targeting bits set is priority=0
        self.assertTrue(np.all(calc_priority(t, z, "GRAY|DARK") == 0))

        # ADM retrieve the cmx_mask.
        colnames, masks, _ = main_cmx_or_sv(t)
        cmx_mask = masks[0]

        # ADM test handling of unobserved SV0_BGS and SV0_MWS
        for name, obscon in [("SV0_BGS", "BRIGHT"), ("SV0_MWS", "POOR")]:
            t['CMX_TARGET'] = cmx_mask[name]
            self.assertTrue(
                np.all(
                    calc_priority(t, z, obscon) ==
                    cmx_mask[name].priorities['UNOBS']))

        # ADM done is Done, regardless of ZWARN.
        for name, obscon in [("SV0_BGS", "BRIGHT"), ("SV0_MWS", "POOR")]:
            t['CMX_TARGET'] = cmx_mask[name]
            t["PRIORITY_INIT"], t["NUMOBS_INIT"] = initial_priority_numobs(t)

            # APC: Use NUMOBS_INIT here to avoid hardcoding NOBS corresponding to "done".
            numobs_done = t['NUMOBS_INIT'][0]
            z['NUMOBS'] = [0, numobs_done, numobs_done]
            z['ZWARN'] = [1, 1, 0]
            p = make_mtl(t, obscon, zcat=z)["PRIORITY"]

            self.assertEqual(p[0], cmx_mask[name].priorities['UNOBS'])
            self.assertEqual(p[1], cmx_mask[name].priorities['DONE'])
            self.assertEqual(p[2], cmx_mask[name].priorities['DONE'])

        # BGS ZGOOD targets always have lower priority than MWS targets that
        # are not DONE.
        lowest_bgs_priority_zgood = cmx_mask['SV0_BGS'].priorities[
            'MORE_ZGOOD']

        lowest_mws_priority_unobs = cmx_mask['SV0_MWS'].priorities['UNOBS']
        lowest_mws_priority_zwarn = cmx_mask['SV0_MWS'].priorities[
            'MORE_ZWARN']
        lowest_mws_priority_zgood = cmx_mask['SV0_MWS'].priorities[
            'MORE_ZGOOD']

        lowest_mws_priority = min(lowest_mws_priority_unobs,
                                  lowest_mws_priority_zwarn,
                                  lowest_mws_priority_zgood)

        self.assertLess(lowest_bgs_priority_zgood, lowest_mws_priority)
예제 #2
0
 def test_bright_mask(self):
     t = self.targets
     t['DESI_TARGET'][0] = desi_mask.ELG
     t['DESI_TARGET'][1] = desi_mask.ELG | desi_mask.NEAR_BRIGHT_OBJECT
     t['DESI_TARGET'][2] = desi_mask.ELG | desi_mask.IN_BRIGHT_OBJECT
     p = calc_priority(t)
     self.assertEqual(
         p[0], p[1],
         "NEAR_BRIGHT_OBJECT shouldn't impact priority but {} != {}".format(
             p[0], p[1]))
     self.assertEqual(p[2], -1, "IN_BRIGHT_OBJECT priority not -1")
예제 #3
0
 def test_priorities(self):
     t = self.targets
     #- No targeting bits set is priority=0
     self.assertTrue(np.all(calc_priority(t) == 0))
     
     #- test QSO > LRG > ELG
     t['DESI_TARGET'] = desi_mask.ELG
     self.assertTrue(np.all(calc_priority(t) == desi_mask.ELG.priorities['UNOBS']))
     t['DESI_TARGET'] |= desi_mask.LRG
     self.assertTrue(np.all(calc_priority(t) == desi_mask.LRG.priorities['UNOBS']))
     t['DESI_TARGET'] |= desi_mask.QSO
     self.assertTrue(np.all(calc_priority(t) == desi_mask.QSO.priorities['UNOBS']))
     
     #- different states -> different priorities
     t['DESI_TARGET'] = desi_mask.BGS_ANY
     t['BGS_TARGET'] |= bgs_mask.BGS_FAINT
     t['NUMOBS'] = [0, 1, 1]
     t['ZWARN'] = [1, 1, 0]
     p = calc_priority(t)
             
     self.assertEqual(p[0], bgs_mask.BGS_FAINT.priorities['UNOBS'])
     self.assertEqual(p[1], bgs_mask.BGS_FAINT.priorities['MORE_ZWARN'])
     self.assertEqual(p[2], bgs_mask.BGS_FAINT.priorities['MORE_ZGOOD'])
     ### BGS_FAINT: {UNOBS: 2000, MORE_ZWARN: 2200, MORE_ZGOOD: 2300}
     
     #- Done is Done, regardless of ZWARN
     t['DESI_TARGET'] = desi_mask.BGS_ANY
     t['BGS_TARGET'] = bgs_mask.BGS_BRIGHT  #- only one obs needed
     t['NUMOBS'] = [0, 1, 1]
     t['ZWARN'] = [1, 1, 0]
     p = calc_priority(t)        
             
     self.assertEqual(p[0], bgs_mask.BGS_BRIGHT.priorities['UNOBS'])
     self.assertEqual(p[1], bgs_mask.BGS_BRIGHT.priorities['DONE'])
     self.assertEqual(p[2], bgs_mask.BGS_BRIGHT.priorities['DONE'])
예제 #4
0
def make_mtl(targets, zcat=None, trim=True):
    '''
    Adds NUMOBS, PRIORITY, and GRAYLAYER columns to a targets table
    
    Args:
        targets : Table with columns TARGETID, DESI_TARGET

    Optional:
        zcat : redshift catalog table with columns TARGETID, NUMOBS, Z, ZWARN
        trim: if True (default), don't include targets that don't need
            any more observations.  If False, include every input target.
    
    Returns:
        MTL Table with targets columns plus
          * NUMOBS_MORE - number of additional observations requested
          * PRIORITY - target priority (larger number = higher priority)
          * GRAYLAYER - can this be observed during gray time?

    TODO:
        Check if input targets is ever altered (ist shouldn't...)
    '''
    n = len(targets)
    targets = Table(targets)
    if zcat is not None:
        ztargets = join(targets, zcat, keys='TARGETID', join_type='outer')
        if ztargets.masked:
            unobs = ztargets['NUMOBS'].mask
            ztargets['NUMOBS'][unobs] = 0
    else:
        ztargets = targets.copy()
        ztargets['NUMOBS'] = np.zeros(n, dtype=np.int32)
        ztargets['Z'] = -1 * np.ones(n, dtype=np.float32)
        ztargets['ZWARN'] = -1  * np.ones(n, dtype=np.int32)
    
    ztargets['NUMOBS_MORE'] = np.maximum(0, calc_numobs(ztargets) - ztargets['NUMOBS'])

    mtl = targets.copy()
    mtl['NUMOBS_MORE'] = ztargets['NUMOBS_MORE']
    mtl['PRIORITY'] = calc_priority(ztargets)

    #- ELGs can be observed during gray time
    graylayer = np.zeros(n, dtype='i4')
    iselg = (mtl['DESI_TARGET'] & desi_mask.ELG) != 0
    graylayer[iselg] = 1
    mtl['GRAYLAYER'] = graylayer

    if trim:
        notdone = mtl['NUMOBS_MORE'] > 0
        mtl = mtl[notdone]
    
    return mtl
예제 #5
0
def make_mtl(targets, zcat=None, trim=False):
    """Adds NUMOBS, PRIORITY, and OBSCONDITIONS columns to a targets table.

    Parameters
    ----------
    targets : :class:`~numpy.array` or `~astropy.table.Table`
        A numpy rec array or astropy Table with at least the columns
        ``TARGETID``, ``DESI_TARGET``, ``NUMOBS_INIT``, ``PRIORITY_INIT``.
        or the corresponding columns for SV or commissioning.
    zcat : :class:`~astropy.table.Table`, optional
        Redshift catalog table with columns ``TARGETID``, ``NUMOBS``, ``Z``,
        ``ZWARN``.
    trim : :class:`bool`, optional
        If ``True`` (default), don't include targets that don't need
        any more observations.  If ``False``, include every input target.

    Returns
    -------
    :class:`~astropy.table.Table`
        MTL Table with targets columns plus:

        * NUMOBS_MORE    - number of additional observations requested
        * PRIORITY       - target priority (larger number = higher priority)
        * OBSCONDITIONS  - replaces old GRAYLAYER
    """
    # ADM set up the default logger.
    from desiutil.log import get_logger
    log = get_logger()

    # ADM determine whether the input targets are main survey, cmx or SV.
    colnames, masks, survey = main_cmx_or_sv(targets)
    # ADM set the first column to be the "desitarget" column
    desi_target, desi_mask = colnames[0], masks[0]

    # Trim targets from zcat that aren't in original targets table
    if zcat is not None:
        ok = np.in1d(zcat['TARGETID'], targets['TARGETID'])
        num_extra = np.count_nonzero(~ok)
        if num_extra > 0:
            log.warning("Ignoring {} zcat entries that aren't "
                        "in the input target list".format(num_extra))
            zcat = zcat[ok]

    n = len(targets)
    # ADM if the input target columns were incorrectly called NUMOBS or PRIORITY
    # ADM rename them to NUMOBS_INIT or PRIORITY_INIT.
    # ADM Note that the syntax is slightly different for a Table.
    for name in ['NUMOBS', 'PRIORITY']:
        if isinstance(targets, Table):
            try:
                targets.rename_column(name, name + '_INIT')
            except KeyError:
                pass
        else:
            targets.dtype.names = [
                name + '_INIT' if col == name else col
                for col in targets.dtype.names
            ]

    # ADM if a redshift catalog was passed, order it to match the input targets
    # ADM catalog on 'TARGETID'.
    if zcat is not None:
        # ADM there might be a quicker way to do this?
        # ADM set up a dictionary of the indexes of each target id.
        d = dict(tuple(zip(targets["TARGETID"], np.arange(n))))
        # ADM loop through the zcat and look-up the index in the dictionary.
        zmatcher = np.array([d[tid] for tid in zcat["TARGETID"]])
        ztargets = zcat
        if ztargets.masked:
            unobs = ztargets['NUMOBS'].mask
            ztargets['NUMOBS'][unobs] = 0
            unobsz = ztargets['Z'].mask
            ztargets['Z'][unobsz] = -1
            unobszw = ztargets['ZWARN'].mask
            ztargets['ZWARN'][unobszw] = -1
    else:
        ztargets = Table()
        ztargets['TARGETID'] = targets['TARGETID']
        ztargets['NUMOBS'] = np.zeros(n, dtype=np.int32)
        ztargets['Z'] = -1 * np.ones(n, dtype=np.float32)
        ztargets['ZWARN'] = -1 * np.ones(n, dtype=np.int32)
        # ADM if zcat wasn't passed, there is a one-to-one correspondence
        # ADM between the targets and the zcat.
        zmatcher = np.arange(n)

    # ADM extract just the targets that match the input zcat.
    targets_zmatcher = targets[zmatcher]

    # ADM use passed value of NUMOBS_INIT instead of calling the memory-heavy calc_numobs.
    # ztargets['NUMOBS_MORE'] = np.maximum(0, calc_numobs(ztargets) - ztargets['NUMOBS'])
    ztargets['NUMOBS_MORE'] = np.maximum(
        0, targets_zmatcher['NUMOBS_INIT'] - ztargets['NUMOBS'])

    # ADM we need a minor hack to ensure that BGS targets are observed once (and only once)
    # ADM every time, regardless of how many times they've previously been observed.
    # ADM I've turned this off for commissioning. Not sure if we'll keep it in general.
    if survey != 'cmx':
        ii = targets_zmatcher[desi_target] & desi_mask.BGS_ANY > 0
        ztargets['NUMOBS_MORE'][ii] = 1

    # ADM assign priorities, note that only things in the zcat can have changed priorities.
    # ADM anything else will be assigned PRIORITY_INIT, below.
    priority = calc_priority(targets_zmatcher, ztargets)

    # If priority went to 0==DONOTOBSERVE or 1==OBS or 2==DONE, then NUMOBS_MORE should also be 0.
    # ## mtl['NUMOBS_MORE'] = ztargets['NUMOBS_MORE']
    ii = (priority <= 2)
    log.info(
        '{:d} of {:d} targets have priority zero, setting N_obs=0.'.format(
            np.sum(ii), n))
    ztargets['NUMOBS_MORE'][ii] = 0

    # - Set the OBSCONDITIONS mask for each target bit.
    obscon = set_obsconditions(targets)

    # ADM set up the output mtl table.
    mtl = Table(targets)
    mtl.meta['EXTNAME'] = 'MTL'
    # ADM any target that wasn't matched to the ZCAT should retain its
    # ADM original (INIT) value of PRIORITY and NUMOBS.
    mtl['NUMOBS_MORE'] = mtl['NUMOBS_INIT']
    mtl['PRIORITY'] = mtl['PRIORITY_INIT']
    # ADM now populate the new mtl columns with the updated information.
    mtl['OBSCONDITIONS'] = obscon
    mtl['PRIORITY'][zmatcher] = priority
    mtl['NUMOBS_MORE'][zmatcher] = ztargets['NUMOBS_MORE']

    # Filter out any targets marked as done.
    if trim:
        notdone = mtl['NUMOBS_MORE'] > 0
        log.info('{:d} of {:d} targets are done, trimming these'.format(
            len(mtl) - np.sum(notdone), len(mtl)))
        mtl = mtl[notdone]

    # Filtering can reset the fill_value, which is just wrong wrong wrong
    # See https://github.com/astropy/astropy/issues/4707
    # and https://github.com/astropy/astropy/issues/4708
    mtl['NUMOBS_MORE'].fill_value = -1

    return mtl
예제 #6
0
    def test_priorities(self):
        """Test that priorities are set correctly for both the main survey and SV.
        """
        # ADM loop through once for SV and once for the main survey.
        for prefix in ["", "SV1_"]:
            t = self.targets.copy()
            z = self.zcat.copy()

            main_names = ['DESI_TARGET', 'BGS_TARGET', 'MWS_TARGET']
            for name in main_names:
                t.rename_column(name, prefix + name)

            # ADM retrieve the mask and column names for this survey flavor.
            colnames, masks, _ = main_cmx_or_sv(t)
            desi_target, bgs_target, mws_target = colnames
            desi_mask, bgs_mask, mws_mask = masks

            # - No targeting bits set is priority=0
            self.assertTrue(np.all(calc_priority(t, z) == 0))

            # - test QSO > (LRG_1PASS | LRG_2PASS) > ELG
            t[desi_target] = desi_mask.ELG
            self.assertTrue(
                np.all(
                    calc_priority(t, z) == desi_mask.ELG.priorities['UNOBS']))
            t[desi_target] |= desi_mask.LRG_1PASS
            self.assertTrue(
                np.all(
                    calc_priority(t, z) == desi_mask.LRG.priorities['UNOBS']))
            t[desi_target] |= desi_mask.LRG_2PASS
            self.assertTrue(
                np.all(
                    calc_priority(t, z) == desi_mask.LRG.priorities['UNOBS']))
            t[desi_target] |= desi_mask.QSO
            self.assertTrue(
                np.all(
                    calc_priority(t, z) == desi_mask.QSO.priorities['UNOBS']))

            # - different states -> different priorities

            # - Done is Done, regardless of ZWARN.
            t[desi_target] = desi_mask.ELG
            t["PRIORITY_INIT"], t["NUMOBS_INIT"] = initial_priority_numobs(t)
            z['NUMOBS'] = [0, 1, 1]
            z['ZWARN'] = [1, 1, 0]
            p = make_mtl(t, z)["PRIORITY"]

            self.assertEqual(p[0], desi_mask.ELG.priorities['UNOBS'])
            self.assertEqual(p[1], desi_mask.ELG.priorities['DONE'])
            self.assertEqual(p[2], desi_mask.ELG.priorities['DONE'])

            # - BGS FAINT targets are never DONE, only MORE_ZGOOD.
            t[desi_target] = desi_mask.BGS_ANY
            t[bgs_target] = bgs_mask.BGS_FAINT
            t["PRIORITY_INIT"], t["NUMOBS_INIT"] = initial_priority_numobs(t)
            z['NUMOBS'] = [0, 1, 1]
            z['ZWARN'] = [1, 1, 0]
            p = make_mtl(t, z)["PRIORITY"]

            self.assertEqual(p[0], bgs_mask.BGS_FAINT.priorities['UNOBS'])
            self.assertEqual(p[1], bgs_mask.BGS_FAINT.priorities['MORE_ZWARN'])
            self.assertEqual(p[2], bgs_mask.BGS_FAINT.priorities['MORE_ZGOOD'])
            # BGS_FAINT: {UNOBS: 2000, MORE_ZWARN: 2000, MORE_ZGOOD: 1000, DONE: 2, OBS: 1, DONOTOBSERVE: 0}

            # - BGS BRIGHT targets are never DONE, only MORE_ZGOOD.
            t[desi_target] = desi_mask.BGS_ANY
            t[bgs_target] = bgs_mask.BGS_BRIGHT
            t["PRIORITY_INIT"], t["NUMOBS_INIT"] = initial_priority_numobs(t)
            z['NUMOBS'] = [0, 1, 1]
            z['ZWARN'] = [1, 1, 0]
            p = make_mtl(t, z)["PRIORITY"]

            self.assertEqual(p[0], bgs_mask.BGS_BRIGHT.priorities['UNOBS'])
            self.assertEqual(p[1],
                             bgs_mask.BGS_BRIGHT.priorities['MORE_ZWARN'])
            self.assertEqual(p[2],
                             bgs_mask.BGS_BRIGHT.priorities['MORE_ZGOOD'])
            # BGS_BRIGHT: {UNOBS: 2100, MORE_ZWARN: 2100, MORE_ZGOOD: 1000, DONE: 2, OBS: 1, DONOTOBSERVE: 0}

            # BGS targets are NEVER done even after 100 observations
            t[desi_target] = desi_mask.BGS_ANY
            t[bgs_target] = bgs_mask.BGS_BRIGHT
            t["PRIORITY_INIT"], t["NUMOBS_INIT"] = initial_priority_numobs(t)
            z['NUMOBS'] = [0, 100, 100]
            z['ZWARN'] = [1, 1, 0]
            p = calc_priority(t, z)

            self.assertEqual(p[0], bgs_mask.BGS_BRIGHT.priorities['UNOBS'])
            self.assertEqual(p[1],
                             bgs_mask.BGS_BRIGHT.priorities['MORE_ZWARN'])
            self.assertEqual(p[2],
                             bgs_mask.BGS_BRIGHT.priorities['MORE_ZGOOD'])

            # BGS ZGOOD targets always have lower priority than MWS targets that
            # are not DONE.
            # ADM first discard N/S informational bits from bitmask as these
            # ADM should never trump the other bits.
            bgs_names = [
                name for name in bgs_mask.names()
                if 'NORTH' not in name and 'SOUTH' not in name
            ]
            mws_names = [
                name for name in mws_mask.names()
                if 'NORTH' not in name and 'SOUTH' not in name
            ]

            lowest_bgs_priority_zgood = min(
                [bgs_mask[n].priorities['MORE_ZGOOD'] for n in bgs_names])

            lowest_mws_priority_unobs = min(
                [mws_mask[n].priorities['UNOBS'] for n in mws_names])
            lowest_mws_priority_zwarn = min(
                [mws_mask[n].priorities['MORE_ZWARN'] for n in mws_names])
            lowest_mws_priority_zgood = min(
                [mws_mask[n].priorities['MORE_ZGOOD'] for n in mws_names])

            lowest_mws_priority = min(lowest_mws_priority_unobs,
                                      lowest_mws_priority_zwarn,
                                      lowest_mws_priority_zgood)

            self.assertLess(lowest_bgs_priority_zgood, lowest_mws_priority)
예제 #7
0
파일: merge.py 프로젝트: forero/mtl
def create_mtl(target_file, specresults_file, output_file):
    """
    Consolidates a Merged Target List file.
    """
    # input basic data
    # targets = fitsio.read(target_file, 1, upper=True)
    # specresults = fitsio.read(specresults_file, 1, upper=True)

    targets = Table.read(target_file, format='fits')
    specresults = Table.read(specresults_file, format='fits')

    n_points = len(targets['TARGETID'])
    n_spec = len(specresults['TARGETID'])
    print("{} objects in the input MTL file".format(n_points))
    print("{} objects in the zcat file".format(n_spec))

    # structure for output data
    type_table = [
        ('TARGETID', '>i8'), 
        ('BRICKNAME', '|S8'),
        ('RA', '>f4'), 
        ('DEC', '>f4'),
        ('NUMOBS', '>i4'), 
        ('PRIORITY', '>i4'),
        ('LASTPASS', '>i4'),
        ('DESI_TARGET', '>i8'), 
        ('BGS_TARGET', '>i8'), 
        ('MWS_TARGET', '>i8')
    ]

    # loops over the targets looking for:
    # - number of observations performed on the target
    # - a definite targetflag


    num_obs = np.zeros(n_points, dtype='int')
    priority = np.zeros(n_points, dtype='int')
    required_numobs = targets['NUMOBS']
    iiobs = np.in1d(targets['TARGETID'], specresults['TARGETID'])

#    import IPython
#    IPython.embed()

    # update the priority, 
    # TEMPORARY: We don't take into account the targetstate. This should be changed).
    priority = calc_priority(targets)
    
    id_results = 0
    for i in range(n_points):
        if iiobs[i]:
            n_obs_done = specresults['NUMOBS'][id_results]
            id_results = id_results + 1
        else:
            n_obs_done = 0
        num_obs[i] = numobs_needed(required_numobs[i], n_obs_done)

    data = np.ndarray(shape=(n_points), dtype=type_table)    
    data['TARGETID'] = targets['TARGETID']
    data['RA'] = targets['RA']
    data['DEC'] = targets['DEC']
    data['BRICKNAME'] = targets['BRICKNAME']
    data['DESI_TARGET'] = targets['DESI_TARGET']
    data['BGS_TARGET'] = targets['BGS_TARGET']
    data['MWS_TARGET'] = targets['MWS_TARGET']
    data['LASTPASS'] = targets['LASTPASS']
    data['NUMOBS'] = num_obs
    data['PRIORITY'] = priority

    #- Create header to include versions, etc.
    hdr = fitsio.FITSHDR()
    hdr['DEPNAM00'] = 'mtl'
    hdr.add_record(dict(name='DEPVER00', value=mtl.__version__, comment='mtl.__version__'))
    hdr['DEPNAM01'] = 'mtl-git'
    hdr.add_record(dict(name='DEPVAL01', value=mtl.gitversion(), comment='git revision'))    

    fitsio.write(output_file, data, extname='MTL', header=hdr, clobber=True)    
    print('wrote {} items to MTL file'.format(n_points))

    #- TEMPORARY: fiberassign needs ASCII not FITS
    #- read it back in an write out an ascii table
    # t = Table.read(output_file, format='fits')
    #text_output = output_file.replace('.fits', '.txt')
    #assert text_output != output_file
    #t.write(text_output, format='ascii.commented_header')

    return 
예제 #8
0
파일: mtl.py 프로젝트: jinyiY/desitarget
def make_mtl(targets, obscon, zcat=None, trim=False, scnd=None):
    """Adds NUMOBS, PRIORITY, and OBSCONDITIONS columns to a targets table.

    Parameters
    ----------
    targets : :class:`~numpy.array` or `~astropy.table.Table`
        A numpy rec array or astropy Table with at least the columns
        ``TARGETID``, ``DESI_TARGET``, ``NUMOBS_INIT``, ``PRIORITY_INIT``.
        or the corresponding columns for SV or commissioning.
    obscon : :class:`str`
        A combination of strings that are in the desitarget bitmask yaml
        file (specifically in `desitarget.targetmask.obsconditions`), e.g.
        "DARK|GRAY". Governs the behavior of how priorities are set based
        on "obsconditions" in the desitarget bitmask yaml file.
    zcat : :class:`~astropy.table.Table`, optional
        Redshift catalog table with columns ``TARGETID``, ``NUMOBS``, ``Z``,
        ``ZWARN``.
    trim : :class:`bool`, optional
        If ``True`` (default), don't include targets that don't need
        any more observations.  If ``False``, include every input target.
    scnd : :class:`~numpy.array`, `~astropy.table.Table`, optional
        A set of secondary targets associated with the `targets`. As with
        the `target` must include at least ``TARGETID``, ``NUMOBS_INIT``,
        ``PRIORITY_INIT`` or the corresponding SV columns.
        The secondary targets will be padded to have the same columns
        as the targets, and concatenated with them.

    Returns
    -------
    :class:`~astropy.table.Table`
        MTL Table with targets columns plus:

        * NUMOBS_MORE    - number of additional observations requested
        * PRIORITY       - target priority (larger number = higher priority)
        * OBSCONDITIONS  - replaces old GRAYLAYER
    """
    start = time()
    # ADM set up the default logger.
    from desiutil.log import get_logger
    log = get_logger()

    # ADM if secondaries were passed, concatenate them with the targets.
    if scnd is not None:
        nrows = len(scnd)
        log.info(
            'Pad {} primary targets with {} secondaries...t={:.1f}s'.format(
                len(targets), nrows,
                time() - start))
        padit = np.zeros(nrows, dtype=targets.dtype)
        sharedcols = set(targets.dtype.names).intersection(
            set(scnd.dtype.names))
        for col in sharedcols:
            padit[col] = scnd[col]
        targets = np.concatenate([targets, padit])
        # APC Propagate a flag on which targets came from scnd
        is_scnd = np.repeat(False, len(targets))
        is_scnd[-nrows:] = True
        log.info('Done with padding...t={:.1f}s'.format(time() - start))

    # ADM determine whether the input targets are main survey, cmx or SV.
    colnames, masks, survey = main_cmx_or_sv(targets)
    # ADM set the first column to be the "desitarget" column
    desi_target, desi_mask = colnames[0], masks[0]

    # Trim targets from zcat that aren't in original targets table
    if zcat is not None:
        ok = np.in1d(zcat['TARGETID'], targets['TARGETID'])
        num_extra = np.count_nonzero(~ok)
        if num_extra > 0:
            log.warning("Ignoring {} zcat entries that aren't "
                        "in the input target list".format(num_extra))
            zcat = zcat[ok]

    n = len(targets)
    # ADM if the input target columns were incorrectly called NUMOBS or PRIORITY
    # ADM rename them to NUMOBS_INIT or PRIORITY_INIT.
    # ADM Note that the syntax is slightly different for a Table.
    for name in ['NUMOBS', 'PRIORITY']:
        if isinstance(targets, Table):
            try:
                targets.rename_column(name, name + '_INIT')
            except KeyError:
                pass
        else:
            targets.dtype.names = [
                name + '_INIT' if col == name else col
                for col in targets.dtype.names
            ]

    # ADM if a redshift catalog was passed, order it to match the input targets
    # ADM catalog on 'TARGETID'.
    if zcat is not None:
        # ADM there might be a quicker way to do this?
        # ADM set up a dictionary of the indexes of each target id.
        d = dict(tuple(zip(targets["TARGETID"], np.arange(n))))
        # ADM loop through the zcat and look-up the index in the dictionary.
        zmatcher = np.array([d[tid] for tid in zcat["TARGETID"]])
        ztargets = zcat
        if ztargets.masked:
            unobs = ztargets['NUMOBS'].mask
            ztargets['NUMOBS'][unobs] = 0
            unobsz = ztargets['Z'].mask
            ztargets['Z'][unobsz] = -1
            unobszw = ztargets['ZWARN'].mask
            ztargets['ZWARN'][unobszw] = -1
    else:
        ztargets = Table()
        ztargets['TARGETID'] = targets['TARGETID']
        ztargets['NUMOBS'] = np.zeros(n, dtype=np.int32)
        ztargets['Z'] = -1 * np.ones(n, dtype=np.float32)
        ztargets['ZWARN'] = -1 * np.ones(n, dtype=np.int32)
        # ADM if zcat wasn't passed, there is a one-to-one correspondence
        # ADM between the targets and the zcat.
        zmatcher = np.arange(n)

    # ADM extract just the targets that match the input zcat.
    targets_zmatcher = targets[zmatcher]

    # ADM use passed value of NUMOBS_INIT instead of calling the memory-heavy calc_numobs.
    # ztargets['NUMOBS_MORE'] = np.maximum(0, calc_numobs(ztargets) - ztargets['NUMOBS'])
    ztargets['NUMOBS_MORE'] = np.maximum(
        0, targets_zmatcher['NUMOBS_INIT'] - ztargets['NUMOBS'])

    # ADM need a minor hack to ensure BGS targets are observed once
    # ADM (and only once) every time during the BRIGHT survey, regardless
    # ADM of how often they've previously been observed. I've turned this
    # ADM off for commissioning. Not sure if we'll keep it in general.
    if survey != 'cmx':
        # ADM only if we're considering bright survey conditions.
        if (obsconditions.mask(obscon) & obsconditions.mask("BRIGHT")) != 0:
            ii = targets_zmatcher[desi_target] & desi_mask.BGS_ANY > 0
            ztargets['NUMOBS_MORE'][ii] = 1
    if survey == 'main':
        # If the object is confirmed to be a tracer QSO, then don't request more observations
        if (obsconditions.mask(obscon) & obsconditions.mask("DARK")) != 0:
            if zcat is not None:
                ii = ztargets['SPECTYPE'] == 'QSO'
                ii &= (ztargets['ZWARN'] == 0)
                ii &= (ztargets['Z'] < 2.1)
                ii &= (ztargets['NUMOBS'] > 0)
                ztargets['NUMOBS_MORE'][ii] = 0

    # ADM assign priorities, note that only things in the zcat can have changed priorities.
    # ADM anything else will be assigned PRIORITY_INIT, below.
    priority = calc_priority(targets_zmatcher, ztargets, obscon)

    # If priority went to 0==DONOTOBSERVE or 1==OBS or 2==DONE, then NUMOBS_MORE should also be 0.
    # ## mtl['NUMOBS_MORE'] = ztargets['NUMOBS_MORE']
    ii = (priority <= 2)
    log.info(
        '{:d} of {:d} targets have priority zero, setting N_obs=0.'.format(
            np.sum(ii), n))
    ztargets['NUMOBS_MORE'][ii] = 0

    # - Set the OBSCONDITIONS mask for each target bit.
    obsconmask = set_obsconditions(targets)

    # APC obsconmask will now be incorrect for secondary-only targets. Fix this
    # APC using the mask on secondary targets.
    if scnd is not None:
        obsconmask[is_scnd] = set_obsconditions(targets[is_scnd], scnd=True)

    # ADM set up the output mtl table.
    mtl = Table(targets)
    mtl.meta['EXTNAME'] = 'MTL'
    # ADM any target that wasn't matched to the ZCAT should retain its
    # ADM original (INIT) value of PRIORITY and NUMOBS.
    mtl['NUMOBS_MORE'] = mtl['NUMOBS_INIT']
    mtl['PRIORITY'] = mtl['PRIORITY_INIT']
    # ADM now populate the new mtl columns with the updated information.
    mtl['OBSCONDITIONS'] = obsconmask
    mtl['PRIORITY'][zmatcher] = priority
    mtl['NUMOBS_MORE'][zmatcher] = ztargets['NUMOBS_MORE']

    # Filter out any targets marked as done.
    if trim:
        notdone = mtl['NUMOBS_MORE'] > 0
        log.info('{:d} of {:d} targets are done, trimming these'.format(
            len(mtl) - np.sum(notdone), len(mtl)))
        mtl = mtl[notdone]

    # Filtering can reset the fill_value, which is just wrong wrong wrong
    # See https://github.com/astropy/astropy/issues/4707
    # and https://github.com/astropy/astropy/issues/4708
    mtl['NUMOBS_MORE'].fill_value = -1

    log.info('Done...t={:.1f}s'.format(time() - start))

    return mtl
예제 #9
0
def make_mtl(targets, obscon, zcat=None, scnd=None,
             trim=False, trimcols=False, trimtozcat=False):
    """Adds fiberassign and zcat columns to a targets table.

    Parameters
    ----------
    targets : :class:`~numpy.array` or `~astropy.table.Table`
        A numpy rec array or astropy Table with at least the columns
        ``TARGETID``, ``DESI_TARGET``, ``NUMOBS_INIT``, ``PRIORITY_INIT``.
        or the corresponding columns for SV or commissioning.
    obscon : :class:`str`
        A combination of strings that are in the desitarget bitmask yaml
        file (specifically in `desitarget.targetmask.obsconditions`), e.g.
        "DARK|GRAY". Governs the behavior of how priorities are set based
        on "obsconditions" in the desitarget bitmask yaml file.
    zcat : :class:`~astropy.table.Table`, optional
        Redshift catalog table with columns ``TARGETID``, ``NUMOBS``, ``Z``,
        ``ZWARN``.
    scnd : :class:`~numpy.array`, `~astropy.table.Table`, optional
        A set of secondary targets associated with the `targets`. As with
        the `target` must include at least ``TARGETID``, ``NUMOBS_INIT``,
        ``PRIORITY_INIT`` or the corresponding SV columns.
        The secondary targets will be padded to have the same columns
        as the targets, and concatenated with them.
    trim : :class:`bool`, optional
        If ``True`` (default), don't include targets that don't need
        any more observations.  If ``False``, include every input target.
    trimcols : :class:`bool`, optional, defaults to ``False``
        Only pass through columns in `targets` that are actually needed
        for fiberassign (see `desitarget.mtl.mtldatamodel`).
    trimtozcat : :class:`bool`, optional, defaults to ``False``
        Only return targets that have been UPDATED (i.e. the targets with
        a match in `zcat`). Returns all targets if `zcat` is ``None``.

    Returns
    -------
    :class:`~astropy.table.Table`
        MTL Table with targets columns plus:

        * NUMOBS_MORE    - number of additional observations requested
        * PRIORITY       - target priority (larger number = higher priority)
        * TARGET_STATE   - the observing state that corresponds to PRIORITY
        * OBSCONDITIONS  - replaces old GRAYLAYER
        * TIMESTAMP      - time that (this) make_mtl() function was run
        * VERSION        - version of desitarget used to run make_mtl()
    """
    start = time()
    # ADM set up the default logger.
    from desiutil.log import get_logger
    log = get_logger()

    # ADM if trimcols was passed, reduce input target columns to minimal.
    if trimcols:
        mtldm = switch_main_cmx_or_sv(mtldatamodel, targets)
        cullcols = list(set(targets.dtype.names) - set(mtldm.dtype.names))
        if isinstance(targets, Table):
            targets.remove_columns(cullcols)
        else:
            targets = rfn.drop_fields(targets, cullcols)

    # ADM determine whether the input targets are main survey, cmx or SV.
    colnames, masks, survey = main_cmx_or_sv(targets, scnd=True)
    # ADM set the first column to be the "desitarget" column
    desi_target, desi_mask = colnames[0], masks[0]
    scnd_target = colnames[-1]

    # ADM if secondaries were passed, concatenate them with the targets.
    if scnd is not None:
        nrows = len(scnd)
        log.info('Pad {} primary targets with {} secondaries...t={:.1f}s'.format(
            len(targets), nrows, time()-start))
        padit = np.zeros(nrows, dtype=targets.dtype)
        sharedcols = set(targets.dtype.names).intersection(set(scnd.dtype.names))
        for col in sharedcols:
            padit[col] = scnd[col]
        targets = np.concatenate([targets, padit])
        # APC Propagate a flag on which targets came from scnd
        is_scnd = np.repeat(False, len(targets))
        is_scnd[-nrows:] = True
        log.info('Done with padding...t={:.1f}s'.format(time()-start))

    # Trim targets from zcat that aren't in original targets table.
    if zcat is not None:
        ok = np.in1d(zcat['TARGETID'], targets['TARGETID'])
        num_extra = np.count_nonzero(~ok)
        if num_extra > 0:
            log.warning("Ignoring {} zcat entries that aren't "
                        "in the input target list".format(num_extra))
            zcat = zcat[ok]

    n = len(targets)
    # ADM if a redshift catalog was passed, order it to match the input targets
    # ADM catalog on 'TARGETID'.
    if zcat is not None:
        # ADM there might be a quicker way to do this?
        # ADM set up a dictionary of the indexes of each target id.
        d = dict(tuple(zip(targets["TARGETID"], np.arange(n))))
        # ADM loop through the zcat and look-up the index in the dictionary.
        zmatcher = np.array([d[tid] for tid in zcat["TARGETID"]])
        ztargets = zcat
        if ztargets.masked:
            unobs = ztargets['NUMOBS'].mask
            ztargets['NUMOBS'][unobs] = 0
            unobsz = ztargets['Z'].mask
            ztargets['Z'][unobsz] = -1
            unobszw = ztargets['ZWARN'].mask
            ztargets['ZWARN'][unobszw] = -1
    else:
        ztargets = Table()
        ztargets['TARGETID'] = targets['TARGETID']
        ztargets['NUMOBS'] = np.zeros(n, dtype=np.int32)
        ztargets['Z'] = -1 * np.ones(n, dtype=np.float32)
        ztargets['ZWARN'] = -1 * np.ones(n, dtype=np.int32)
        # ADM if zcat wasn't passed, there is a one-to-one correspondence
        # ADM between the targets and the zcat.
        zmatcher = np.arange(n)

    # ADM extract just the targets that match the input zcat.
    targets_zmatcher = targets[zmatcher]

    # ADM update the number of observations for the targets.
    ztargets['NUMOBS_MORE'] = calc_numobs_more(targets_zmatcher, ztargets, obscon)

    # ADM assign priorities. Only things in the zcat can have changed
    # ADM priorities. Anything else is assigned PRIORITY_INIT, below.
    priority, target_state = calc_priority(
        targets_zmatcher, ztargets, obscon, state=True)

    # If priority went to 0==DONOTOBSERVE or 1==OBS or 2==DONE, then
    # NUMOBS_MORE should also be 0.
    # ## mtl['NUMOBS_MORE'] = ztargets['NUMOBS_MORE']
    ii = (priority <= 2)
    log.info('{:d} of {:d} targets have priority zero, setting N_obs=0.'.format(
        np.sum(ii), n))
    ztargets['NUMOBS_MORE'][ii] = 0

    # - Set the OBSCONDITIONS mask for each target bit.
    obsconmask = set_obsconditions(targets)

    # APC obsconmask will now be incorrect for secondary-only targets. Fix this
    # APC using the mask on secondary targets.
    if scnd is not None:
        obsconmask[is_scnd] = set_obsconditions(targets[is_scnd], scnd=True)

    # ADM set up the output mtl table.
    mtl = Table(targets)
    mtl.meta['EXTNAME'] = 'MTL'

    # ADM add a placeholder for the secondary bit-mask, if it isn't there.
    if scnd_target not in mtl.dtype.names:
        mtl[scnd_target] = np.zeros(len(mtl),
                                    dtype=mtldatamodel["SCND_TARGET"].dtype)

    # ADM initialize columns to avoid zero-length/missing/format errors.
    zcols = ["NUMOBS_MORE", "NUMOBS", "Z", "ZWARN"]
    for col in zcols + ["TARGET_STATE", "TIMESTAMP", "VERSION"]:
        mtl[col] = np.empty(len(mtl), dtype=mtldatamodel[col].dtype)

    # ADM any target that wasn't matched to the ZCAT should retain its
    # ADM original (INIT) value of PRIORITY and NUMOBS.
    mtl['NUMOBS_MORE'] = mtl['NUMOBS_INIT']
    mtl['PRIORITY'] = mtl['PRIORITY_INIT']
    mtl['TARGET_STATE'] = "UNOBS"
    # ADM add the time and version of the desitarget code that was run.
    utc = datetime.utcnow().isoformat(timespec='seconds')
    mtl["TIMESTAMP"] = utc
    mtl["VERSION"] = dt_version

    # ADM now populate the new mtl columns with the updated information.
    mtl['OBSCONDITIONS'] = obsconmask
    mtl['PRIORITY'][zmatcher] = priority
    mtl['TARGET_STATE'][zmatcher] = target_state
    for col in zcols:
        mtl[col][zmatcher] = ztargets[col]

    # Filter out any targets marked as done.
    if trim:
        notdone = mtl['NUMOBS_MORE'] > 0
        log.info('{:d} of {:d} targets are done, trimming these'.format(
            len(mtl) - np.sum(notdone), len(mtl))
        )
        mtl = mtl[notdone]

    # Filtering can reset the fill_value, which is just wrong wrong wrong
    # See https://github.com/astropy/astropy/issues/4707
    # and https://github.com/astropy/astropy/issues/4708
    mtl['NUMOBS_MORE'].fill_value = -1

    # ADM assert the data model is complete.
    # ADM turning this off for now, useful for testing.
#    mtltypes = [mtl[i].dtype.type for i in mtl.dtype.names]
#    mtldmtypes = [mtldm[i].dtype.type for i in mtl.dtype.names]
#    assert set(mtl.dtype.names) == set(mtldm.dtype.names)
#    assert mtltypes == mtldmtypes

    log.info('Done...t={:.1f}s'.format(time()-start))

    if trimtozcat:
        return mtl[zmatcher]
    return mtl
예제 #10
0
    def test_priorities(self):
        """Test that priorities are set correctly for both the main survey and SV.
        """
        # ADM loop through once for SV and once for the main survey.
        for prefix in ["", "SV1_"]:
            t = self.targets.copy()
            z = self.zcat.copy()

            main_names = ['DESI_TARGET', 'BGS_TARGET', 'MWS_TARGET']
            for name in main_names:
                t.rename_column(name, prefix + name)

            # ADM retrieve the mask and column names for this survey flavor.
            colnames, masks, _ = main_cmx_or_sv(t)
            desi_target, bgs_target, mws_target = colnames
            desi_mask, bgs_mask, mws_mask = masks

            # - No targeting bits set is priority=0
            self.assertTrue(np.all(calc_priority(t, z, "BRIGHT") == 0))

            # ADM test QSO > LRG > ELG for main survey and SV.
            t[desi_target] = desi_mask.ELG
            self.assertTrue(
                np.all(
                    calc_priority(t, z, "GRAY|DARK") ==
                    desi_mask.ELG.priorities['UNOBS']))
            t[desi_target] |= desi_mask.LRG
            self.assertTrue(
                np.all(
                    calc_priority(t, z, "GRAY|DARK") ==
                    desi_mask.LRG.priorities['UNOBS']))
            t[desi_target] |= desi_mask.QSO
            self.assertTrue(
                np.all(
                    calc_priority(t, z, "GRAY|DARK") ==
                    desi_mask.QSO.priorities['UNOBS']))

            # - different states -> different priorities
            # - Done is Done, regardless of ZWARN.
            t[desi_target] = desi_mask.ELG
            t["PRIORITY_INIT"], t["NUMOBS_INIT"] = initial_priority_numobs(t)
            z['NUMOBS'] = [0, 1, 1]
            z['ZWARN'] = [1, 1, 0]
            p = make_mtl(t, "GRAY|DARK", zcat=z)["PRIORITY"]

            self.assertEqual(p[0], desi_mask.ELG.priorities['UNOBS'])
            self.assertEqual(p[1], desi_mask.ELG.priorities['DONE'])
            self.assertEqual(p[2], desi_mask.ELG.priorities['DONE'])

            # ADM In BRIGHT conditions BGS FAINT targets are
            # ADM never DONE, only MORE_ZGOOD.
            t[desi_target] = desi_mask.BGS_ANY
            t[bgs_target] = bgs_mask.BGS_FAINT
            t["PRIORITY_INIT"], t["NUMOBS_INIT"] = initial_priority_numobs(t)
            z['NUMOBS'] = [0, 1, 1]
            z['ZWARN'] = [1, 1, 0]
            p = make_mtl(t, "BRIGHT", zcat=z)["PRIORITY"]

            self.assertEqual(p[0], bgs_mask.BGS_FAINT.priorities['UNOBS'])
            self.assertEqual(p[1], bgs_mask.BGS_FAINT.priorities['MORE_ZWARN'])
            self.assertEqual(p[2], bgs_mask.BGS_FAINT.priorities['MORE_ZGOOD'])
            # BGS_FAINT: {UNOBS: 2000, MORE_ZWARN: 2000, MORE_ZGOOD: 1000, DONE: 2, OBS: 1, DONOTOBSERVE: 0}

            # ADM but in DARK conditions, BGS_FAINT should behave as
            # ADM for other target classes.
            z = self.zcat.copy()
            z['NUMOBS'] = [0, 1, 1]
            z['ZWARN'] = [1, 1, 0]
            p = make_mtl(t, "DARK|GRAY", zcat=z)["PRIORITY"]

            self.assertEqual(p[0], bgs_mask.BGS_FAINT.priorities['UNOBS'])
            self.assertEqual(p[1], bgs_mask.BGS_FAINT.priorities['DONE'])
            self.assertEqual(p[2], bgs_mask.BGS_FAINT.priorities['DONE'])

            # ADM In BRIGHT conditions BGS BRIGHT targets are
            # ADM never DONE, only MORE_ZGOOD.
            t[desi_target] = desi_mask.BGS_ANY
            t[bgs_target] = bgs_mask.BGS_BRIGHT
            t["PRIORITY_INIT"], t["NUMOBS_INIT"] = initial_priority_numobs(t)
            z['NUMOBS'] = [0, 1, 1]
            z['ZWARN'] = [1, 1, 0]
            p = make_mtl(t, "BRIGHT", zcat=z)["PRIORITY"]

            self.assertEqual(p[0], bgs_mask.BGS_BRIGHT.priorities['UNOBS'])
            self.assertEqual(p[1],
                             bgs_mask.BGS_BRIGHT.priorities['MORE_ZWARN'])
            self.assertEqual(p[2],
                             bgs_mask.BGS_BRIGHT.priorities['MORE_ZGOOD'])
            # BGS_BRIGHT: {UNOBS: 2100, MORE_ZWARN: 2100, MORE_ZGOOD: 1000, DONE: 2, OBS: 1, DONOTOBSERVE: 0}

            # ADM In BRIGHT conditions BGS targets are
            # ADM NEVER done even after 100 observations
            t[desi_target] = desi_mask.BGS_ANY
            t[bgs_target] = bgs_mask.BGS_BRIGHT
            t["PRIORITY_INIT"], t["NUMOBS_INIT"] = initial_priority_numobs(t)
            z['NUMOBS'] = [0, 100, 100]
            z['ZWARN'] = [1, 1, 0]
            p = calc_priority(t, z, "BRIGHT")

            self.assertEqual(p[0], bgs_mask.BGS_BRIGHT.priorities['UNOBS'])
            self.assertEqual(p[1],
                             bgs_mask.BGS_BRIGHT.priorities['MORE_ZWARN'])
            self.assertEqual(p[2],
                             bgs_mask.BGS_BRIGHT.priorities['MORE_ZGOOD'])

            # BGS ZGOOD targets always have lower priority than MWS targets that
            # are not DONE. Exempting the MWS "BACKUP" targets.
            # ADM first discard N/S informational bits from bitmask as these
            # ADM should never trump the other bits.
            bgs_names = [
                name for name in bgs_mask.names()
                if 'NORTH' not in name and 'SOUTH' not in name
            ]
            mws_names = [
                name for name in mws_mask.names() if 'NORTH' not in name
                and 'SOUTH' not in name and 'BACKUP' not in name
            ]

            lowest_mws_priority_unobs = [
                mws_mask[n].priorities['UNOBS'] for n in mws_names
            ]

            lowest_bgs_priority_zgood = np.min(
                [bgs_mask[n].priorities['MORE_ZGOOD'] for n in bgs_names])

            # ADM MORE_ZGOOD and MORE_ZWARN are only meaningful if a
            # ADM target class requests more than 1 observation (except
            # ADM for BGS, which has a numobs=infinity exception)
            lowest_mws_priority_zwarn = [
                mws_mask[n].priorities['MORE_ZWARN'] for n in mws_names
                if mws_mask[n].numobs > 1
            ]
            lowest_mws_priority_zgood = [
                mws_mask[n].priorities['MORE_ZGOOD'] for n in mws_names
                if mws_mask[n].numobs > 1
            ]

            lowest_mws_priority = np.min(
                np.concatenate([
                    lowest_mws_priority_unobs, lowest_mws_priority_zwarn,
                    lowest_mws_priority_zgood
                ]))

            self.assertLess(lowest_bgs_priority_zgood, lowest_mws_priority)
예제 #11
0
def create_mtl(target_file, specresults_file, output_file):
    """
    Consolidates a Merged Target List file.
    """
    # input basic data
    # targets = fitsio.read(target_file, 1, upper=True)
    # specresults = fitsio.read(specresults_file, 1, upper=True)

    targets = Table.read(target_file, format='fits')
    specresults = Table.read(specresults_file, format='fits')

    n_points = len(targets['TARGETID'])
    n_spec = len(specresults['TARGETID'])
    print("{} objects in the input MTL file".format(n_points))
    print("{} objects in the zcat file".format(n_spec))

    # structure for output data
    type_table = [('TARGETID', '>i8'), ('BRICKNAME', '|S8'), ('RA', '>f4'),
                  ('DEC', '>f4'), ('NUMOBS', '>i4'), ('PRIORITY', '>i4'),
                  ('LASTPASS', '>i4'), ('DESI_TARGET', '>i8'),
                  ('BGS_TARGET', '>i8'), ('MWS_TARGET', '>i8')]

    # loops over the targets looking for:
    # - number of observations performed on the target
    # - a definite targetflag

    num_obs = np.zeros(n_points, dtype='int')
    priority = np.zeros(n_points, dtype='int')
    required_numobs = targets['NUMOBS']
    iiobs = np.in1d(targets['TARGETID'], specresults['TARGETID'])

    #    import IPython
    #    IPython.embed()

    # update the priority,
    # TEMPORARY: We don't take into account the targetstate. This should be changed).
    priority = calc_priority(targets)

    id_results = 0
    for i in range(n_points):
        if iiobs[i]:
            n_obs_done = specresults['NUMOBS'][id_results]
            id_results = id_results + 1
        else:
            n_obs_done = 0
        num_obs[i] = numobs_needed(required_numobs[i], n_obs_done)

    data = np.ndarray(shape=(n_points), dtype=type_table)
    data['TARGETID'] = targets['TARGETID']
    data['RA'] = targets['RA']
    data['DEC'] = targets['DEC']
    data['BRICKNAME'] = targets['BRICKNAME']
    data['DESI_TARGET'] = targets['DESI_TARGET']
    data['BGS_TARGET'] = targets['BGS_TARGET']
    data['MWS_TARGET'] = targets['MWS_TARGET']
    data['LASTPASS'] = targets['LASTPASS']
    data['NUMOBS'] = num_obs
    data['PRIORITY'] = priority

    #- Create header to include versions, etc.
    hdr = fitsio.FITSHDR()
    hdr['DEPNAM00'] = 'mtl'
    hdr.add_record(
        dict(name='DEPVER00', value=mtl.__version__,
             comment='mtl.__version__'))
    hdr['DEPNAM01'] = 'mtl-git'
    hdr.add_record(
        dict(name='DEPVAL01', value=mtl.gitversion(), comment='git revision'))

    fitsio.write(output_file, data, extname='MTL', header=hdr, clobber=True)
    print('wrote {} items to MTL file'.format(n_points))

    #- TEMPORARY: fiberassign needs ASCII not FITS
    #- read it back in an write out an ascii table
    # t = Table.read(output_file, format='fits')
    #text_output = output_file.replace('.fits', '.txt')
    #assert text_output != output_file
    #t.write(text_output, format='ascii.commented_header')

    return
예제 #12
0
    def test_priorities(self):
        t = self.targets
        #- No targeting bits set is priority=0
        self.assertTrue(np.all(calc_priority(t) == 0))

        #- test QSO > LRG > ELG
        t['DESI_TARGET'] = desi_mask.ELG
        self.assertTrue(
            np.all(calc_priority(t) == desi_mask.ELG.priorities['UNOBS']))
        t['DESI_TARGET'] |= desi_mask.LRG
        self.assertTrue(
            np.all(calc_priority(t) == desi_mask.LRG.priorities['UNOBS']))
        t['DESI_TARGET'] |= desi_mask.QSO
        self.assertTrue(
            np.all(calc_priority(t) == desi_mask.QSO.priorities['UNOBS']))

        #- different states -> different priorities

        #- Done is Done, regardless of ZWARN.
        t['DESI_TARGET'] = desi_mask.ELG
        t['NUMOBS'] = [0, 1, 1]
        t['ZWARN'] = [1, 1, 0]
        p = calc_priority(t)

        self.assertEqual(p[0], desi_mask.ELG.priorities['UNOBS'])
        self.assertEqual(p[1], desi_mask.ELG.priorities['DONE'])
        self.assertEqual(p[2], desi_mask.ELG.priorities['DONE'])

        #- BGS FAINT targets are never DONE, only MORE_ZGOOD.
        t['DESI_TARGET'] = desi_mask.BGS_ANY
        t['BGS_TARGET'] = bgs_mask.BGS_FAINT
        t['NUMOBS'] = [0, 1, 1]
        t['ZWARN'] = [1, 1, 0]
        p = calc_priority(t)

        self.assertEqual(p[0], bgs_mask.BGS_FAINT.priorities['UNOBS'])
        self.assertEqual(p[1], bgs_mask.BGS_FAINT.priorities['MORE_ZWARN'])
        self.assertEqual(p[2], bgs_mask.BGS_FAINT.priorities['MORE_ZGOOD'])
        ### BGS_FAINT: {UNOBS: 2000, MORE_ZWARN: 2000, MORE_ZGOOD: 1000, DONE: 2, OBS: 1, DONOTOBSERVE: 0}

        #- BGS BRIGHT targets are never DONE, only MORE_ZGOOD.
        t['DESI_TARGET'] = desi_mask.BGS_ANY
        t['BGS_TARGET'] = bgs_mask.BGS_BRIGHT
        t['NUMOBS'] = [0, 1, 1]
        t['ZWARN'] = [1, 1, 0]
        p = calc_priority(t)

        self.assertEqual(p[0], bgs_mask.BGS_BRIGHT.priorities['UNOBS'])
        self.assertEqual(p[1], bgs_mask.BGS_BRIGHT.priorities['MORE_ZWARN'])
        self.assertEqual(p[2], bgs_mask.BGS_BRIGHT.priorities['MORE_ZGOOD'])
        ### BGS_BRIGHT: {UNOBS: 2100, MORE_ZWARN: 2100, MORE_ZGOOD: 1000, DONE: 2, OBS: 1, DONOTOBSERVE: 0}

        # BGS targets are NEVER done even after 100 observations
        t['DESI_TARGET'] = desi_mask.BGS_ANY
        t['BGS_TARGET'] = bgs_mask.BGS_BRIGHT
        t['NUMOBS'] = [0, 100, 100]
        t['ZWARN'] = [1, 1, 0]
        p = calc_priority(t)

        self.assertEqual(p[0], bgs_mask.BGS_BRIGHT.priorities['UNOBS'])
        self.assertEqual(p[1], bgs_mask.BGS_BRIGHT.priorities['MORE_ZWARN'])
        self.assertEqual(p[2], bgs_mask.BGS_BRIGHT.priorities['MORE_ZGOOD'])

        # BGS ZGOOD targets always have lower priority than MWS targets that
        # are not DONE.
        lowest_bgs_priority_zgood = min(
            [bgs_mask[n].priorities['MORE_ZGOOD'] for n in bgs_mask.names()])

        lowest_mws_priority_unobs = min(
            [mws_mask[n].priorities['UNOBS'] for n in mws_mask.names()])
        lowest_mws_priority_zwarn = min(
            [mws_mask[n].priorities['MORE_ZWARN'] for n in mws_mask.names()])
        lowest_mws_priority_zgood = min(
            [mws_mask[n].priorities['MORE_ZGOOD'] for n in mws_mask.names()])

        lowest_mws_priority = min(lowest_mws_priority_unobs,
                                  lowest_mws_priority_zwarn,
                                  lowest_mws_priority_zgood)

        self.assertLess(lowest_bgs_priority_zgood, lowest_mws_priority)