Example #1
0
def report_survey_overlaps(tiledata):
    """
    """
    is_overlap = survey_overlaps(tiledata)
    print('{:d} fibers with both MWS and non-MWS target bits:'.format(
        is_overlap.sum()))

    udesi, udesi_count = np.unique(tiledata['DESI_TARGET'][is_overlap],
                                   return_counts=True)

    overlap_lines = list()
    for (_desi, _c) in zip(udesi, udesi_count):
        names = desi_mask.names(_desi)
        names.remove('MWS_ANY')
        desi_str = ' & '.join(names)

        _ = tiledata['DESI_TARGET'][is_overlap] == _desi
        mws_bits = np.unique(tiledata['MWS_TARGET'][is_overlap][_])

        mws_str = list()
        for _ in mws_bits:
            if _ in util.mws_bits_to_name:
                mws_str.append(util.mws_bits_to_name[_])
        mws_str = ' | '.join(mws_str)

        line = ' {:30s} {:4d} {:s}'.format(desi_str, _c, mws_str)
        overlap_lines.append(line)

    for line in (sorted(overlap_lines)):
        print(line)

    return
Example #2
0
def default_main_sciencemask():
    """Returns default mask of bits for science targets in main survey.
    """
    sciencemask = 0
    sciencemask |= desi_mask["LRG"].mask
    sciencemask |= desi_mask["ELG"].mask
    sciencemask |= desi_mask["QSO"].mask
    sciencemask |= desi_mask["BGS_ANY"].mask
    sciencemask |= desi_mask["MWS_ANY"].mask
    if "SCND_ANY" in desi_mask.names():
        sciencemask |= desi_mask["SCND_ANY"].mask
    else:
        sciencemask |= desi_mask["SECONDARY_ANY"].mask
    return sciencemask
Example #3
0
    def _update_info_div(self):
        '''Update the text div with information about the current target'''
        fibermap = self.spectra.fibermap[self.ispec]
        zb = self.zbest[self.izbest]

        info = list()
        info.append('<table>')
        info.append('<tr><th>TargetID</th><td>{}</td></tr>'.format(
            zb['TARGETID']))
        info.append('<tr><th>DESI_TARGET</th><td>{0}</td></tr>'.format(
            ' '.join(desi_mask.names(fibermap['DESI_TARGET']))))
        info.append('<tr><th>BGS_TARGET</th><td>{0}</td></tr>'.format(' '.join(
            bgs_mask.names(fibermap['BGS_TARGET']))))
        info.append('<tr><th>MWS_TARGET</th><td>{0}</td></tr>'.format(' '.join(
            mws_mask.names(fibermap['MWS_TARGET']))))
        info.append('</table>')

        self.info_div.text = '\n'.join(info)
Example #4
0
def print_numobs_stats(truth, targets, zcat):
    print('Target distributions')
    #- truth and targets are row-matched, so directly add columns instead of join
    for colname in targets.colnames:
        if colname not in truth.colnames:
            truth[colname] = targets[colname]

    xcat = join(zcat, truth, keys='TARGETID')

    for times_observed in range(1,5):
        print('\t Fraction (number) with exactly {} observations'.format(times_observed))
        ii = (xcat['NUMOBS']==times_observed)
        c = Counter(xcat['DESI_TARGET'][ii])

        total = np.sum(list(c.values()))
        for k in c:
            print("\t\t {}: {} ({} total)".format(desi_mask.names(k), c[k]/total, c[k]))
    return
Example #5
0
def print_numobs_stats(truth, targets, zcat):
    print('Target distributions')
    #- truth and targets are row-matched, so directly add columns instead of join
    for colname in targets.colnames:
        if colname not in truth.colnames:
            truth[colname] = targets[colname]

    xcat = join(zcat, truth, keys='TARGETID')

    for times_observed in range(1,5):
        print('\t Fraction (number) with exactly {} observations'.format(times_observed))
        ii = (xcat['NUMOBS']==times_observed)
        c = Counter(xcat['DESI_TARGET'][ii])

        total = np.sum(list(c.values()))
        for k in c:
            print("\t\t {}: {} ({} total)".format(desi_mask.names(k), c[k]/total, c[k]))
    return
Example #6
0
def fibermap_new2old(fibermap):
    '''Converts new format fibermap into old format fibermap

    Args:
        fibermap: new-format fibermap table (e.g. with FLUX_G column)

    Returns:
        old format fibermap (e.g. with MAG column)

    Note: this is a transitional convenience function to allow us to
    simulate new format fibermaps while still running code that expects
    the old format.  After all code has been converted to use the new
    format, this will be removed.
    '''
    from desiutil.brick import Bricks
    from desitarget.targetmask import desi_mask

    brickmap = Bricks()
    fm = fibermap.copy()
    n = len(fm)

    isMWS = (fm['DESI_TARGET'] & desi_mask.MWS_ANY) != 0
    fm['OBJTYPE'][isMWS] = 'MWS_STAR'
    isBGS = (fm['DESI_TARGET'] & desi_mask.BGS_ANY) != 0
    fm['OBJTYPE'][isBGS] = 'BGS'

    stdmask = 0
    for name in [
            'STD', 'STD_FSTAR', 'STD_WD', 'STD_FAINT', 'STD_FAINT_BEST',
            'STD_BRIGHT', 'STD_BRIGHT_BEST'
    ]:
        if name in desi_mask.names():
            stdmask |= desi_mask[name]

    isSTD = (fm['DESI_TARGET'] & stdmask) != 0
    fm['OBJTYPE'][isSTD] = 'STD'

    isELG = (fm['DESI_TARGET'] & desi_mask.ELG) != 0
    fm['OBJTYPE'][isELG] = 'ELG'
    isLRG = (fm['DESI_TARGET'] & desi_mask.LRG) != 0
    fm['OBJTYPE'][isLRG] = 'LRG'
    isQSO = (fm['DESI_TARGET'] & desi_mask.QSO) != 0
    fm['OBJTYPE'][isQSO] = 'QSO'

    if ('FLAVOR' in fm.meta):
        if fm.meta['FLAVOR'] == 'arc':
            fm['OBJTYPE'] = 'ARC'
        elif fm.meta['FLAVOR'] == 'flat':
            fm['OBJTYPE'] = 'FLAT'

    fm.rename_column('TARGET_RA', 'RA_TARGET')
    fm.rename_column('TARGET_DEC', 'DEC_TARGET')

    fm['BRICKNAME'] = brickmap.brickname(fm['RA_TARGET'], fm['DEC_TARGET'])
    fm['TARGETCAT'] = np.full(n, 'UNKNOWN', dtype=(str, 20))

    fm['MAG'] = np.zeros((n, 5), dtype='f4')
    fm['MAG'][:, 0] = 22.5 - 2.5 * np.log10(fm['FLUX_G'])
    fm['MAG'][:, 1] = 22.5 - 2.5 * np.log10(fm['FLUX_R'])
    fm['MAG'][:, 2] = 22.5 - 2.5 * np.log10(fm['FLUX_Z'])
    fm['MAG'][:, 3] = 22.5 - 2.5 * np.log10(fm['FLUX_W1'])
    fm['MAG'][:, 4] = 22.5 - 2.5 * np.log10(fm['FLUX_W2'])

    fm['FILTER'] = np.zeros((n, 5), dtype=(str, 10))
    fm['FILTER'][:, 0] = 'DECAM_G'
    fm['FILTER'][:, 1] = 'DECAM_R'
    fm['FILTER'][:, 2] = 'DECAM_Z'
    fm['FILTER'][:, 3] = 'WISE_W1'
    fm['FILTER'][:, 4] = 'WISE_W2'

    fm['POSITIONER'] = fm['LOCATION'].astype('i8')
    fm.rename_column('LAMBDA_REF', 'LAMBDAREF')

    fm.rename_column('FIBER_RA', 'RA_OBS')
    fm.rename_column('FIBER_DEC', 'DEC_OBS')

    fm.rename_column('DESIGN_X', 'X_TARGET')
    fm.rename_column('DESIGN_Y', 'Y_TARGET')
    fm['X_FVCOBS'] = fm['X_TARGET']
    fm['Y_FVCOBS'] = fm['Y_TARGET']
    fm['X_FVCERR'] = np.full(n, 1e-3, dtype='f4')
    fm['Y_FVCERR'] = np.full(n, 1e-3, dtype='f4')

    for colname in [
            'BRICKID',
            'BRICK_OBJID',
            'COMM_TARGET',
            'DELTA_XFPA',
            'DELTA_XFPA_IVAR',
            'DELTA_YFPA',
            'DELTA_YFPA_IVAR',
            'DESIGN_Q',
            'DESIGN_S',
            'FIBERFLUX_G',
            'FIBERFLUX_R',
            'FIBERFLUX_Z',
            'FIBERSTATUS',
            'FIBERTOTFLUX_G',
            'FIBERTOTFLUX_R',
            'FIBERTOTFLUX_Z',
            'FIBER_DEC_IVAR',
            'FIBER_RA_IVAR',
            'FLUX_IVAR_G',
            'FLUX_IVAR_R',
            'FLUX_IVAR_W1',
            'FLUX_IVAR_W2',
            'FLUX_IVAR_Z',
            'FLUX_G',
            'FLUX_R',
            'FLUX_W1',
            'FLUX_W2',
            'FLUX_Z',
            'MORPHTYPE',
            'NUMTARGET',
            'NUM_ITER',
            'PMDEC',
            'PMDEC_IVAR',
            'PMRA',
            'PMRA_IVAR',
            'PRIORITY',
            'REF_ID',
            'SECONDARY_TARGET',
            'SUBPRIORITY',
            'SV1_BGS_TARGET',
            'SV1_DESI_TARGET',
            'SV1_MWS_TARGET',
            'TARGET_DEC_IVAR',
            'TARGET_RA_IVAR',
    ]:
        if colname in fm.colnames:
            fm.remove_column(colname)

    return fm
