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
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
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)
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
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
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)
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
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
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')
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
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
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), ))
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
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)