def update_obslog(obstype='science', program='DARK', expid=None, dateobs=None, tileid=-1, ra=None, dec=None): """ Update obslog with a new exposure obstype : 'arc', 'flat', 'bias', 'test', 'science', ... program : 'DARK', 'GRAY', 'BRIGHT', 'CALIB' expid : integer exposure ID, default from get_next_expid() dateobs : time.struct_time tuple; default time.localtime() tileid : integer TileID, default -1, i.e. not a DESI tile ra, dec : float (ra, dec) coordinates, default tile ra,dec or (0,0) returns tuple (expid, dateobs) TODO: normalize obstype vs. program; see desisim issue #97 """ #- Connect to sqlite database file and create DB if needed dbdir = io.simdir() + '/etc' if not os.path.exists(dbdir): os.makedirs(dbdir) dbfile = dbdir+'/obslog.sqlite' with sqlite3.connect(dbfile, isolation_level="EXCLUSIVE") as db: db.execute("""\ CREATE TABLE IF NOT EXISTS obslog ( expid INTEGER PRIMARY KEY, dateobs DATETIME, -- seconds since Unix Epoch (1970) night TEXT, -- YEARMMDD obstype TEXT DEFAULT "science", program TEXT DEFAULT "DARK", tileid INTEGER DEFAULT -1, ra REAL DEFAULT 0.0, dec REAL DEFAULT 0.0 ) """) #- Fill in defaults if expid is None: expid = get_next_expid() if dateobs is None: dateobs = time.localtime() if ra is None: assert (dec is None) if tileid < 0: ra, dec = (0.0, 0.0) else: ra, dec = io.get_tile_radec(tileid) night = get_night(utc=dateobs) insert = """\ INSERT OR REPLACE INTO obslog(expid,dateobs,night,obstype,program,tileid,ra,dec) VALUES (?,?,?,?,?,?,?,?) """ db.execute(insert, (int(expid), time.mktime(dateobs), str(night), str(obstype.upper()), str(program.upper()), int(tileid), float(ra), float(dec))) db.commit() return expid, dateobs
def update_obslog(obstype='science', expid=None, dateobs=None, tileid=-1, ra=None, dec=None): """ Update obslog with a new exposure obstype : 'science', 'arc', 'flat', 'bias', 'dark', or 'test' expid : integer exposure ID, default from get_next_expid() dateobs : time.struct_time tuple; default time.localtime() tileid : integer TileID, default -1, i.e. not a DESI tile ra, dec : float (ra, dec) coordinates, default tile ra,dec or (0,0) returns tuple (expid, dateobs) """ #- Connect to sqlite database file and create DB if needed dbdir = io.simdir() + '/etc' if not os.path.exists(dbdir): os.makedirs(dbdir) dbfile = dbdir+'/obslog.sqlite' db = sqlite3.connect(dbfile) db.execute("""\ CREATE TABLE IF NOT EXISTS obslog ( expid INTEGER PRIMARY KEY, dateobs DATETIME, -- seconds since Unix Epoch (1970) night TEXT, -- YEARMMDD obstype TEXT DEFAULT "science", tileid INTEGER DEFAULT -1, ra REAL DEFAULT 0.0, dec REAL DEFAULT 0.0 ) """) #- Fill in defaults if expid is None: expid = get_next_expid() if dateobs is None: dateobs = time.localtime() if ra is None: assert (dec is None) if tileid < 0: ra, dec = (0.0, 0.0) else: ra, dec = io.get_tile_radec(tileid) night = get_night(utc=dateobs) insert = """\ INSERT OR REPLACE INTO obslog(expid,dateobs,night,obstype,tileid,ra,dec) VALUES (?,?,?,?,?,?,?) """ db.execute(insert, (expid, time.mktime(dateobs), night, obstype, tileid, ra, dec)) db.commit() return expid, dateobs
def update_obslog(obstype='science', expid=None, dateobs=None, tileid=-1, ra=None, dec=None): """ Update obslog with a new exposure obstype : 'science', 'arc', 'flat', 'bias', 'dark', or 'test' expid : integer exposure ID, default from get_next_expid() dateobs : time.struct_time tuple; default time.localtime() tileid : integer TileID, default -1, i.e. not a DESI tile ra, dec : float (ra, dec) coordinates, default tile ra,dec or (0,0) returns tuple (expid, dateobs) """ #- Connect to sqlite database file and create DB if needed dbdir = io.simdir() + '/etc' if not os.path.exists(dbdir): os.makedirs(dbdir) dbfile = dbdir + '/obslog.sqlite' db = sqlite3.connect(dbfile) db.execute("""\ CREATE TABLE IF NOT EXISTS obslog ( expid INTEGER PRIMARY KEY, dateobs DATETIME, -- seconds since Unix Epoch (1970) night TEXT, -- YEARMMDD obstype TEXT DEFAULT "science", tileid INTEGER DEFAULT -1, ra REAL DEFAULT 0.0, dec REAL DEFAULT 0.0 ) """) #- Fill in defaults if expid is None: expid = get_next_expid() if dateobs is None: dateobs = time.localtime() if ra is None: assert (dec is None) if tileid < 0: ra, dec = (0.0, 0.0) else: ra, dec = io.get_tile_radec(tileid) night = get_night(utc=dateobs) insert = """\ INSERT OR REPLACE INTO obslog(expid,dateobs,night,obstype,tileid,ra,dec) VALUES (?,?,?,?,?,?,?) """ db.execute(insert, (expid, time.mktime(dateobs), night, obstype, tileid, ra, dec)) db.commit() return expid, dateobs
def new_exposure(flavor, nspec=5000, night=None, expid=None, tileid=None, \ airmass=1.0, exptime=None): """ Create a new exposure and output input simulation files. Does not generate pixel-level simulations or noisy spectra. Args: nspec (optional): integer number of spectra to simulate night (optional): YEARMMDD string expid (optional): positive integer exposure ID tileid (optional): tile ID airmass (optional): airmass, default 1.0 Writes: $DESI_SPECTRO_SIM/$PIXPROD/{night}/fibermap-{expid}.fits $DESI_SPECTRO_SIM/$PIXPROD/{night}/simspec-{expid}.fits Returns: fibermap numpy structured array truth dictionary """ if expid is None: expid = get_next_expid() if tileid is None: tileid = get_next_tileid() if night is None: #- simulation obs time = now, even if sun is up dateobs = time.gmtime() night = get_night(utc=dateobs) else: #- 10pm on night YEARMMDD dateobs = time.strptime(night + ':22', '%Y%m%d:%H') params = desimodel.io.load_desiparams() if flavor == 'arc': infile = os.getenv( 'DESI_ROOT' ) + '/spectro/templates/calib/v0.2/arc-lines-average.fits' d = fits.getdata(infile, 1) wave = d['AIRWAVE'] phot = d['ELECTRONS'] truth = dict(WAVE=wave) meta = None fibermap = desispec.io.fibermap.empty_fibermap(nspec) for channel in ('B', 'R', 'Z'): thru = desimodel.io.load_throughput(channel) ii = np.where((thru.wavemin <= wave) & (wave <= thru.wavemax))[0] truth['WAVE_' + channel] = wave[ii] truth['PHOT_' + channel] = np.tile(phot[ii], nspec).reshape(nspec, len(ii)) elif flavor == 'flat': infile = os.getenv( 'DESI_ROOT' ) + '/spectro/templates/calib/v0.2/flat-3100K-quartz-iodine.fits' flux = fits.getdata(infile, 0) hdr = fits.getheader(infile, 0) wave = desispec.io.util.header2wave(hdr) #- resample to 0.2 A grid dw = 0.2 ww = np.arange(wave[0], wave[-1] + dw / 2, dw) flux = resample_flux(ww, wave, flux) wave = ww #- Convert to 2D for projection flux = np.tile(flux, nspec).reshape(nspec, len(wave)) truth = dict(WAVE=wave, FLUX=flux) meta = None fibermap = desispec.io.fibermap.empty_fibermap(nspec) for channel in ('B', 'R', 'Z'): thru = desimodel.io.load_throughput(channel) ii = (thru.wavemin <= wave) & (wave <= thru.wavemax) phot = thru.photons(wave[ii], flux[:, ii], units=hdr['BUNIT'], objtype='CALIB', exptime=10) truth['WAVE_' + channel] = wave[ii] truth['PHOT_' + channel] = phot elif flavor == 'science': fibermap, truth = get_targets(nspec, tileid=tileid) flux = truth['FLUX'] wave = truth['WAVE'] nwave = len(wave) if exptime is None: exptime = params['exptime'] #- Load sky [Magic knowledge of units 1e-17 erg/s/cm2/A/arcsec2] skyfile = os.getenv('DESIMODEL') + '/data/spectra/spec-sky.dat' skywave, skyflux = np.loadtxt(skyfile, unpack=True) skyflux = np.interp(wave, skywave, skyflux) truth['SKYFLUX'] = skyflux for channel in ('B', 'R', 'Z'): thru = desimodel.io.load_throughput(channel) ii = np.where((thru.wavemin <= wave) & (wave <= thru.wavemax))[0] #- Project flux to photons phot = thru.photons(wave[ii], flux[:, ii], units=truth['UNITS'], objtype=truth['OBJTYPE'], exptime=exptime, airmass=airmass) truth['PHOT_' + channel] = phot truth['WAVE_' + channel] = wave[ii] #- Project sky flux to photons skyphot = thru.photons(wave[ii], skyflux[ii] * airmass, units='1e-17 erg/s/cm2/A/arcsec2', objtype='SKY', exptime=exptime, airmass=airmass) #- 2D version ### truth['SKYPHOT_'+channel] = np.tile(skyphot, nspec).reshape((nspec, len(ii))) #- 1D version truth['SKYPHOT_' + channel] = skyphot.astype(np.float32) #- NOTE: someday skyflux and skyphot may be 2D instead of 1D #- Extract the metadata part of the truth dictionary into a table columns = ( 'OBJTYPE', 'REDSHIFT', 'TEMPLATEID', 'D4000', 'OIIFLUX', 'VDISP', ) meta = {key: truth[key] for key in columns} #- (end indentation for arc/flat/science flavors) #- Override $DESI_SPECTRO_DATA in order to write to simulation area datadir_orig = os.getenv('DESI_SPECTRO_DATA') simbase = os.path.join(os.getenv('DESI_SPECTRO_SIM'), os.getenv('PIXPROD')) os.environ['DESI_SPECTRO_DATA'] = simbase #- Write fibermap telera, teledec = io.get_tile_radec(tileid) hdr = dict( NIGHT=(night, 'Night of observation YEARMMDD'), EXPID=(expid, 'DESI exposure ID'), TILEID=(tileid, 'DESI tile ID'), FLAVOR=(flavor, 'Flavor [arc, flat, science, ...]'), TELRA=(telera, 'Telescope pointing RA [degrees]'), TELDEC=(teledec, 'Telescope pointing dec [degrees]'), ) #- ISO 8601 DATE-OBS year-mm-ddThh:mm:ss fiberfile = desispec.io.findfile('fibermap', night, expid) desispec.io.write_fibermap(fiberfile, fibermap, header=hdr) print fiberfile #- Write simspec; expand fibermap header hdr['AIRMASS'] = (airmass, 'Airmass at middle of exposure') hdr['EXPTIME'] = (exptime, 'Exposure time [sec]') hdr['DATE-OBS'] = (time.strftime('%FT%T', dateobs), 'Start of exposure') simfile = io.write_simspec(meta, truth, expid, night, header=hdr) print(simfile) #- Update obslog that we succeeded with this exposure update_obslog(flavor, expid, dateobs, tileid) #- Restore $DESI_SPECTRO_DATA if datadir_orig is not None: os.environ['DESI_SPECTRO_DATA'] = datadir_orig else: del os.environ['DESI_SPECTRO_DATA'] return fibermap, truth
def new_exposure(flavor, nspec=5000, night=None, expid=None, tileid=None, airmass=1.0, \ exptime=None): """ Create a new exposure and output input simulation files. Does not generate pixel-level simulations or noisy spectra. Args: nspec (optional): integer number of spectra to simulate night (optional): YEARMMDD string expid (optional): positive integer exposure ID tileid (optional): tile ID airmass (optional): airmass, default 1.0 Writes: $DESI_SPECTRO_SIM/$PIXPROD/{night}/fibermap-{expid}.fits $DESI_SPECTRO_SIM/$PIXPROD/{night}/simspec-{expid}.fits Returns: fibermap numpy structured array truth dictionary """ if expid is None: expid = get_next_expid() if tileid is None: tileid = get_next_tileid() if night is None: #- simulation obs time = now, even if sun is up dateobs = time.gmtime() night = get_night(utc=dateobs) else: #- 10pm on night YEARMMDD dateobs = time.strptime(night+':22', '%Y%m%d:%H') params = desimodel.io.load_desiparams() if flavor == 'arc': infile = os.getenv('DESI_ROOT')+'/spectro/templates/calib/v0.1/arc-lines-average.fits' d = fits.getdata(infile, 1) wave = d['AIRWAVE'] phot = d['ELECTRONS'] truth = dict(WAVE=wave) meta = None fibermap = desispec.io.fibermap.empty_fibermap(nspec) for channel in ('B', 'R', 'Z'): thru = desimodel.io.load_throughput(channel) ii = np.where( (thru.wavemin <= wave) & (wave <= thru.wavemax) )[0] truth['WAVE_'+channel] = wave[ii] truth['PHOT_'+channel] = np.tile(phot[ii], nspec).reshape(nspec, len(ii)) elif flavor == 'flat': infile = os.getenv('DESI_ROOT')+'/spectro/templates/calib/v0.1/flat-3100K-quartz-iodine.fits' flux = fits.getdata(infile, 0) hdr = fits.getheader(infile, 0) wave = desispec.io.util.header2wave(hdr) #- resample to 0.2 A grid dw = 0.2 ww = np.arange(wave[0], wave[-1]+dw/2, dw) flux = resample_flux(ww, wave, flux) wave = ww #- Convert to 2D for projection flux = np.tile(flux, nspec).reshape(nspec, len(wave)) truth = dict(WAVE=wave, FLUX=flux) meta = None fibermap = desispec.io.fibermap.empty_fibermap(nspec) for channel in ('B', 'R', 'Z'): psf = desimodel.io.load_psf(channel) thru = desimodel.io.load_throughput(channel) ii = (psf.wmin <= wave) & (wave <= psf.wmax) phot = thru.photons(wave[ii], flux[:,ii], units=hdr['BUNIT'], objtype='CALIB') truth['WAVE_'+channel] = wave[ii] truth['PHOT_'+channel] = phot elif flavor == 'science': fibermap, truth = get_targets(nspec, tileid=tileid) flux = truth['FLUX'] wave = truth['WAVE'] nwave = len(wave) if exptime is None: exptime = params['exptime'] #- Load sky [Magic knowledge of units 1e-17 erg/s/cm2/A/arcsec2] skyfile = os.getenv('DESIMODEL')+'/data/spectra/spec-sky.dat' skywave, skyflux = np.loadtxt(skyfile, unpack=True) skyflux = np.interp(wave, skywave, skyflux) truth['SKYFLUX'] = skyflux for channel in ('B', 'R', 'Z'): thru = desimodel.io.load_throughput(channel) ii = np.where( (thru.wavemin <= wave) & (wave <= thru.wavemax) )[0] #- Project flux to photons phot = thru.photons(wave[ii], flux[:,ii], units='1e-17 erg/s/cm2/A', objtype=truth['OBJTYPE'], exptime=exptime, airmass=airmass) truth['PHOT_'+channel] = phot truth['WAVE_'+channel] = wave[ii] #- Project sky flux to photons skyphot = thru.photons(wave[ii], skyflux[ii]*airmass, units='1e-17 erg/s/cm2/A/arcsec2', objtype='SKY', exptime=exptime, airmass=airmass) #- 2D version ### truth['SKYPHOT_'+channel] = np.tile(skyphot, nspec).reshape((nspec, len(ii))) #- 1D version truth['SKYPHOT_'+channel] = skyphot.astype(np.float32) #- NOTE: someday skyflux and skyphot may be 2D instead of 1D #- Extract the metadata part of the truth dictionary into a table columns = ( 'OBJTYPE', 'REDSHIFT', 'TEMPLATEID', 'O2FLUX', ) meta = _dict2ndarray(truth, columns) #- (end indentation for arc/flat/science flavors) #- Write fibermap telera, teledec = io.get_tile_radec(tileid) hdr = dict( NIGHT = (night, 'Night of observation YEARMMDD'), EXPID = (expid, 'DESI exposure ID'), TILEID = (tileid, 'DESI tile ID'), FLAVOR = (flavor, 'Flavor [arc, flat, science, ...]'), TELERA = (telera, 'Telescope pointing RA [degrees]'), TELEDEC = (teledec, 'Telescope pointing dec [degrees]'), ) fiberfile = desispec.io.findfile('fibermap', night, expid) desispec.io.write_fibermap(fiberfile, fibermap, header=hdr) print fiberfile #- Write simfile hdr = dict( AIRMASS=(airmass, 'Airmass at middle of exposure'), EXPTIME=(exptime, 'Exposure time [sec]'), FLAVOR=(flavor, 'exposure flavor [arc, flat, science]'), ) simfile = io.write_simspec(meta, truth, expid, night, header=hdr) print simfile #- Update obslog that we succeeded with this exposure update_obslog(flavor, expid, dateobs, tileid) return fibermap, truth
def new_exposure(program, nspec=5000, night=None, expid=None, tileid=None, nproc=None, seed=None, obsconditions=None, specify_targets=dict(), testslit=False, exptime=None, arc_lines_filename=None, flat_spectrum_filename=None, outdir=None, config='desi', telescope=None, overwrite=False): """ Create a new exposure and output input simulation files. Does not generate pixel-level simulations or noisy spectra. Args: program (str): 'arc', 'flat', 'bright', 'dark', 'bgs', 'mws', ... nspec (int, optional): number of spectra to simulate night (str, optional): YEARMMDD string expid (int, optional): positive integer exposure ID tileid (int, optional): integer tile ID nproc (object, optional): What does this do? seed (int, optional): random seed obsconditions (str or dict-like, optional): see options below specify_targets (dict of dicts, optional): 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() testslit (bool, optional): simulate test slit if True, default False; only for arc/flat exptime (float, optional): exposure time [seconds], overrides obsconditions['EXPTIME'] arc_lines_filename (str, optional): use alternate arc lines filename (used if program="arc") flat_spectrum_filename (str, optional): use alternate flat spectrum filename (used if program="flat") outdir (str, optional): output directory config (str, optional): the yaml configuration to load telescope (str, optional): the telescope used (i.e. 1m, 160mm) overwrite (bool, optional): optionally clobber existing files Returns: science: sim, fibermap, meta, obsconditions, objmeta Writes to outdir or $DESI_SPECTRO_SIM/$PIXPROD/{night}/ * fibermap-{expid}.fits * simspec-{expid}.fits input obsconditions can be a string 'dark', 'gray', 'bright', or dict-like observation metadata with keys SEEING (arcsec), EXPTIME (sec), AIRMASS, MOONFRAC (0-1), MOONALT (deg), MOONSEP (deg). Output obsconditions is is expanded dict-like structure. program is used to pick the sky brightness, and is propagated to desisim.targets.sample_objtype() to get the correct distribution of targets for a given program, e.g. ELGs, LRGs, QSOs for program='dark'. if program is 'arc' or 'flat', then `sim` is truth table with keys FLUX and WAVE; and meta=None and obsconditions=None. Also see simexp.simarc(), .simflat(), and .simscience(), the last of which simulates a science exposure given surveysim obsconditions input, fiber assignments, and pre-generated mock target spectra. """ if expid is None: expid = get_next_expid() if tileid is None: tileid = get_next_tileid() if night is None: #- simulation obs time = now, even if sun is up dateobs = time.gmtime() night = get_night(utc=dateobs) else: #- 10pm on night YEARMMDD night = str(night) #- just in case we got an integer instead of string dateobs = time.strptime(night + ':22', '%Y%m%d:%H') outsimspec = desisim.io.findfile('simspec', night, expid) outfibermap = desisim.io.findfile('simfibermap', night, expid) if outdir is not None: outsimspec = os.path.join(outdir, os.path.basename(outsimspec)) outfibermap = os.path.join(outdir, os.path.basename(outfibermap)) program = program.lower() log.debug('Generating {} targets'.format(nspec)) header = dict(NIGHT=night, EXPID=expid, PROGRAM=program) if program in ('arc', 'flat'): header['FLAVOR'] = program else: header['FLAVOR'] = 'science' #- ISO 8601 DATE-OBS year-mm-ddThh:mm:ss header['DATE-OBS'] = time.strftime('%FT%T', dateobs) if program == 'arc': if arc_lines_filename is None: infile = os.getenv( 'DESI_ROOT' ) + '/spectro/templates/calib/v0.4/arc-lines-average-in-vacuum-from-winlight-20170118.fits' else: infile = arc_lines_filename arcdata = fits.getdata(infile, 1) if exptime is None: exptime = 5 wave, phot, fibermap = desisim.simexp.simarc(arcdata, nspec=nspec, testslit=testslit) header['EXPTIME'] = exptime desisim.io.write_simspec_arc(outsimspec, wave, phot, header, fibermap=fibermap, overwrite=overwrite) fibermap.meta['NIGHT'] = night fibermap.meta['EXPID'] = expid desispec.io.write_fibermap(outfibermap, fibermap) truth = dict(WAVE=wave, PHOT=phot, UNITS='photon') return truth, fibermap, None, None, None elif program == 'flat': if flat_spectrum_filename is None: infile = os.getenv( 'DESI_ROOT' ) + '/spectro/templates/calib/v0.4/flat-3100K-quartz-iodine.fits' else: infile = flat_spectrum_filename if exptime is None: exptime = 10 sim, fibermap = desisim.simexp.simflat(infile, nspec=nspec, exptime=exptime, testslit=testslit, psfconvolve=False) header['EXPTIME'] = exptime header['FLAVOR'] = 'flat' desisim.io.write_simspec(sim, truth=None, fibermap=fibermap, obs=None, expid=expid, night=night, header=header, filename=outsimspec, overwrite=overwrite) fibermap.meta['NIGHT'] = night fibermap.meta['EXPID'] = expid desispec.io.write_fibermap(outfibermap, fibermap) # fluxunits = 1e-17 * u.erg / (u.s * u.cm**2 * u.Angstrom) fluxunits = '1e-17 erg/(s * cm2 * Angstrom)' flux = sim.simulated['source_flux'].to(fluxunits) wave = sim.simulated['wavelength'].to('Angstrom') truth = dict(WAVE=wave, FLUX=flux, UNITS=str(fluxunits)) return truth, fibermap, None, None, None #- all other programs fibermap, (flux, wave, meta, objmeta) = get_targets_parallel(nspec, program, tileid=tileid, nproc=nproc, seed=seed, specify_targets=specify_targets, config=config, telescope=telescope) if obsconditions is None: if program in ['dark', 'lrg', 'qso']: obsconditions = desisim.simexp.reference_conditions['DARK'] elif program in ['elg', 'gray', 'grey']: obsconditions = desisim.simexp.reference_conditions['GRAY'] elif program in ['mws', 'bgs', 'bright']: obsconditions = desisim.simexp.reference_conditions['BRIGHT'] else: raise ValueError('unknown program {}'.format(program)) elif isinstance(obsconditions, str): try: obsconditions = desisim.simexp.reference_conditions[ obsconditions.upper()] except KeyError: raise ValueError('obsconditions {} not in {}'.format( obsconditions.upper(), list(desisim.simexp.reference_conditions.keys()))) if exptime is not None: obsconditions['EXPTIME'] = exptime desiparams = load_desiparams(config=config, telescope=telescope) sim = simulate_spectra(wave, flux, fibermap=fibermap, obsconditions=obsconditions, psfconvolve=False, specsim_config_file=config, params=desiparams) #- Write fibermap telera, teledec = io.get_tile_radec(tileid) hdr = dict( NIGHT=(night, 'Night of observation YEARMMDD'), EXPID=(expid, 'DESI exposure ID'), TILEID=(tileid, 'DESI tile ID'), PROGRAM=(program, 'program [dark, bright, ...]'), FLAVOR=('science', 'Flavor [arc, flat, science, zero, ...]'), TELRA=(telera, 'Telescope pointing RA [degrees]'), TELDEC=(teledec, 'Telescope pointing dec [degrees]'), AIRMASS=(obsconditions['AIRMASS'], 'Airmass at middle of exposure'), EXPTIME=(obsconditions['EXPTIME'], 'Exposure time [sec]'), SEEING=(obsconditions['SEEING'], 'Seeing FWHM [arcsec]'), MOONFRAC=(obsconditions['MOONFRAC'], 'Moon illumination fraction 0-1; 1=full'), MOONALT=(obsconditions['MOONALT'], 'Moon altitude [degrees]'), MOONSEP=(obsconditions['MOONSEP'], 'Moon:tile separation angle [degrees]'), ) hdr['DATE-OBS'] = (time.strftime('%FT%T', dateobs), 'Start of exposure') simfile = io.write_simspec(sim, meta, fibermap, obsconditions, expid, night, objmeta=objmeta, header=hdr, filename=outsimspec, overwrite=overwrite) if not isinstance(fibermap, table.Table): fibermap = table.Table(fibermap) fibermap.meta.update(hdr) desispec.io.write_fibermap(outfibermap, fibermap) log.info('Wrote ' + outfibermap) update_obslog(obstype='science', program=program, expid=expid, dateobs=dateobs, tileid=tileid) return sim, fibermap, meta, obsconditions, objmeta
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 get_targets(nspec, tileid=None): """ Returns: fibermap truth table TODO: document this better """ if tileid is None: tile_ra, tile_dec = 0.0, 0.0 else: tile_ra, tile_dec = io.get_tile_radec(tileid) #- Get distribution of target types true_objtype, target_objtype = sample_objtype(nspec) #- Get DESI wavelength coverage 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) truth = dict() truth['FLUX'] = np.zeros( (nspec, len(wave)) ) truth['REDSHIFT'] = np.zeros(nspec, dtype='f4') truth['TEMPLATEID'] = np.zeros(nspec, dtype='i4') truth['O2FLUX'] = np.zeros(nspec, dtype='f4') truth['OBJTYPE'] = np.zeros(nspec, dtype='S10') #- Note: unlike other elements, first index of WAVE isn't spectrum index truth['WAVE'] = wave fibermap = empty_fibermap(nspec) for objtype in set(true_objtype): ii = np.where(true_objtype == objtype)[0] fibermap['OBJTYPE'][ii] = target_objtype[ii] truth['OBJTYPE'][ii] = true_objtype[ii] if objtype == 'SKY': continue try: simflux, meta = io.read_templates(wave, objtype, len(ii)) except ValueError, err: print err continue truth['FLUX'][ii] = simflux #- STD don't have redshift Z; others do #- In principle we should also have redshifts (radial velocities) #- for standards as well. if 'Z' in meta.dtype.names: truth['REDSHIFT'][ii] = meta['Z'] elif objtype != 'STD': print "No redshifts for", objtype, len(ii) #- Only ELGs have [OII] flux if objtype == 'ELG': truth['O2FLUX'][ii] = meta['OII_3727'] #- Everyone had a templateid truth['TEMPLATEID'][ii] = meta['TEMPLATEID'] #- Extract magnitudes from colors #- TODO: make this more consistent at the input level #- Standard Stars have SDSS magnitudes if objtype == 'STD': magr = meta['SDSS_R'] magi = magr - meta['SDSS_RI'] magz = magi - meta['SDSS_IZ'] magg = magr - meta['SDSS_GR'] #- R-G, not G-R ? magu = magg - meta['SDSS_UG'] mags = np.vstack( [magu, magg, magr, magi, magz] ).T filters = ['SDSS_U', 'SDSS_G', 'SDSS_R', 'SDSS_I', 'SDSS_Z'] fibermap['MAG'][ii] = mags fibermap['FILTER'][ii] = filters #- LRGs elif objtype == 'LRG': magz = meta['DECAM_Z'] magr = magz - meta['DECAM_RZ'] magw = magr - meta['DECAM_RW1'] fibermap['MAG'][ii, 0:3] = np.vstack( [magr, magz, magw] ).T fibermap['FILTER'][ii, 0:3] = ['DECAM_R', 'DECAM_Z', 'WISE_W1'] #- ELGs elif objtype == 'ELG': magr = meta['DECAM_R'] magg = magr - meta['DECAM_GR'] magz = magr - meta['DECAM_RZ'] fibermap['MAG'][ii, 0:3] = np.vstack( [magg, magr, magz] ).T fibermap['FILTER'][ii, 0:3] = ['DECAM_G', 'DECAM_R', 'DECAM_Z'] elif objtype == 'QSO': #- QSO templates don't have magnitudes yet pass
def get_targets(nspec, tileid=None): """ Returns: fibermap truth table TODO (@moustakas): Deal with the random seed correctly. TODO: document this better """ if tileid is None: tile_ra, tile_dec = 0.0, 0.0 else: tile_ra, tile_dec = io.get_tile_radec(tileid) #- Get distribution of target types true_objtype, target_objtype = sample_objtype(nspec) #- Get DESI wavelength coverage 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) truth = dict() truth['FLUX'] = np.zeros((nspec, len(wave))) truth['REDSHIFT'] = np.zeros(nspec, dtype='f4') truth['TEMPLATEID'] = np.zeros(nspec, dtype='i4') truth['OIIFLUX'] = np.zeros(nspec, dtype='f4') truth['D4000'] = np.zeros(nspec, dtype='f4') truth['VDISP'] = np.zeros(nspec, dtype='f4') truth['OBJTYPE'] = np.zeros(nspec, dtype='S10') #- Note: unlike other elements, first index of WAVE isn't spectrum index truth['WAVE'] = wave fibermap = empty_fibermap(nspec) for objtype in set(true_objtype): ii = np.where(true_objtype == objtype)[0] nobj = len(ii) fibermap['OBJTYPE'][ii] = target_objtype[ii] truth['OBJTYPE'][ii] = true_objtype[ii] # Simulate spectra if objtype == 'SKY': continue elif objtype == 'ELG': from desisim.templates import ELG elg = ELG(wave=wave) simflux, wave1, meta = elg.make_templates(nmodel=nobj) elif objtype == 'LRG': from desisim.templates import LRG lrg = LRG(wave=wave) simflux, wave1, meta = lrg.make_templates(nmodel=nobj) elif objtype == 'QSO': from desisim.templates import QSO qso = QSO(wave=wave) simflux, wave1, meta = qso.make_templates(nmodel=nobj) # 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. elif objtype == 'QSO_BAD': from desisim.templates import STAR star = STAR(wave=wave) simflux, wave1, meta = star.make_templates(nmodel=nobj) elif objtype == 'STD': from desisim.templates import STAR star = STAR(wave=wave, FSTD=True) simflux, wave1, meta = star.make_templates(nmodel=nobj) truth['FLUX'][ii] = 1e17 * simflux truth['UNITS'] = '1e-17 erg/s/cm2/A' truth['TEMPLATEID'][ii] = meta['TEMPLATEID'] truth['REDSHIFT'][ii] = meta['REDSHIFT'] # Pack in the photometry. TODO: Include WISE. magg = meta['GMAG'] magr = meta['RMAG'] magz = meta['ZMAG'] fibermap['MAG'][ii, 0:3] = np.vstack([magg, magr, magz]).T fibermap['FILTER'][ii, 0:3] = ['DECAM_G', 'DECAM_R', 'DECAM_Z'] if objtype == 'ELG': truth['OIIFLUX'][ii] = meta['OIIFLUX'] truth['D4000'][ii] = meta['D4000'] truth['VDISP'][ii] = meta['VDISP'] if objtype == 'LRG': truth['D4000'][ii] = meta['D4000'] truth['VDISP'][ii] = meta['VDISP'] #- Load fiber -> positioner mapping and tile information fiberpos = desimodel.io.load_fiberpos() #- Where are these targets? Centered on positioners for now. x = fiberpos['X'][0:nspec] y = fiberpos['Y'][0: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'][0:nspec] fibermap['SPECTROID'] = fiberpos['SPECTROGRAPH'][0:nspec] fibermap['TARGETID'] = np.random.randint(sys.maxint, size=nspec) fibermap['TARGETCAT'] = np.zeros(nspec, dtype='|S20') fibermap['LAMBDAREF'] = np.ones(nspec, dtype=np.float32) * 5400 fibermap['TARGET_MASK0'] = np.zeros(nspec, dtype='i8') fibermap['RA_TARGET'] = ra fibermap['DEC_TARGET'] = dec fibermap['X_TARGET'] = x fibermap['Y_TARGET'] = y fibermap['X_FVCOBS'] = fibermap['X_TARGET'] fibermap['Y_FVCOBS'] = fibermap['Y_TARGET'] fibermap['X_FVCERR'] = np.zeros(nspec, dtype=np.float32) fibermap['Y_FVCERR'] = np.zeros(nspec, dtype=np.float32) fibermap['RA_OBS'] = fibermap['RA_TARGET'] fibermap['DEC_OBS'] = fibermap['DEC_TARGET'] fibermap['BRICKNAME'] = brick.brickname(ra, dec) return fibermap, truth
def get_targets(nspec, tileid=None): """ Returns: fibermap truth table TODO (@moustakas): Deal with the random seed correctly. TODO: document this better """ if tileid is None: tile_ra, tile_dec = 0.0, 0.0 else: tile_ra, tile_dec = io.get_tile_radec(tileid) # - Get distribution of target types true_objtype, target_objtype = sample_objtype(nspec) # - Get DESI wavelength coverage 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) truth = dict() truth["FLUX"] = np.zeros((nspec, len(wave))) truth["REDSHIFT"] = np.zeros(nspec, dtype="f4") truth["TEMPLATEID"] = np.zeros(nspec, dtype="i4") truth["OIIFLUX"] = np.zeros(nspec, dtype="f4") truth["D4000"] = np.zeros(nspec, dtype="f4") truth["OBJTYPE"] = np.zeros(nspec, dtype="S10") # - Note: unlike other elements, first index of WAVE isn't spectrum index truth["WAVE"] = wave fibermap = empty_fibermap(nspec) for objtype in set(true_objtype): ii = np.where(true_objtype == objtype)[0] nobj = len(ii) fibermap["OBJTYPE"][ii] = target_objtype[ii] truth["OBJTYPE"][ii] = true_objtype[ii] # Simulate spectra if objtype == "SKY": continue elif objtype == "ELG": from desisim.templates import ELG elg = ELG(nmodel=nobj, wave=wave) simflux, wave1, meta = elg.make_templates() elif objtype == "LRG": from desisim.templates import LRG lrg = LRG(nmodel=nobj, wave=wave) simflux, wave1, meta = lrg.make_templates() elif objtype == "QSO": from desisim.templates import QSO qso = QSO(nmodel=nobj, wave=wave) simflux, wave1, meta = qso.make_templates() # 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. elif objtype == "QSO_BAD": from desisim.templates import STAR star = STAR(nmodel=nobj, wave=wave) simflux, wave1, meta = star.make_templates() elif objtype == "STD": from desisim.templates import STAR star = STAR(nmodel=nobj, wave=wave, FSTD=True) simflux, wave1, meta = star.make_templates() truth["FLUX"][ii] = simflux truth["TEMPLATEID"][ii] = meta["TEMPLATEID"] truth["REDSHIFT"][ii] = meta["REDSHIFT"] # Pack in the photometry. TODO: Include WISE. magg = meta["GMAG"] magr = meta["RMAG"] magz = meta["ZMAG"] fibermap["MAG"][ii, 0:3] = np.vstack([magg, magr, magz]).T fibermap["FILTER"][ii, 0:3] = ["DECAM_G", "DECAM_R", "DECAM_Z"] if objtype == "ELG": truth["OIIFLUX"][ii] = meta["OIIFLUX"] truth["D4000"][ii] = meta["D4000"] if objtype == "LRG": truth["D4000"][ii] = meta["D4000"] # - Load fiber -> positioner mapping and tile information fiberpos = desimodel.io.load_fiberpos() # - Where are these targets? Centered on positioners for now. x = fiberpos["X"][0:nspec] y = fiberpos["Y"][0: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"][0:nspec] fibermap["SPECTROID"] = fiberpos["SPECTROGRAPH"][0:nspec] fibermap["TARGETID"] = np.random.randint(sys.maxint, size=nspec) fibermap["TARGETCAT"] = np.zeros(nspec, dtype="|S20") fibermap["LAMBDAREF"] = np.ones(nspec, dtype=np.float32) * 5400 fibermap["TARGET_MASK0"] = np.zeros(nspec, dtype="i8") fibermap["RA_TARGET"] = ra fibermap["DEC_TARGET"] = dec fibermap["X_TARGET"] = x fibermap["Y_TARGET"] = y fibermap["X_FVCOBS"] = fibermap["X_TARGET"] fibermap["Y_FVCOBS"] = fibermap["Y_TARGET"] fibermap["X_FVCERR"] = np.zeros(nspec, dtype=np.float32) fibermap["Y_FVCERR"] = np.zeros(nspec, dtype=np.float32) fibermap["RA_OBS"] = fibermap["RA_TARGET"] fibermap["DEC_OBS"] = fibermap["DEC_TARGET"] fibermap["BRICKNAME"] = brick.brickname(ra, dec) return fibermap, truth
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 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') fibermap = empty_fibermap(nspec) 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 = 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 = 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 = 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 = 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 = star.make_templates(nmodel=nobj, seed=seed, **obj_kwargs) fibermap['DESI_TARGET'][ii] = desi_mask.QSO elif objtype == 'STD': from desisim.templates import FSTD fstd = FSTD(wave=wave) simflux, wave1, meta1 = fstd.make_templates(nmodel=nobj, seed=seed, **obj_kwargs) fibermap['DESI_TARGET'][ii] = desi_mask.STD_FSTAR 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 'rmagrange' not in obj_kwargs.keys(): obj_kwargs['rmagrange'] = (15.0, 20.0) simflux, wave1, meta1 = 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)) flux[ii] = simflux meta[ii] = meta1 fibermap['FILTER'][ii, :6] = [ 'DECAM_G', 'DECAM_R', 'DECAM_Z', 'WISE_W1', 'WISE_W2' ] fibermap['MAG'][ii, 0] = 22.5 - 2.5 * np.log10(meta['FLUX_G'][ii]) fibermap['MAG'][ii, 1] = 22.5 - 2.5 * np.log10(meta['FLUX_R'][ii]) fibermap['MAG'][ii, 2] = 22.5 - 2.5 * np.log10(meta['FLUX_Z'][ii]) fibermap['MAG'][ii, 3] = 22.5 - 2.5 * np.log10(meta['FLUX_W1'][ii]) fibermap['MAG'][ii, 4] = 22.5 - 2.5 * np.log10(meta['FLUX_W2'][ii]) #- 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['TARGETID'] = np.random.randint(sys.maxsize, size=nspec) fibermap['TARGETCAT'] = np.zeros(nspec, dtype=(str, 20)) fibermap['LAMBDAREF'] = np.ones(nspec, dtype=np.float32) * 5400 fibermap['RA_TARGET'] = ra fibermap['DEC_TARGET'] = dec fibermap['X_TARGET'] = x fibermap['Y_TARGET'] = y fibermap['X_FVCOBS'] = fibermap['X_TARGET'] fibermap['Y_FVCOBS'] = fibermap['Y_TARGET'] fibermap['X_FVCERR'] = np.zeros(nspec, dtype=np.float32) fibermap['Y_FVCERR'] = np.zeros(nspec, dtype=np.float32) fibermap['RA_OBS'] = fibermap['RA_TARGET'] fibermap['DEC_OBS'] = fibermap['DEC_TARGET'] fibermap['BRICKNAME'] = brick.brickname(ra, dec) return fibermap, (flux, wave, meta)
def get_targets(nspec, tileid=None): """ Returns: fibermap truth table TODO: document this better """ if tileid is None: tile_ra, tile_dec = 0.0, 0.0 else: tile_ra, tile_dec = io.get_tile_radec(tileid) #- Get distribution of target types true_objtype, target_objtype = sample_objtype(nspec) #- Get DESI wavelength coverage 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) truth = dict() truth['FLUX'] = np.zeros((nspec, len(wave))) truth['REDSHIFT'] = np.zeros(nspec, dtype='f4') truth['TEMPLATEID'] = np.zeros(nspec, dtype='i4') truth['O2FLUX'] = np.zeros(nspec, dtype='f4') truth['OBJTYPE'] = np.zeros(nspec, dtype='S10') #- Note: unlike other elements, first index of WAVE isn't spectrum index truth['WAVE'] = wave fibermap = empty_fibermap(nspec) for objtype in set(true_objtype): ii = np.where(true_objtype == objtype)[0] fibermap['OBJTYPE'][ii] = target_objtype[ii] truth['OBJTYPE'][ii] = true_objtype[ii] if objtype == 'SKY': continue try: simflux, meta = io.read_templates(wave, objtype, len(ii)) except ValueError, err: print err continue truth['FLUX'][ii] = simflux #- STD don't have redshift Z; others do #- In principle we should also have redshifts (radial velocities) #- for standards as well. if 'Z' in meta.dtype.names: truth['REDSHIFT'][ii] = meta['Z'] elif objtype != 'STD': print "No redshifts for", objtype, len(ii) #- Only ELGs have [OII] flux if objtype == 'ELG': truth['O2FLUX'][ii] = meta['OII_3727'] #- Everyone had a templateid truth['TEMPLATEID'][ii] = meta['TEMPLATEID'] #- Extract magnitudes from colors #- TODO: make this more consistent at the input level #- Standard Stars have SDSS magnitudes if objtype == 'STD': magr = meta['SDSS_R'] magi = magr - meta['SDSS_RI'] magz = magi - meta['SDSS_IZ'] magg = magr - meta['SDSS_GR'] #- R-G, not G-R ? magu = magg - meta['SDSS_UG'] mags = np.vstack([magu, magg, magr, magi, magz]).T filters = ['SDSS_U', 'SDSS_G', 'SDSS_R', 'SDSS_I', 'SDSS_Z'] fibermap['MAG'][ii] = mags fibermap['FILTER'][ii] = filters #- LRGs elif objtype == 'LRG': magz = meta['DECAM_Z'] magr = magz - meta['DECAM_RZ'] magw = magr - meta['DECAM_RW1'] fibermap['MAG'][ii, 0:3] = np.vstack([magr, magz, magw]).T fibermap['FILTER'][ii, 0:3] = ['DECAM_R', 'DECAM_Z', 'WISE_W1'] #- ELGs elif objtype == 'ELG': magr = meta['DECAM_R'] magg = magr - meta['DECAM_GR'] magz = magr - meta['DECAM_RZ'] fibermap['MAG'][ii, 0:3] = np.vstack([magg, magr, magz]).T fibermap['FILTER'][ii, 0:3] = ['DECAM_G', 'DECAM_R', 'DECAM_Z'] elif objtype == 'QSO': #- QSO templates don't have magnitudes yet pass
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)
def new_exposure(program, nspec=5000, night=None, expid=None, tileid=None, nproc=None, seed=None, obsconditions=None, specify_targets=dict(), testslit=False, exptime=None, arc_lines_filename=None, flat_spectrum_filename=None, outdir=None, overwrite=False): """ Create a new exposure and output input simulation files. Does not generate pixel-level simulations or noisy spectra. Args: program (str): 'arc', 'flat', 'bright', 'dark', 'bgs', 'mws', ... nspec (int, optional): number of spectra to simulate night (str, optional): YEARMMDD string expid (int, optional): positive integer exposure ID tileid (int, optional): integer tile ID nproc (object, optional): What does this do? seed (int, optional): random seed obsconditions (str or dict-like, optional): see options below specify_targets (dict of dicts, optional): 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() testslit (bool, optional): simulate test slit if True, default False; only for arc/flat exptime (float, optional): exposure time [seconds], overrides obsconditions['EXPTIME'] arc_lines_filename (str, optional): use alternate arc lines filename (used if program="arc") flat_spectrum_filename (str, optional): use alternate flat spectrum filename (used if program="flat") outdir (str, optional): output directory overwrite (bool, optional): optionally clobber existing files Returns: science: sim, fibermap, meta, obsconditions, objmeta Writes to outdir or $DESI_SPECTRO_SIM/$PIXPROD/{night}/ * fibermap-{expid}.fits * simspec-{expid}.fits input obsconditions can be a string 'dark', 'gray', 'bright', or dict-like observation metadata with keys SEEING (arcsec), EXPTIME (sec), AIRMASS, MOONFRAC (0-1), MOONALT (deg), MOONSEP (deg). Output obsconditions is is expanded dict-like structure. program is used to pick the sky brightness, and is propagated to desisim.targets.sample_objtype() to get the correct distribution of targets for a given program, e.g. ELGs, LRGs, QSOs for program='dark'. if program is 'arc' or 'flat', then `sim` is truth table with keys FLUX and WAVE; and meta=None and obsconditions=None. Also see simexp.simarc(), .simflat(), and .simscience(), the last of which simulates a science exposure given surveysim obsconditions input, fiber assignments, and pre-generated mock target spectra. """ if expid is None: expid = get_next_expid() if tileid is None: tileid = get_next_tileid() if night is None: #- simulation obs time = now, even if sun is up dateobs = time.gmtime() night = get_night(utc=dateobs) else: #- 10pm on night YEARMMDD night = str(night) #- just in case we got an integer instead of string dateobs = time.strptime(night+':22', '%Y%m%d:%H') outsimspec = desisim.io.findfile('simspec', night, expid) outfibermap = desisim.io.findfile('simfibermap', night, expid) if outdir is not None: outsimspec = os.path.join(outdir, os.path.basename(outsimspec)) outfibermap = os.path.join(outdir, os.path.basename(outfibermap)) program = program.lower() log.debug('Generating {} targets'.format(nspec)) header = dict(NIGHT=night, EXPID=expid, PROGRAM=program) if program in ('arc', 'flat'): header['FLAVOR'] = program else: header['FLAVOR'] = 'science' #- ISO 8601 DATE-OBS year-mm-ddThh:mm:ss header['DATE-OBS'] = time.strftime('%FT%T', dateobs) if program == 'arc': if arc_lines_filename is None : infile = os.getenv('DESI_ROOT')+'/spectro/templates/calib/v0.4/arc-lines-average-in-vacuum-from-winlight-20170118.fits' else : infile = arc_lines_filename arcdata = fits.getdata(infile, 1) if exptime is None: exptime = 5 wave, phot, fibermap = desisim.simexp.simarc(arcdata, nspec=nspec, testslit=testslit) header['EXPTIME'] = exptime desisim.io.write_simspec_arc(outsimspec, wave, phot, header, fibermap=fibermap, overwrite=overwrite) fibermap.meta['NIGHT'] = night fibermap.meta['EXPID'] = expid desispec.io.write_fibermap(outfibermap, fibermap) truth = dict(WAVE=wave, PHOT=phot, UNITS='photon') return truth, fibermap, None, None, None elif program == 'flat': if flat_spectrum_filename is None : infile = os.getenv('DESI_ROOT')+'/spectro/templates/calib/v0.4/flat-3100K-quartz-iodine.fits' else : infile = flat_spectrum_filename if exptime is None: exptime = 10 sim, fibermap = desisim.simexp.simflat(infile, nspec=nspec, exptime=exptime, testslit=testslit, psfconvolve=False) header['EXPTIME'] = exptime header['FLAVOR'] = 'flat' desisim.io.write_simspec(sim, truth=None, fibermap=fibermap, obs=None, expid=expid, night=night, header=header, filename=outsimspec, overwrite=overwrite) fibermap.meta['NIGHT'] = night fibermap.meta['EXPID'] = expid desispec.io.write_fibermap(outfibermap, fibermap) # fluxunits = 1e-17 * u.erg / (u.s * u.cm**2 * u.Angstrom) fluxunits = '1e-17 erg/(s * cm2 * Angstrom)' flux = sim.simulated['source_flux'].to(fluxunits) wave = sim.simulated['wavelength'].to('Angstrom') truth = dict(WAVE=wave, FLUX=flux, UNITS=str(fluxunits)) return truth, fibermap, None, None, None #- all other programs fibermap, (flux, wave, meta, objmeta) = get_targets_parallel(nspec, program, tileid=tileid, nproc=nproc, seed=seed, specify_targets=specify_targets) if obsconditions is None: if program in ['dark', 'lrg', 'qso']: obsconditions = desisim.simexp.reference_conditions['DARK'] elif program in ['elg', 'gray', 'grey']: obsconditions = desisim.simexp.reference_conditions['GRAY'] elif program in ['mws', 'bgs', 'bright']: obsconditions = desisim.simexp.reference_conditions['BRIGHT'] else: raise ValueError('unknown program {}'.format(program)) elif isinstance(obsconditions, str): try: obsconditions = desisim.simexp.reference_conditions[obsconditions.upper()] except KeyError: raise ValueError('obsconditions {} not in {}'.format( obsconditions.upper(), list(desisim.simexp.reference_conditions.keys()))) if exptime is not None: obsconditions['EXPTIME'] = exptime sim = simulate_spectra(wave, flux, fibermap=fibermap, obsconditions=obsconditions, psfconvolve=False) #- Write fibermap telera, teledec = io.get_tile_radec(tileid) hdr = dict( NIGHT = (night, 'Night of observation YEARMMDD'), EXPID = (expid, 'DESI exposure ID'), TILEID = (tileid, 'DESI tile ID'), PROGRAM = (program, 'program [dark, bright, ...]'), FLAVOR = ('science', 'Flavor [arc, flat, science, zero, ...]'), TELRA = (telera, 'Telescope pointing RA [degrees]'), TELDEC = (teledec, 'Telescope pointing dec [degrees]'), AIRMASS = (obsconditions['AIRMASS'], 'Airmass at middle of exposure'), EXPTIME = (obsconditions['EXPTIME'], 'Exposure time [sec]'), SEEING = (obsconditions['SEEING'], 'Seeing FWHM [arcsec]'), MOONFRAC = (obsconditions['MOONFRAC'], 'Moon illumination fraction 0-1; 1=full'), MOONALT = (obsconditions['MOONALT'], 'Moon altitude [degrees]'), MOONSEP = (obsconditions['MOONSEP'], 'Moon:tile separation angle [degrees]'), ) hdr['DATE-OBS'] = (time.strftime('%FT%T', dateobs), 'Start of exposure') simfile = io.write_simspec(sim, meta, fibermap, obsconditions, expid, night, objmeta=objmeta, header=hdr, filename=outsimspec, overwrite=overwrite) if not isinstance(fibermap, table.Table): fibermap = table.Table(fibermap) fibermap.meta.update(hdr) desispec.io.write_fibermap(outfibermap, fibermap) log.info('Wrote '+outfibermap) update_obslog(obstype='science', program=program, expid=expid, dateobs=dateobs, tileid=tileid) return sim, fibermap, meta, obsconditions, objmeta