Example #7
0
def get_targets(nspec, program, tileid=None, seed=None, specify_targets=dict(), specmin=0):
    """
    Generates a set of targets for the requested program

    Args:
        nspec: (int) number of targets to generate
        program: (str) program name DARK, BRIGHT, GRAY, MWS, BGS, LRG, ELG, ...

    Options:
      * tileid: (int) tileid, used for setting RA,dec
      * seed: (int) random number seed
      * specify_targets: (dict of dicts)  Define target properties like magnitude and redshift
                                 for each target class. Each objtype has its own key,value pair
                                 see simspec.templates.specify_galparams_dict() 
                                 or simsepc.templates.specify_starparams_dict()
      * specmin: (int) first spectrum number (0-indexed)

    Returns:
      * fibermap
      * targets as tuple of (flux, wave, meta)
    """
    if tileid is None:
        tile_ra, tile_dec = 0.0, 0.0
    else:
        tile_ra, tile_dec = io.get_tile_radec(tileid)

    program = program.upper()
    log.debug('Using random seed {}'.format(seed))
    np.random.seed(seed)

    #- Get distribution of target types
    true_objtype, target_objtype = sample_objtype(nspec, program)

    #- Get DESI wavelength coverage
    try:
        params = desimodel.io.load_desiparams()
        wavemin = params['ccd']['b']['wavemin']
        wavemax = params['ccd']['z']['wavemax']
    except KeyError:
        wavemin = desimodel.io.load_throughput('b').wavemin
        wavemax = desimodel.io.load_throughput('z').wavemax
    dw = 0.2
    wave = np.arange(round(wavemin, 1), wavemax, dw)
    nwave = len(wave)

    flux = np.zeros( (nspec, len(wave)) )
    meta, _ = empty_metatable(nmodel=nspec, objtype='SKY')
    objmeta = dict()
    fibermap = empty_fibermap(nspec)

    targetid = np.random.randint(sys.maxsize, size=nspec).astype(np.int64)
    meta['TARGETID'] = targetid
    fibermap['TARGETID'] = targetid
    
    for objtype in set(true_objtype):
        ii = np.where(true_objtype == objtype)[0]
        nobj = len(ii)

        fibermap['OBJTYPE'][ii] = target_objtype[ii]

        if objtype in specify_targets.keys():
            obj_kwargs = specify_targets[objtype]
        else:
            obj_kwargs = dict()
                
        # Simulate spectra
        if objtype == 'SKY':
            fibermap['DESI_TARGET'][ii] = desi_mask.SKY
            continue

        elif objtype == 'ELG':
            from desisim.templates import ELG
            elg = ELG(wave=wave)
            simflux, wave1, meta1, objmeta1 = elg.make_templates(nmodel=nobj, seed=seed, **obj_kwargs)
            fibermap['DESI_TARGET'][ii] = desi_mask.ELG

        elif objtype == 'LRG':
            from desisim.templates import LRG
            lrg = LRG(wave=wave)
            simflux, wave1, meta1, objmeta1 = lrg.make_templates(nmodel=nobj, seed=seed, **obj_kwargs)
            fibermap['DESI_TARGET'][ii] = desi_mask.LRG

        elif objtype == 'BGS':
            from desisim.templates import BGS
            bgs = BGS(wave=wave)
            simflux, wave1, meta1, objmeta1 = bgs.make_templates(nmodel=nobj, seed=seed, **obj_kwargs)
            fibermap['DESI_TARGET'][ii] = desi_mask.BGS_ANY
            fibermap['BGS_TARGET'][ii] = bgs_mask.BGS_BRIGHT

        elif objtype == 'QSO':
            from desisim.templates import QSO
            qso = QSO(wave=wave)
            simflux, wave1, meta1, objmeta1 = qso.make_templates(nmodel=nobj, seed=seed, lyaforest=False, **obj_kwargs)
            fibermap['DESI_TARGET'][ii] = desi_mask.QSO

        # For a "bad" QSO simulate a normal star without color cuts, which isn't
        # right. We need to apply the QSO color-cuts to the normal stars to pull
        # out the correct population of contaminating stars.

        # Note by @moustakas: we can now do this using desisim/#150, but we are
        # going to need 'noisy' photometry (because the QSO color-cuts
        # explicitly avoid the stellar locus).
        elif objtype == 'QSO_BAD':
            from desisim.templates import STAR
            #from desitarget.cuts import isQSO
            #star = STAR(wave=wave, colorcuts_function=isQSO)
            star = STAR(wave=wave)
            simflux, wave1, meta1, objmeta1 = star.make_templates(nmodel=nobj, seed=seed, **obj_kwargs)
            fibermap['DESI_TARGET'][ii] = desi_mask.QSO

        elif objtype == 'STD':
            from desisim.templates import STD
            std = STD(wave=wave)
            simflux, wave1, meta1, objmeta1 = std.make_templates(nmodel=nobj, seed=seed, **obj_kwargs)
            #- Loop options for forwards/backwards compatibility
            for name in ['STD_FAINT', 'STD_FSTAR', 'STD']:
                if name in desi_mask.names():
                    fibermap['DESI_TARGET'][ii] |= desi_mask[name]
                    break

        elif objtype == 'MWS_STAR':
            from desisim.templates import MWS_STAR
            mwsstar = MWS_STAR(wave=wave)
            # TODO: mag ranges for different programs of STAR targets should be in desimodel
            if 'magrange' not in obj_kwargs.keys():
                obj_kwargs['magrange'] = (15.0,20.0)
            simflux, wave1, meta1, objmeta1 = mwsstar.make_templates(nmodel=nobj, seed=seed, **obj_kwargs)
            fibermap['DESI_TARGET'][ii] |= desi_mask.MWS_ANY
            #- MWS bit names changed after desitarget 0.6.0 so use number
            #- instead of name for now (bit 0 = mask 1 = MWS_MAIN currently)
            fibermap['MWS_TARGET'][ii] = 1

        else:
            raise ValueError('Unable to simulate OBJTYPE={}'.format(objtype))

        # Assign targetid
        meta1['TARGETID'] = targetid[ii]
        if hasattr(objmeta1, 'data'): # simqso.sqgrids.QsoSimPoints object
            objmeta1.data['TARGETID'] = targetid[ii]
        else:
            if len(objmeta1) > 0:
                objmeta1['TARGETID'] = targetid[ii]
                # We want the dict key tied to the "true" object type (e.g., STAR),
                # not, e.g., QSO_BAD.
                objmeta[meta1['OBJTYPE'][0]] = objmeta1

        flux[ii] = simflux
        meta[ii] = meta1

        for band in ['G', 'R', 'Z', 'W1', 'W2']:
            key = 'FLUX_'+band
            fibermap[key][ii] = meta[key][ii]
            #- TODO: FLUX_IVAR

    #- Load fiber -> positioner mapping and tile information
    fiberpos = desimodel.io.load_fiberpos()

    #- Where are these targets?  Centered on positioners for now.
    x = fiberpos['X'][specmin:specmin+nspec]
    y = fiberpos['Y'][specmin:specmin+nspec]
    fp = FocalPlane(tile_ra, tile_dec)
    ra = np.zeros(nspec)
    dec = np.zeros(nspec)
    for i in range(nspec):
        ra[i], dec[i] = fp.xy2radec(x[i], y[i])

    #- Fill in the rest of the fibermap structure
    fibermap['FIBER'] = np.arange(nspec, dtype='i4')
    fibermap['POSITIONER'] = fiberpos['POSITIONER'][specmin:specmin+nspec]
    fibermap['SPECTROID'] = fiberpos['SPECTROGRAPH'][specmin:specmin+nspec]
    fibermap['TARGETCAT'] = np.zeros(nspec, dtype=(str, 20))
    fibermap['LAMBDA_REF'] = np.ones(nspec, dtype=np.float32)*5400
    fibermap['TARGET_RA'] = ra
    fibermap['TARGET_DEC'] = dec
    fibermap['FIBERASSIGN_X'] = x
    fibermap['FIBERASSIGN_Y'] = y
    fibermap['FIBER_RA'] = fibermap['TARGET_RA']
    fibermap['FIBER_DEC'] = fibermap['TARGET_DEC']
    fibermap['BRICKNAME'] = brick.brickname(ra, dec)

    return fibermap, (flux, wave, meta, objmeta)
Example #8
0
def calc_numobs_more(targets, zcat, obscon):
    """
    Calculate target NUMOBS_MORE from masks, observation/redshift status.

    Parameters
    ----------
    targets : :class:`~numpy.ndarray`
        numpy structured array or astropy Table of targets. Must include
        the columns `DESI_TARGET`, `BGS_TARGET`, `MWS_TARGET`
        (or their SV/cmx equivalents) `TARGETID` and `NUMOBS_INIT`.
    zcat : :class:`~numpy.ndarray`
        numpy structured array or Table of redshift info. Must include
        `Z`, `ZWARN`, `NUMOBS` and `TARGETID` and BE SORTED ON TARGETID
        to match `targets` row-by-row. May also contain `NUMOBS_MORE` if
        this isn't the first time through MTL and `NUMOBS > 0`.
    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.

    Returns
    -------
    :class:`~numpy.array`
        Integer array of number of additional observations (NUMOBS_MORE).

    Notes
    -----
        - Will automatically detect if the passed targets are main
          survey, commissioning or SV and behave accordingly.
        - Most targets are updated to NUMOBS_MORE = NUMOBS_INIT-NUMOBS.
          Special cases include BGS targets which always get NUMOBS_MORE
          of 1 in bright time and QSO "tracer" targets which always get
          NUMOBS_MORE=0 in dark time.
    """
    # ADM check input arrays are sorted to match row-by-row on TARGETID.
    assert np.all(targets["TARGETID"] == zcat["TARGETID"])

    # ADM determine whether the input targets are main survey, cmx or SV.
    colnames, masks, survey = main_cmx_or_sv(targets, scnd=True)
    # ADM the target bits/names should be shared between main survey and SV.
    if survey != 'cmx':
        desi_target, bgs_target, mws_target, scnd_target = colnames
        desi_mask, bgs_mask, mws_mask, scnd_mask = masks
    else:
        cmx_mask = masks[0]

    # ADM main case, just decrement by NUMOBS.
    numobs_more = np.maximum(0, targets['NUMOBS_INIT'] - zcat['NUMOBS'])

    if survey != 'cmx':
        # ADM BGS targets are observed during the BRIGHT survey, regardless
        # ADM of how often they've previously been observed.
        if (obsconditions.mask(obscon) & obsconditions.mask("BRIGHT")) != 0:
            ii = targets[desi_target] & desi_mask.BGS_ANY > 0
            numobs_more[ii] = 1

    if survey == 'main':
        # ADM If a DARK layer target is confirmed to have a good redshift
        # ADM at z < zcut it always needs just one total observation.
        # ADM (zcut is defined at the top of this module).
        if (obsconditions.mask(obscon) & obsconditions.mask("DARK")) != 0:
            ii = (zcat['ZWARN'] == 0)
            ii &= (zcat['Z'] < zcut)
            ii &= (zcat['NUMOBS'] > 0)
            numobs_more[ii] = 0

        # ADM We will have to be more careful if some DARK layer targets
        # ADM other than QSOs request more than one observation.
        check = {bit: desi_mask[bit].numobs for bit in desi_mask.names() if
                 'DARK' in desi_mask[bit].obsconditions and 'QSO' not in bit
                 and desi_mask[bit].numobs > 1}
        if len(check) > 1:
            msg = "logic not programmed for main survey dark-time targets other"
            msg += " than QSOs having NUMOBS_INIT > 1: {}".format(check)
            log.critical(msg)
            raise ValueError(msg)

    return numobs_more
Example #9
0
def load_target_table(tgs,
                      tgdata,
                      survey=None,
                      typeforce=None,
                      typecol=None,
                      sciencemask=None,
                      stdmask=None,
                      skymask=None,
                      suppskymask=None,
                      safemask=None,
                      excludemask=None):
    """Append targets from a table.

    Use the table data to append targets to the input Targets object.
    A subset of the columns in the file will be stored in each Target added
    to the Targets object.  Each target is classified into one or more of the
    4 types used internally in assignment (science, standard, sky, safe).

    This classification is controlled by applying bitmasks to the specified
    data column.  Alternatively, all targets in the file can be forced to one
    type.

    Args:
        tgs (Targets): The targets object on which to append this data.
        tgdata (Table): A table or recarray with the target properties.
        survey (str):  The survey type.  If None, query from columns.
        typeforce (int): If specified, it must equal one of the TARGET_TYPE_*
            values.  All targets read from the file will be assigned this type.
        typecol (str): Optional column to use for bitmask matching (default
            uses the result of main_cmx_or_sv from desitarget).
        sciencemask (int): Bitmask for classifying targets as science.
        stdmask (int): Bitmask for classifying targets as a standard.
        skymask (int): Bitmask for classifying targets as sky.
        suppskymask (int): Bitmask for classifying targets as suppsky.
        safemask (int): Bitmask for classifying targets as a safe location.
        excludemask (int): Bitmask for excluding targets.

    Returns:
        None

    """
    log = Logger.get()
    if "TARGETID" not in tgdata.dtype.names:
        msg = "TARGETID column is required"
        log.error(msg)
        raise RuntimeError(msg)
    if tgdata.dtype["TARGETID"].char != "l":
        msg = "TARGETID column should be int64"
        log.error(msg)
        raise RuntimeError(msg)
    if "PRIORITY" in tgdata.dtype.names:
        if tgdata.dtype["PRIORITY"].char not in ["i", "l"]:
            msg = "PRIORITY column should be an integer type"
            log.error(msg)
            raise RuntimeError(msg)
    if "SUBPRIORITY" not in tgdata.dtype.names:
        msg = "SUBPRIORITY column is required"
        log.error(msg)
        raise RuntimeError(msg)
    if tgdata.dtype["SUBPRIORITY"].char != "d":
        msg = "SUBPRIORITY column should be float64"
        log.error(msg)
        raise RuntimeError(msg)
    if "NUMOBS_MORE" in tgdata.dtype.names:
        if tgdata.dtype["NUMOBS_MORE"].char not in ["i", "l"]:
            msg = "NUMOBS_MORE column should be an integer type"
            log.error(msg)
            raise RuntimeError(msg)
    if "NUMOBS_INIT" in tgdata.dtype.names:
        if tgdata.dtype["NUMOBS_INIT"].char not in ["i", "l"]:
            msg = "NUMOBS_INIT column should be an integer type"
            log.error(msg)
            raise RuntimeError(msg)
    if "OBSCONDITIONS" not in tgdata.dtype.names:
        msg = "OBSCONDITIONS column is required"
        log.error(msg)
        raise RuntimeError(msg)
    if tgdata.dtype["OBSCONDITIONS"].char not in ["i", "l"]:
        msg = "OBSCONDITIONS column should be an integer type"
        log.error(msg)
        raise RuntimeError(msg)

    # Are we loading raw output?  If so, we require the survey key to get
    # the default masks.
    fsurvey = None
    fcol = None
    fsciencemask = None
    fstdmask = None
    fskymask = None
    fsuppskymask = None
    fsafemask = None
    fexcludemask = None
    if typecol == "FA_TYPE":
        if survey is None:
            msg = "When loading raw fiberassign tables, the survey must be \
                specified"

            log.error(msg)
            raise RuntimeError(msg)
        fsciencemask, fstdmask, fskymask, fsuppskymask, fsafemask, \
            fexcludemask = default_survey_target_masks(survey)
    else:
        fsurvey, fcol, fsciencemask, fstdmask, fskymask, fsuppskymask, \
            fsafemask, fexcludemask = default_target_masks(tgdata)
        if fcol is None:
            # File could not be identified.  In this case, the user must
            # completely specify the bitmask and column to use.
            if typeforce is None:
                if (typecol is None) or (sciencemask is None) \
                        or (stdmask is None) or (skymask is None) \
                        or (suppskymask is None) or (safemask is None) \
                        or (excludemask is None):
                    msg = "Unknown survey type.  To use this table, \
                        specify the column name and every bitmask."

                    log.error(msg)
                    raise RuntimeError(msg)

    if survey is None:
        survey = fsurvey
    if typecol is None:
        typecol = fcol
    if sciencemask is None:
        sciencemask = fsciencemask
    if stdmask is None:
        stdmask = fstdmask
    if skymask is None:
        skymask = fskymask
    if suppskymask is None:
        suppskymask = fsuppskymask
    if safemask is None:
        safemask = fsafemask
    if excludemask is None:
        excludemask = fexcludemask

    log.debug("Target table using survey '{}', column {}:".format(
        survey, typecol))
    if survey == "main":
        log.debug("  sciencemask {}".format("|".join(
            desi_mask.names(sciencemask))))
        log.debug("  stdmask     {}".format("|".join(
            desi_mask.names(stdmask))))
        log.debug("  skymask     {}".format("|".join(
            desi_mask.names(skymask))))
        log.debug("  suppskymask     {}".format("|".join(
            desi_mask.names(suppskymask))))
        log.debug("  safemask    {}".format("|".join(
            desi_mask.names(safemask))))
        log.debug("  excludemask {}".format("|".join(
            desi_mask.names(excludemask))))
    elif survey == "cmx":
        log.debug("  sciencemask {}".format("|".join(
            cmx_mask.names(sciencemask))))
        log.debug("  stdmask     {}".format("|".join(cmx_mask.names(stdmask))))
        log.debug("  skymask     {}".format("|".join(cmx_mask.names(skymask))))
        log.debug("  suppskymask     {}".format("|".join(
            cmx_mask.names(suppskymask))))
        log.debug("  safemask    {}".format("|".join(
            cmx_mask.names(safemask))))
        log.debug("  excludemask {}".format("|".join(
            cmx_mask.names(excludemask))))
    elif survey == "sv1":
        log.debug("  sciencemask {}".format("|".join(
            sv1_mask.names(sciencemask))))
        log.debug("  stdmask     {}".format("|".join(sv1_mask.names(stdmask))))
        log.debug("  skymask     {}".format("|".join(sv1_mask.names(skymask))))
        log.debug("  suppskymask     {}".format("|".join(
            sv1_mask.names(suppskymask))))
        log.debug("  safemask    {}".format("|".join(
            sv1_mask.names(safemask))))
        log.debug("  excludemask {}".format("|".join(
            sv1_mask.names(excludemask))))
    else:
        raise RuntimeError("unknown survey type, should never get here!")
    append_target_table(tgs, tgdata, survey, typeforce, typecol, sciencemask,
                        stdmask, skymask, suppskymask, safemask, excludemask)
    return
Example #10
0
    mtl.write(mtlfile)
    

    #print some stats
    print('MWS_TARGETS: {}'.format(np.count_nonzero(mtl['MWS_TARGET']!=0)))
    print('BGS_TARGETS: {}'.format(np.count_nonzero(mtl['BGS_TARGET']!=0)))
    print('DESI_TARGETS: {}'.format(np.count_nonzero(mtl['DESI_TARGET']!=0)))
    print('finished computing mtl')

#standards
if not os.path.exists(starfile):
    std_mask = 0
    for name in ['STD', 'STD_FSTAR', 'STD_WD',
             'STD_FAINT', 'STD_FAINT_BEST',
             'STD_BRIGHT', 'STD_BRIGHT_BEST']:
        if name in desi_mask.names():
            std_mask |= desi_mask[name]

    starstd = (targetdata['DESI_TARGET'] & std_mask) != 0
    stardata = targetdata[starstd]

    if program=="bright":
        obscond = np.int_(np.repeat(obsconditions['BRIGHT'], len(stardata)))
    else:
        obscond = np.int_(np.repeat(obsconditions['DARK']|obsconditions['GRAY'], len(stardata))) 

    stardata = np.lib.recfunctions.append_fields(stardata, 'OBSCONDITIONS', obscond)  
        
    fitsio.write(starfile, stardata, extname='STD')
    print('{} standards'.format(np.count_nonzero(stardata)))
    print('Finished with standards')
Example #11
0
def specviewer_selection(spectra,
                         log=None,
                         mask=None,
                         mask_type=None,
                         gmag_cut=None,
                         rmag_cut=None,
                         chi2cut=None,
                         zbest=None,
                         snr_cut=None,
                         with_dirty_mask_merge=False,
                         remove_scores=False):
    '''
    Simple sub-selection on spectra based on meta-data.
        Implemented cuts based on : target mask ; photo mag (g, r) ; chi2 from fit ; SNR (in spectra.scores, BRZ)
        - if chi2cut : a catalog zbest must be provided, with entries matching exactly those of spectra
    '''

    # SNR selection
    if snr_cut is not None:
        assert ((len(snr_cut) == 2) and (spectra.scores is not None))
        for band in ['B', 'R', 'Z']:
            w, = np.where(
                (spectra.scores['MEDIAN_CALIB_SNR_' + band] > snr_cut[0])
                & (spectra.scores['MEDIAN_CALIB_SNR_' + band] < snr_cut[1]))
            if len(w) == 0:
                if log is not None:
                    log.info(" * No spectra with MEDIAN_CALIB_SNR_" + band +
                             " in requested range")
                return 0
            else:
                targetids = spectra.fibermap['TARGETID'][w]
                spectra = myspecselect.myspecselect(
                    spectra, targets=targetids, remove_scores=remove_scores)

    # Target mask selection
    if mask is not None:
        assert mask_type in ['SV1_DESI_TARGET', 'DESI_TARGET', 'CMX_TARGET']
        if mask_type == 'SV1_DESI_TARGET':
            assert (mask in sv1_desi_mask.names())
            w, = np.where(
                (spectra.fibermap['SV1_DESI_TARGET'] & sv1_desi_mask[mask]))
        elif mask_type == 'DESI_TARGET':
            assert (mask in desi_mask.names())
            w, = np.where((spectra.fibermap['DESI_TARGET'] & desi_mask[mask]))
        elif mask_type == 'CMX_TARGET':
            assert (mask in cmx_mask.names())
            mask2 = None
            if with_dirty_mask_merge:  # Self-explanatory... only for fast VI of minisv
                if mask in ['SV0_QSO', 'SV0_ELG', 'SV0_LRG']:
                    mask2 = mask.replace('SV0', 'MINI_SV')
                if mask == 'SV0_BGS': mask2 = 'MINI_SV_BGS_BRIGHT'
                if mask in ['SV0_STD_FAINT', 'SV0_STD_BRIGHT']:
                    mask2 = mask.replace('SV0_', '')
            if mask2 is None:
                w, = np.where(
                    (spectra.fibermap['CMX_TARGET'] & cmx_mask[mask]))
            else:
                w, = np.where((spectra.fibermap['CMX_TARGET'] & cmx_mask[mask])
                              | (spectra.fibermap['CMX_TARGET']
                                 & cmx_mask[mask2]))
        if len(w) == 0:
            if log is not None: log.info(" * No spectra with mask " + mask)
            return 0
        else:
            targetids = spectra.fibermap['TARGETID'][w]
            spectra = myspecselect.myspecselect(spectra,
                                                targets=targetids,
                                                remove_scores=remove_scores)

    # Photometry selection
    if gmag_cut is not None:
        assert len(gmag_cut) == 2  # Require range [gmin, gmax]
        gmag = np.zeros(spectra.num_spectra())
        w, = np.where((spectra.fibermap['FLUX_G'] > 0)
                      & (spectra.fibermap['MW_TRANSMISSION_G'] > 0))
        gmag[w] = -2.5 * np.log10(
            spectra.fibermap['FLUX_G'][w] /
            spectra.fibermap['MW_TRANSMISSION_G'][w]) + 22.5
        w, = np.where((gmag > gmag_cut[0]) & (gmag < gmag_cut[1]))
        if len(w) == 0:
            if log is not None:
                log.info(" * No spectra with g_mag in requested range")
            return 0
        else:
            targetids = spectra.fibermap['TARGETID'][w]
            spectra = myspecselect.myspecselect(spectra, targets=targetids)
    if rmag_cut is not None:
        assert len(rmag_cut) == 2  # Require range [rmin, rmax]
        rmag = np.zeros(spectra.num_spectra())
        w, = np.where((spectra.fibermap['FLUX_R'] > 0)
                      & (spectra.fibermap['MW_TRANSMISSION_R'] > 0))
        rmag[w] = -2.5 * np.log10(
            spectra.fibermap['FLUX_R'][w] /
            spectra.fibermap['MW_TRANSMISSION_R'][w]) + 22.5
        w, = np.where((rmag > rmag_cut[0]) & (rmag < rmag_cut[1]))
        if len(w) == 0:
            if log is not None:
                log.info(" * No spectra with r_mag in requested range")
            return 0
        else:
            targetids = spectra.fibermap['TARGETID'][w]
            spectra = myspecselect.myspecselect(spectra,
                                                targets=targetids,
                                                remove_scores=remove_scores)

    # Chi2 selection
    if chi2cut is not None:
        assert len(chi2cut) == 2  # Require range [chi2min, chi2max]
        if np.any(zbest['TARGETID'] != spectra.fibermap['TARGETID']):
            raise RunTimeError(
                'specviewer_selection : zbest and spectra do not match (different targetids)'
            )

        w, = np.where((zbest['DELTACHI2'] > chi2cut[0])
                      & (zbest['DELTACHI2'] < chi2cut[1]))
        if len(w) == 0:
            if log is not None:
                log.info(
                    " * No target in this pixel with DeltaChi2 in requested range"
                )
            return 0
        else:
            targetids = spectra.fibermap['TARGETID'][w]
            spectra = myspecselect.myspecselect(spectra,
                                                targets=targetids,
                                                remove_scores=remove_scores)

    return spectra
Example #12
0
def fibermap_new2old(fibermap):
    '''Converts new format fibermap into old format fibermap

    Args:
        fibermap: new-format fibermap table (e.g. with FLUX_G column)

    Returns:
        old format fibermap (e.g. with MAG column)

    Note: this is a transitional convenience function to allow us to
    simulate new format fibermaps while still running code that expects
    the old format.  After all code has been converted to use the new
    format, this will be removed.
    '''
    from desiutil.brick import Bricks
    from desitarget.targetmask import desi_mask

    brickmap = Bricks()
    fm = fibermap.copy()
    n = len(fm)

    isMWS = (fm['DESI_TARGET'] & desi_mask.MWS_ANY) != 0
    fm['OBJTYPE'][isMWS] = 'MWS_STAR'
    isBGS = (fm['DESI_TARGET'] & desi_mask.BGS_ANY) != 0
    fm['OBJTYPE'][isBGS] = 'BGS'

    stdmask = 0
    for name in ['STD', 'STD_FSTAR', 'STD_WD',
            'STD_FAINT', 'STD_FAINT_BEST', 'STD_BRIGHT', 'STD_BRIGHT_BEST']:
        if name in desi_mask.names():
            stdmask |= desi_mask[name]

    isSTD = (fm['DESI_TARGET'] & stdmask) != 0
    fm['OBJTYPE'][isSTD] = 'STD'

    isELG = (fm['DESI_TARGET'] & desi_mask.ELG) != 0
    fm['OBJTYPE'][isELG] = 'ELG'
    isLRG = (fm['DESI_TARGET'] & desi_mask.LRG) != 0
    fm['OBJTYPE'][isLRG] = 'LRG'
    isQSO = (fm['DESI_TARGET'] & desi_mask.QSO) != 0
    fm['OBJTYPE'][isQSO] = 'QSO'

    if ('FLAVOR' in fm.meta):
        if fm.meta['FLAVOR'] == 'arc':
            fm['OBJTYPE'] = 'ARC'
        elif fm.meta['FLAVOR'] == 'flat':
            fm['OBJTYPE'] = 'FLAT'

    fm.rename_column('TARGET_RA', 'RA_TARGET')
    fm.rename_column('TARGET_DEC', 'DEC_TARGET')

    fm['BRICKNAME'] = brickmap.brickname(fm['RA_TARGET'], fm['DEC_TARGET'])
    fm['TARGETCAT'] = np.full(n, 'UNKNOWN', dtype=(str, 20))

    fm['MAG'] = np.zeros((n,5), dtype='f4')
    fm['MAG'][:,0] = 22.5 - 2.5*np.log10(fm['FLUX_G'])
    fm['MAG'][:,1] = 22.5 - 2.5*np.log10(fm['FLUX_R'])
    fm['MAG'][:,2] = 22.5 - 2.5*np.log10(fm['FLUX_Z'])
    fm['MAG'][:,3] = 22.5 - 2.5*np.log10(fm['FLUX_W1'])
    fm['MAG'][:,4] = 22.5 - 2.5*np.log10(fm['FLUX_W2'])

    fm['FILTER'] = np.zeros((n,5), dtype=(str, 10))
    fm['FILTER'][:,0] = 'DECAM_G'
    fm['FILTER'][:,1] = 'DECAM_R'
    fm['FILTER'][:,2] = 'DECAM_Z'
    fm['FILTER'][:,3] = 'WISE_W1'
    fm['FILTER'][:,4] = 'WISE_W2'

    fm['POSITIONER'] = fm['LOCATION'].astype('i8')
    fm.rename_column('LAMBDA_REF', 'LAMBDAREF')

    fm.rename_column('FIBER_RA', 'RA_OBS')
    fm.rename_column('FIBER_DEC', 'DEC_OBS')

    fm.rename_column('DESIGN_X', 'X_TARGET')
    fm.rename_column('DESIGN_Y', 'Y_TARGET')
    fm['X_FVCOBS'] = fm['X_TARGET']
    fm['Y_FVCOBS'] = fm['Y_TARGET']
    fm['X_FVCERR'] = np.full(n, 1e-3, dtype='f4')
    fm['Y_FVCERR'] = np.full(n, 1e-3, dtype='f4')

    for colname in [
        'BRICKID', 'BRICK_OBJID', 'COMM_TARGET',
        'DELTA_XFPA', 'DELTA_XFPA_IVAR', 'DELTA_YFPA', 'DELTA_YFPA_IVAR',
        'DESIGN_Q', 'DESIGN_S',
        'FIBERFLUX_G', 'FIBERFLUX_R', 'FIBERFLUX_Z',
        'FIBERSTATUS',
        'FIBERTOTFLUX_G', 'FIBERTOTFLUX_R', 'FIBERTOTFLUX_Z', 'FIBER_DEC_IVAR', 'FIBER_RA_IVAR',
        'FLUX_IVAR_G', 'FLUX_IVAR_R', 'FLUX_IVAR_W1', 'FLUX_IVAR_W2', 'FLUX_IVAR_Z',
        'FLUX_G', 'FLUX_R', 'FLUX_W1', 'FLUX_W2', 'FLUX_Z',
        'MORPHTYPE', 'NUMTARGET', 'NUM_ITER',
        'PMDEC', 'PMDEC_IVAR', 'PMRA', 'PMRA_IVAR',
        'PRIORITY', 'REF_ID', 'SECONDARY_TARGET', 'SUBPRIORITY',
        'SV1_BGS_TARGET', 'SV1_DESI_TARGET', 'SV1_MWS_TARGET',
        'TARGET_DEC_IVAR', 'TARGET_RA_IVAR',
        ]:
        if colname in fm.colnames:
            fm.remove_column(colname)

    return fm
Example #13
0
def plotspectra(spectra,
                zcatalog=None,
                model=None,
                notebook=False,
                title=None):
    '''
    TODO: document
    '''

    if notebook:
        bk.output_notebook()

    #- If inputs are frames, convert to a spectra object
    if isinstance(spectra, list) and isinstance(spectra[0],
                                                desispec.frame.Frame):
        spectra = frames2spectra(spectra)
        frame_input = True
    else:
        frame_input = False

    if frame_input and title is None:
        meta = spectra.meta
        title = 'Night {} ExpID {} Spectrograph {}'.format(
            meta['NIGHT'],
            meta['EXPID'],
            meta['CAMERA'][1],
        )

    #- Gather spectra into ColumnDataSource objects for Bokeh
    nspec = spectra.num_spectra()
    cds_spectra = list()

    for band in spectra.bands:
        #- Set masked bins to NaN so that Bokeh won't plot them
        bad = (spectra.ivar[band] == 0.0) | (spectra.mask[band] != 0)
        spectra.flux[band][bad] = np.nan

        cdsdata = dict(
            origwave=spectra.wave[band].copy(),
            plotwave=spectra.wave[band].copy(),
        )

        for i in range(nspec):
            key = 'origflux' + str(i)
            cdsdata[key] = spectra.flux[band][i]

        cdsdata['plotflux'] = cdsdata['origflux0']

        cds_spectra.append(bk.ColumnDataSource(cdsdata, name=band))

    #- Reorder zcatalog to match input targets
    #- TODO: allow more than one zcatalog entry with different ZNUM per targetid
    targetids = spectra.target_ids()
    if zcatalog is not None:
        ii = np.argsort(np.argsort(targetids))
        jj = np.argsort(zcatalog['TARGETID'])
        kk = jj[ii]
        zcatalog = zcatalog[kk]

        #- That sequence of argsorts may feel like magic,
        #- so make sure we got it right
        assert np.all(zcatalog['TARGETID'] == targetids)
        assert np.all(zcatalog['TARGETID'] == spectra.fibermap['TARGETID'])

        #- Also need to re-order input model fluxes
        if model is not None:
            mwave, mflux = model
            model = mwave, mflux[kk]

    #- Gather models into ColumnDataSource objects, row matched to spectra
    if model is not None:
        mwave, mflux = model
        model_obswave = mwave.copy()
        model_restwave = mwave.copy()
        cds_model_data = dict(
            origwave=mwave.copy(),
            plotwave=mwave.copy(),
            plotflux=np.zeros(len(mwave)),
        )

        for i in range(nspec):
            key = 'origflux' + str(i)
            cds_model_data[key] = mflux[i]

        cds_model_data['plotflux'] = cds_model_data['origflux0']
        cds_model = bk.ColumnDataSource(cds_model_data)
    else:
        cds_model = None

    #- Subset of zcatalog and fibermap columns into ColumnDataSource
    target_info = list()
    for i, row in enumerate(spectra.fibermap):
        target_bit_names = ' '.join(desi_mask.names(row['DESI_TARGET']))
        txt = 'Target {}: {}'.format(row['TARGETID'], target_bit_names)
        if zcatalog is not None:
            txt += '<BR/>{} z={:.4f} ± {:.4f}  ZWARN={}'.format(
                zcatalog['SPECTYPE'][i],
                zcatalog['Z'][i],
                zcatalog['ZERR'][i],
                zcatalog['ZWARN'][i],
            )
        target_info.append(txt)

    cds_targetinfo = bk.ColumnDataSource(dict(target_info=target_info),
                                         name='targetinfo')
    if zcatalog is not None:
        cds_targetinfo.add(zcatalog['Z'], name='z')

    plot_width = 800
    plot_height = 400
    # tools = 'pan,box_zoom,wheel_zoom,undo,redo,reset,save'
    tools = 'pan,box_zoom,wheel_zoom,reset,save'
    fig = bk.figure(height=plot_height,
                    width=plot_width,
                    title=title,
                    tools=tools,
                    toolbar_location='above',
                    y_range=(-10, 20))
    fig.toolbar.active_drag = fig.tools[1]  #- box zoom
    fig.toolbar.active_scroll = fig.tools[2]  #- wheel zoom
    fig.xaxis.axis_label = 'Wavelength [Å]'
    fig.yaxis.axis_label = 'Flux'
    fig.xaxis.axis_label_text_font_style = 'normal'
    fig.yaxis.axis_label_text_font_style = 'normal'
    colors = dict(b='#1f77b4', r='#d62728', z='maroon')

    data_lines = list()
    for spec in cds_spectra:
        lx = fig.line('plotwave',
                      'plotflux',
                      source=spec,
                      line_color=colors[spec.name])
        data_lines.append(lx)

    if cds_model is not None:
        model_lines = list()
        lx = fig.line('plotwave',
                      'plotflux',
                      source=cds_model,
                      line_color='black')
        model_lines.append(lx)

        legend = Legend(items=[
            ("data",
             data_lines[-1::-1]),  #- reversed to get blue as lengend entry
            ("model", model_lines),
        ])
    else:
        legend = Legend(items=[
            ("data",
             data_lines[-1::-1]),  #- reversed to get blue as lengend entry
        ])

    fig.add_layout(legend, 'center')
    fig.legend.click_policy = 'hide'  #- or 'mute'

    #- Zoom figure around mouse hover of main plot
    zoomfig = bk.figure(
        height=plot_height // 2,
        width=plot_height // 2,
        y_range=fig.y_range,
        x_range=(5000, 5100),
        # output_backend="webgl",
        toolbar_location=None,
        tools=[])

    for spec in cds_spectra:
        zoomfig.line('plotwave',
                     'plotflux',
                     source=spec,
                     line_color=colors[spec.name],
                     line_width=1,
                     line_alpha=1.0)

    if cds_model is not None:
        zoomfig.line('plotwave',
                     'plotflux',
                     source=cds_model,
                     line_color='black')

    #- Callback to update zoom window x-range
    zoom_callback = CustomJS(args=dict(zoomfig=zoomfig),
                             code="""
            zoomfig.x_range.start = cb_obj.x - 100;
            zoomfig.x_range.end = cb_obj.x + 100;
        """)

    fig.js_on_event(bokeh.events.MouseMove, zoom_callback)

    #-----
    #- Emission and absorption lines
    z = zcatalog['Z'][0] if (zcatalog is not None) else 0.0
    line_data, lines, line_labels = add_lines(fig, z=z)

    #-----
    #- Add widgets for controling plots
    z1 = np.floor(z * 100) / 100
    dz = z - z1
    zslider = Slider(start=0.0, end=4.0, value=z1, step=0.01, title='Redshift')
    dzslider = Slider(start=0.0,
                      end=0.01,
                      value=dz,
                      step=0.0001,
                      title='+ Delta redshift')
    dzslider.format = "0[.]0000"

    #- Observer vs. Rest frame wavelengths
    waveframe_buttons = RadioButtonGroup(labels=["Obs", "Rest"], active=0)

    ifiberslider = Slider(start=0, end=nspec - 1, value=0, step=1)
    if frame_input:
        ifiberslider.title = 'Fiber'
    else:
        ifiberslider.title = 'Target'

    zslider_callback = CustomJS(
        args=dict(
            spectra=cds_spectra,
            model=cds_model,
            targetinfo=cds_targetinfo,
            ifiberslider=ifiberslider,
            zslider=zslider,
            dzslider=dzslider,
            waveframe_buttons=waveframe_buttons,
            line_data=line_data,
            lines=lines,
            line_labels=line_labels,
            fig=fig,
        ),
        #- TODO: reorder to reduce duplicated code
        code="""
        var z = zslider.value + dzslider.value
        var line_restwave = line_data.data['restwave']
        var ifiber = ifiberslider.value
        var zfit = 0.0
        if(targetinfo.data['z'] != undefined) {
            zfit = targetinfo.data['z'][ifiber]
        }

        // Observer Frame
        if(waveframe_buttons.active == 0) {
            var x = 0.0
            for(var i=0; i<line_restwave.length; i++) {
                x = line_restwave[i] * (1+z)
                lines[i].location = x
                line_labels[i].x = x
            }
            for(var i=0; i<spectra.length; i++) {
                var data = spectra[i].data
                var origwave = data['origwave']
                var plotwave = data['plotwave']
                for (var j=0; j<plotwave.length; j++) {
                    plotwave[j] = origwave[j]
                }
                spectra[i].change.emit()
            }

            // Update model wavelength array
            if(model) {
                var origwave = model.data['origwave']
                var plotwave = model.data['plotwave']
                for(var i=0; i<plotwave.length; i++) {
                    plotwave[i] = origwave[i] * (1+z) / (1+zfit)
                }
                model.change.emit()
            }

        // Rest Frame
        } else {
            for(i=0; i<line_restwave.length; i++) {
                lines[i].location = line_restwave[i]
                line_labels[i].x = line_restwave[i]
            }
            for (var i=0; i<spectra.length; i++) {
                var data = spectra[i].data
                var origwave = data['origwave']
                var plotwave = data['plotwave']
                for (var j=0; j<plotwave.length; j++) {
                    plotwave[j] = origwave[j] / (1+z)
                }
                spectra[i].change.emit()
            }

            // Update model wavelength array
            if(model) {
                var origwave = model.data['origwave']
                var plotwave = model.data['plotwave']
                for(var i=0; i<plotwave.length; i++) {
                    plotwave[i] = origwave[i] / (1+zfit)
                }
                model.change.emit()
            }
        }
        """)

    zslider.js_on_change('value', zslider_callback)
    dzslider.js_on_change('value', zslider_callback)
    waveframe_buttons.js_on_click(zslider_callback)

    plotrange_callback = CustomJS(args=dict(
        zslider=zslider,
        dzslider=dzslider,
        waveframe_buttons=waveframe_buttons,
        fig=fig,
    ),
                                  code="""
        var z = zslider.value + dzslider.value
        // Observer Frame
        if(waveframe_buttons.active == 0) {
            fig.x_range.start = fig.x_range.start * (1+z)
            fig.x_range.end = fig.x_range.end * (1+z)
        } else {
            fig.x_range.start = fig.x_range.start / (1+z)
            fig.x_range.end = fig.x_range.end / (1+z)
        }
        """)
    waveframe_buttons.js_on_click(plotrange_callback)

    smootherslider = Slider(start=0,
                            end=31,
                            value=0,
                            step=1.0,
                            title='Gaussian Sigma Smooth')
    target_info_div = Div(text=target_info[0])

    #-----
    #- Toggle lines
    lines_button_group = CheckboxButtonGroup(labels=["Emission", "Absorption"],
                                             active=[])

    lines_callback = CustomJS(args=dict(line_data=line_data,
                                        lines=lines,
                                        line_labels=line_labels),
                              code="""
        var show_emission = false
        var show_absorption = false
        if (cb_obj.active.indexOf(0) >= 0) {  // index 0=Emission in active list
            show_emission = true
        }
        if (cb_obj.active.indexOf(1) >= 0) {  // index 1=Absorption in active list
            show_absorption = true
        }

        for(var i=0; i<lines.length; i++) {
            if(line_data.data['emission'][i]) {
                lines[i].visible = show_emission
                line_labels[i].visible = show_emission
            } else {
                lines[i].visible = show_absorption
                line_labels[i].visible = show_absorption
            }
        }
        """)
    lines_button_group.js_on_click(lines_callback)
    # lines_button_group.js_on_change('value', lines_callback)

    #-----
    update_plot = CustomJS(args=dict(
        spectra=cds_spectra,
        model=cds_model,
        targetinfo=cds_targetinfo,
        target_info_div=target_info_div,
        ifiberslider=ifiberslider,
        smootherslider=smootherslider,
        zslider=zslider,
        dzslider=dzslider,
        lines_button_group=lines_button_group,
        fig=fig,
    ),
                           code="""
        var ifiber = ifiberslider.value
        var nsmooth = smootherslider.value
        target_info_div.text = targetinfo.data['target_info'][ifiber]

        if(targetinfo.data['z'] != undefined) {
            var z = targetinfo.data['z'][ifiber]
            var z1 = Math.floor(z*100) / 100
            zslider.value = z1
            dzslider.value = (z - z1)
        }

        function get_y_minmax(pmin, pmax, data) {
            // copy before sorting to not impact original, and filter out NaN
            var dx = data.slice().filter(Boolean)
            dx.sort()
            var imin = Math.floor(pmin * dx.length)
            var imax = Math.floor(pmax * dx.length)
            return [dx[imin], dx[imax]]
        }

        // Smoothing kernel
        var kernel = [];
        for(var i=-2*nsmooth; i<=2*nsmooth; i++) {
            kernel.push(Math.exp(-(i**2)/(2*nsmooth)))
        }
        var kernel_offset = Math.floor(kernel.length/2)

        // Smooth plot and recalculate ymin/ymax
        // TODO: add smoother function to reduce duplicated code
        var ymin = 0.0
        var ymax = 0.0
        for (var i=0; i<spectra.length; i++) {
            var data = spectra[i].data
            var plotflux = data['plotflux']
            var origflux = data['origflux'+ifiber]
            for (var j=0; j<plotflux.length; j++) {
                if(nsmooth == 0) {
                    plotflux[j] = origflux[j]
                } else {
                    plotflux[j] = 0.0
                    var weight = 0.0
                    // TODO: speed could be improved by moving `if` out of loop
                    for (var k=0; k<kernel.length; k++) {
                        var m = j+k-kernel_offset
                        if((m >= 0) && (m < plotflux.length)) {
                            var fx = origflux[m]
                            if(fx == fx) {
                                plotflux[j] = plotflux[j] + fx * kernel[k]
                                weight += kernel[k]
                            }
                        }
                    }
                    plotflux[j] = plotflux[j] / weight
                }
            }
            spectra[i].change.emit()

            tmp = get_y_minmax(0.01, 0.99, plotflux)
            ymin = Math.min(ymin, tmp[0])
            ymax = Math.max(ymax, tmp[1])
        }

        // update model
        if(model) {
            var plotflux = model.data['plotflux']
            var origflux = model.data['origflux'+ifiber]
            for (var j=0; j<plotflux.length; j++) {
                if(nsmooth == 0) {
                    plotflux[j] = origflux[j]
                } else {
                    plotflux[j] = 0.0
                    var weight = 0.0
                    // TODO: speed could be improved by moving `if` out of loop
                    for (var k=0; k<kernel.length; k++) {
                        var m = j+k-kernel_offset
                        if((m >= 0) && (m < plotflux.length)) {
                            var fx = origflux[m]
                            if(fx == fx) {
                                plotflux[j] = plotflux[j] + fx * kernel[k]
                                weight += kernel[k]
                            }
                        }
                    }
                    plotflux[j] = plotflux[j] / weight
                }
            }
            model.change.emit()
        }

        // update y_range
        if(ymin<0) {
            fig.y_range.start = ymin * 1.4
        } else {
            fig.y_range.start = ymin * 0.6
        }
        fig.y_range.end = ymax * 1.4
    """)
    smootherslider.js_on_change('value', update_plot)
    ifiberslider.js_on_change('value', update_plot)

    #-----
    #- Add navigation buttons
    navigation_button_width = 30
    prev_button = Button(label="<", width=navigation_button_width)
    next_button = Button(label=">", width=navigation_button_width)

    prev_callback = CustomJS(args=dict(ifiberslider=ifiberslider),
                             code="""
        if(ifiberslider.value>0) {
            ifiberslider.value--
        }
        """)
    next_callback = CustomJS(args=dict(ifiberslider=ifiberslider, nspec=nspec),
                             code="""
        if(ifiberslider.value<nspec+1) {
            ifiberslider.value++
        }
        """)

    prev_button.js_on_event('button_click', prev_callback)
    next_button.js_on_event('button_click', next_callback)

    #-----
    slider_width = plot_width - 2 * navigation_button_width
    navigator = bk.Row(
        widgetbox(prev_button, width=navigation_button_width),
        widgetbox(next_button, width=navigation_button_width + 20),
        widgetbox(ifiberslider, width=slider_width - 20))
    bk.show(
        bk.Column(
            bk.Row(fig, zoomfig),
            widgetbox(target_info_div, width=plot_width),
            navigator,
            widgetbox(smootherslider, width=plot_width // 2),
            bk.Row(
                widgetbox(waveframe_buttons, width=120),
                widgetbox(zslider, width=plot_width // 2 - 60),
                widgetbox(dzslider, width=plot_width // 2 - 60),
            ),
            widgetbox(lines_button_group),
        ))
Example #14
0
def specviewer_selection(spectra,
                         log=None,
                         mask=None,
                         mask_type=None,
                         gmag_cut=None,
                         rmag_cut=None,
                         chi2cut=None,
                         zbest=None,
                         snr_cut=None):
    '''
    Simple sub-selection on spectra based on meta-data.
        Implemented cuts based on : target mask ; photo mag (g, r) ; chi2 from fit ; SNR (in spectra.scores, BRZ)
    '''

    # Target mask selection
    if mask is not None:
        assert mask_type in ['SV1_DESI_TARGET', 'DESI_TARGET', 'CMX_TARGET']
        if mask_type == 'SV1_DESI_TARGET':
            assert (mask in sv1_desi_mask.names())
            w, = np.where(
                (spectra.fibermap['SV1_DESI_TARGET'] & sv1_desi_mask[mask]))
        elif mask_type == 'DESI_TARGET':
            assert (mask in desi_mask.names())
            w, = np.where((spectra.fibermap['DESI_TARGET'] & desi_mask[mask]))
        elif mask_type == 'CMX_TARGET':
            assert (mask in cmx_mask.names())
            w, = np.where((spectra.fibermap['CMX_TARGET'] & cmx_mask[mask]))
        if len(w) == 0:
            if log is not None: log.info(" * No spectra with mask " + mask)
            return 0
        else:
            targetids = spectra.fibermap['TARGETID'][w]
            spectra = myspecselect.myspecselect(spectra, targets=targetids)

    # Photometry selection
    if gmag_cut is not None:
        assert len(gmag_cut) == 2  # Require range [gmin, gmax]
        gmag = np.zeros(spectra.num_spectra())
        w, = np.where((spectra.fibermap['FLUX_G'] > 0)
                      & (spectra.fibermap['MW_TRANSMISSION_G'] > 0))
        gmag[w] = -2.5 * np.log10(
            spectra.fibermap['FLUX_G'][w] /
            spectra.fibermap['MW_TRANSMISSION_G'][w]) + 22.5
        w, = np.where((gmag > gmag_cut[0]) & (gmag < gmag_cut[1]))
        if len(w) == 0:
            if log is not None:
                log.info(" * No spectra with g_mag in requested range")
            return 0
        else:
            targetids = spectra.fibermap['TARGETID'][w]
            spectra = myspecselect.myspecselect(spectra, targets=targetids)
    if rmag_cut is not None:
        assert len(rmag_cut) == 2  # Require range [rmin, rmax]
        rmag = np.zeros(spectra.num_spectra())
        w, = np.where((spectra.fibermap['FLUX_R'] > 0)
                      & (spectra.fibermap['MW_TRANSMISSION_R'] > 0))
        rmag[w] = -2.5 * np.log10(
            spectra.fibermap['FLUX_R'][w] /
            spectra.fibermap['MW_TRANSMISSION_R'][w]) + 22.5
        w, = np.where((rmag > rmag_cut[0]) & (rmag < rmag_cut[1]))
        if len(w) == 0:
            if log is not None:
                log.info(" * No spectra with r_mag in requested range")
            return 0
        else:
            targetids = spectra.fibermap['TARGETID'][w]
            spectra = myspecselect.myspecselect(spectra, targets=targetids)

    # SNR selection ## TODO check it !! May not work ...
    if snr_cut is not None:
        assert ((len(snr_cut) == 2) and (spectra.scores is not None))
        for band in ['B', 'R', 'Z']:
            w, = np.where(
                (spectra.scores['MEDIAN_CALIB_SNR_' + band] > snr_cut[0])
                & (spectra.scores['MEDIAN_CALIB_SNR_' + band] < snr_cut[1]))
            if len(w) == 0:
                if log is not None:
                    log.info(" * No spectra with MEDIAN_CALIB_SNR_" + band +
                             " in requested range")
                return 0
            else:
                targetids = spectra.fibermap['TARGETID'][w]
                spectra = myspecselect.myspecselect(spectra, targets=targetids)

    # Chi2 selection
    if chi2cut is not None:
        assert len(chi2cut) == 2  # Require range [chi2min, chi2max]
        assert (zbest is not None)
        thezb, kk = match_zcat_to_spectra(zbest, spectra)
        w, = np.where((thezb['DELTACHI2'] > chi2cut[0])
                      & (thezb['DELTACHI2'] < chi2cut[1]))
        if len(w) == 0:
            if log is not None:
                log.info(
                    " * No target in this pixel with DeltaChi2 in requested range"
                )
            return 0
        else:
            targetids = spectra.fibermap['TARGETID'][w]
            spectra = myspecselect.myspecselect(spectra, targets=targetids)

    return spectra
Example #15
0
def get_targets(nspec, program, tileid=None, seed=None, specify_targets=dict(), specmin=0):
    """
    Generates a set of targets for the requested program

    Args:
        nspec: (int) number of targets to generate
        program: (str) program name DARK, BRIGHT, GRAY, MWS, BGS, LRG, ELG, ...

    Options:
      * tileid: (int) tileid, used for setting RA,dec
      * seed: (int) random number seed
      * specify_targets: (dict of dicts)  Define target properties like magnitude and redshift
                                 for each target class. Each objtype has its own key,value pair
                                 see simspec.templates.specify_galparams_dict() 
                                 or simsepc.templates.specify_starparams_dict()
      * specmin: (int) first spectrum number (0-indexed)

    Returns:
      * fibermap
      * targets as tuple of (flux, wave, meta)
    """
    if tileid is None:
        tile_ra, tile_dec = 0.0, 0.0
    else:
        tile_ra, tile_dec = io.get_tile_radec(tileid)

    program = program.upper()
    log.debug('Using random seed {}'.format(seed))
    np.random.seed(seed)

    #- Get distribution of target types
    true_objtype, target_objtype = sample_objtype(nspec, program)

    #- Get DESI wavelength coverage
    try:
        params = desimodel.io.load_desiparams()
        wavemin = params['ccd']['b']['wavemin']
        wavemax = params['ccd']['z']['wavemax']
    except KeyError:
        wavemin = desimodel.io.load_throughput('b').wavemin
        wavemax = desimodel.io.load_throughput('z').wavemax
    dw = 0.2
    wave = np.arange(round(wavemin, 1), wavemax, dw)
    nwave = len(wave)

    flux = np.zeros( (nspec, len(wave)) )
    meta, _ = empty_metatable(nmodel=nspec, objtype='SKY')
    objmeta = dict()
    fibermap = empty_fibermap(nspec)

    targetid = np.random.randint(sys.maxsize, size=nspec).astype(np.int64)
    meta['TARGETID'] = targetid
    fibermap['TARGETID'] = targetid
    
    for objtype in set(true_objtype):
        ii = np.where(true_objtype == objtype)[0]
        nobj = len(ii)

        fibermap['OBJTYPE'][ii] = target_objtype[ii]

        if objtype in specify_targets.keys():
            obj_kwargs = specify_targets[objtype]
        else:
            obj_kwargs = dict()
                
        # Simulate spectra
        if objtype == 'SKY':
            fibermap['DESI_TARGET'][ii] = desi_mask.SKY
            continue

        elif objtype == 'ELG':
            from desisim.templates import ELG
            elg = ELG(wave=wave)
            simflux, wave1, meta1, objmeta1 = elg.make_templates(nmodel=nobj, seed=seed, **obj_kwargs)
            fibermap['DESI_TARGET'][ii] = desi_mask.ELG

        elif objtype == 'LRG':
            from desisim.templates import LRG
            lrg = LRG(wave=wave)
            simflux, wave1, meta1, objmeta1 = lrg.make_templates(nmodel=nobj, seed=seed, **obj_kwargs)
            fibermap['DESI_TARGET'][ii] = desi_mask.LRG

        elif objtype == 'BGS':
            from desisim.templates import BGS
            bgs = BGS(wave=wave)
            simflux, wave1, meta1, objmeta1 = bgs.make_templates(nmodel=nobj, seed=seed, **obj_kwargs)
            fibermap['DESI_TARGET'][ii] = desi_mask.BGS_ANY
            fibermap['BGS_TARGET'][ii] = bgs_mask.BGS_BRIGHT

        elif objtype == 'QSO':
            from desisim.templates import QSO
            qso = QSO(wave=wave)
            simflux, wave1, meta1, objmeta1 = qso.make_templates(nmodel=nobj, seed=seed, lyaforest=False, **obj_kwargs)
            fibermap['DESI_TARGET'][ii] = desi_mask.QSO

        # For a "bad" QSO simulate a normal star without color cuts, which isn't
        # right. We need to apply the QSO color-cuts to the normal stars to pull
        # out the correct population of contaminating stars.

        # Note by @moustakas: we can now do this using desisim/#150, but we are
        # going to need 'noisy' photometry (because the QSO color-cuts
        # explicitly avoid the stellar locus).
        elif objtype == 'QSO_BAD':
            from desisim.templates import STAR
            #from desitarget.cuts import isQSO
            #star = STAR(wave=wave, colorcuts_function=isQSO)
            star = STAR(wave=wave)
            simflux, wave1, meta1, objmeta1 = star.make_templates(nmodel=nobj, seed=seed, **obj_kwargs)
            fibermap['DESI_TARGET'][ii] = desi_mask.QSO

        elif objtype == 'STD':
            from desisim.templates import STD
            std = STD(wave=wave)
            simflux, wave1, meta1, objmeta1 = std.make_templates(nmodel=nobj, seed=seed, **obj_kwargs)
            #- Loop options for forwards/backwards compatibility
            for name in ['STD_FAINT', 'STD_FSTAR', 'STD']:
                if name in desi_mask.names():
                    fibermap['DESI_TARGET'][ii] |= desi_mask[name]
                    break

        elif objtype == 'MWS_STAR':
            from desisim.templates import MWS_STAR
            mwsstar = MWS_STAR(wave=wave)
            # TODO: mag ranges for different programs of STAR targets should be in desimodel
            if 'magrange' not in obj_kwargs.keys():
                obj_kwargs['magrange'] = (15.0,20.0)
            simflux, wave1, meta1, objmeta1 = mwsstar.make_templates(nmodel=nobj, seed=seed, **obj_kwargs)
            fibermap['DESI_TARGET'][ii] |= desi_mask.MWS_ANY
            #- MWS bit names changed after desitarget 0.6.0 so use number
            #- instead of name for now (bit 0 = mask 1 = MWS_MAIN currently)
            fibermap['MWS_TARGET'][ii] = 1

        else:
            raise ValueError('Unable to simulate OBJTYPE={}'.format(objtype))

        # Assign targetid
        meta1['TARGETID'] = targetid[ii]
        if hasattr(objmeta1, 'data'): # simqso.sqgrids.QsoSimPoints object
            objmeta1.data['TARGETID'] = targetid[ii]
        else:
            if len(objmeta1) > 0:
                objmeta1['TARGETID'] = targetid[ii]
                # We want the dict key tied to the "true" object type (e.g., STAR),
                # not, e.g., QSO_BAD.
                objmeta[meta1['OBJTYPE'][0]] = objmeta1

        flux[ii] = simflux
        meta[ii] = meta1

        for band in ['G', 'R', 'Z', 'W1', 'W2']:
            key = 'FLUX_'+band
            fibermap[key][ii] = meta[key][ii]
            #- TODO: FLUX_IVAR

    #- Load fiber -> positioner mapping and tile information
    fiberpos = desimodel.io.load_fiberpos()

    #- Where are these targets?  Centered on positioners for now.
    x = fiberpos['X'][specmin:specmin+nspec]
    y = fiberpos['Y'][specmin:specmin+nspec]
    fp = FocalPlane(tile_ra, tile_dec)
    ra = np.zeros(nspec)
    dec = np.zeros(nspec)
    for i in range(nspec):
        ra[i], dec[i] = fp.xy2radec(x[i], y[i])

    #- Fill in the rest of the fibermap structure
    fibermap['FIBER'] = np.arange(nspec, dtype='i4')
    fibermap['POSITIONER'] = fiberpos['POSITIONER'][specmin:specmin+nspec]
    fibermap['SPECTROID'] = fiberpos['SPECTROGRAPH'][specmin:specmin+nspec]
    fibermap['TARGETCAT'] = np.zeros(nspec, dtype=(str, 20))
    fibermap['LAMBDA_REF'] = np.ones(nspec, dtype=np.float32)*5400
    fibermap['TARGET_RA'] = ra
    fibermap['TARGET_DEC'] = dec
    fibermap['DESIGN_X'] = x
    fibermap['DESIGN_Y'] = y
    fibermap['FIBER_RA'] = fibermap['TARGET_RA']
    fibermap['FIBER_DEC'] = fibermap['TARGET_DEC']
    fibermap['BRICKNAME'] = brick.brickname(ra, dec)

    return fibermap, (flux, wave, meta, objmeta)