Skip to content

Commit

Permalink
Use constants PROGRAMS, PROGRAM_INDEX defined in Tiles
Browse files Browse the repository at this point in the history
  • Loading branch information
dkirkby committed Oct 14, 2018
1 parent d1b542a commit 09e8619
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 43 deletions.
22 changes: 9 additions & 13 deletions py/desisurvey/ephemerides.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import desiutil.log
import desisurvey.config
import desisurvey.utils
import desisurvey.tiles


class Ephemerides(object):
Expand Down Expand Up @@ -57,11 +58,6 @@ def __init__(self, start_date=None, stop_date=None, num_obj_steps=25,
self.log = desiutil.log.get_logger()
config = desisurvey.config.Configuration()

# Get the list of all programs in canonical order.
self.programs = list(config.programs.keys)
# Map program names to small integer indices.
self.program_index = {pname: pidx for pidx, pname in enumerate(self.programs)}

# Freeze IERS table for consistent results.
desisurvey.utils.freeze_iers()

Expand Down Expand Up @@ -403,7 +399,7 @@ def get_night_program(self, night, include_twilight=False, program_as_int=False)
if include_twilight:
start = night_ephem['brightdusk']
stop = night_ephem['brightdawn']
BRIGHT = self.program_index['BRIGHT']
BRIGHT = desisurvey.tiles.Tiles.PROGRAM_INDEX['BRIGHT']
if programs[0] != BRIGHT:
# Twilight adds a BRIGHT program at the start of the night.
programs = np.insert(programs, 0, BRIGHT)
Expand All @@ -419,7 +415,7 @@ def get_night_program(self, night, include_twilight=False, program_as_int=False)
changes = np.concatenate(([start], changes, [stop]))
if not program_as_int:
# Replace program indices with names.
programs = [self.programs[pidx] for pidx in programs]
programs = [desisurvey.tiles.Tiles.PROGRAMS[pidx] for pidx in programs]
return programs, changes

def tabulate_program(self, mjd, include_twilight=True, as_tuple=True):
Expand All @@ -446,9 +442,9 @@ def tabulate_program(self, mjd, include_twilight=True, as_tuple=True):
tuple or array
Tuple (dark, gray, bright) of boolean arrays that tabulates the
program at each input MJD or an array of small integer indices
into ``self.programs[]``, with the special value -1 indicating
DAYTIME. All output arrays have the same shape as the input
``mjd`` array.
into :attr:`desisurvey.tiles.Tiles.PROGRAMS`, with the special value
-1 indicating DAYTIME. All output arrays have the same shape as
the input ``mjd`` array.
"""
# Get the night of the earliest time.
mjd = np.asarray(mjd)
Expand Down Expand Up @@ -491,9 +487,9 @@ def tabulate_program(self, mjd, include_twilight=True, as_tuple=True):
else:
# Default value -1=DAYTIME.
program = np.full(mjd.shape, -1, np.int16)
program[dark] = self.program_index['DARK']
program[gray] = self.program_index['GRAY']
program[bright] = self.program_index['BRIGHT']
program[dark] = desisurvey.tiles.Tiles.PROGRAM_INDEX['DARK']
program[gray] = desisurvey.tiles.Tiles.PROGRAM_INDEX['GRAY']
program[bright] = desisurvey.tiles.Tiles.PROGRAM_INDEX['BRIGHT']
return program

def is_full_moon(self, night, num_nights=None):
Expand Down
25 changes: 13 additions & 12 deletions py/desisurvey/forecast.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ def __init__(self, use_twilight=False, tiles_file=None,
self.cummulative_days = np.cumsum(available, axis=1) / 24.
# Calculate program parameters.
ntiles, tsched, openfrac, dust, airmass = [], [], [], [], []
for program in tiles.programs:
for program in tiles.PROGRAMS:
tile_sel = tiles.program_mask[program]
ntiles.append(np.count_nonzero(tile_sel))
progindx = ephem.program_index[program]
progindx = tiles.PROGRAM_INDEX[program]
scheduled_sum = scheduled[progindx].sum()
tsched.append(scheduled_sum)
openfrac.append(available[progindx].sum() / scheduled_sum)
Expand All @@ -63,7 +63,7 @@ def __init__(self, use_twilight=False, tiles_file=None,
df['Scheduled time (hr)'] = tsched
df['Dome open fraction'] = openfrac
self.set_overheads()
df['Nominal exposure (s)'] = [nominal[p] for p in self.tiles.programs]
df['Nominal exposure (s)'] = [nominal[p] for p in self.tiles.PROGRAMS]
df['Dust factor'] = dust
df['Airmass factor'] = airmass
self.set_factors()
Expand All @@ -72,7 +72,7 @@ def summary(self):
"""Print a summary table of the forecast parameters.
"""
df = self.df.transpose()
df.rename({pidx: pname for pidx, pname in enumerate(self.tiles.programs)},
df.rename({pidx: pname for pidx, pname in enumerate(self.tiles.PROGRAMS)},
inplace=True, axis='columns')
return df

Expand All @@ -81,12 +81,13 @@ def set_overheads(self, update_margin=True,
split={'DARK': 100, 'GRAY': 100, 'BRIGHT': 75},
dead ={'DARK': 20, 'GRAY': 100, 'BRIGHT': 10}):
df = self.df
df['Setup overhead / tile (s)'] = [setup[p] for p in self.tiles.programs]
df['Cosmic split overhead / tile (s)'] = [split[p] for p in self.tiles.programs]
df['Operations overhead / tile (s)'] = [dead[p] for p in self.tiles.programs]
df['Setup overhead / tile (s)'] = [setup[p] for p in self.tiles.PROGRAMS]
df['Cosmic split overhead / tile (s)'] = [split[p] for p in self.tiles.PROGRAMS]
df['Operations overhead / tile (s)'] = [dead[p] for p in self.tiles.PROGRAMS]
df['Average available / tile (s)'] = (
df['Scheduled time (hr)'] * df['Dome open fraction'] /
df['Number of tiles'] * 3600 -
# Avoid division by zero for a program with no tiles.
np.maximum(1, df['Number of tiles']) * 3600 -
df['Setup overhead / tile (s)'] -
df['Cosmic split overhead / tile (s)'] -
df['Operations overhead / tile (s)'])
Expand All @@ -96,8 +97,8 @@ def set_factors(self, update_margin=True,
moon = {'DARK': 1.00, 'GRAY': 1.10, 'BRIGHT': 1.33},
weather = {'DARK': 1.22, 'GRAY': 1.20, 'BRIGHT': 1.16}):
df = self.df
df['Moon factor'] = [moon[p] for p in self.tiles.programs]
df['Weather factor'] = [weather[p] for p in self.tiles.programs]
df['Moon factor'] = [moon[p] for p in self.tiles.PROGRAMS]
df['Weather factor'] = [weather[p] for p in self.tiles.PROGRAMS]
df['Average required / tile (s)'] = (
df['Nominal exposure (s)'] *
df['Dust factor'] *
Expand All @@ -114,8 +115,8 @@ def update(self):
df['Average available / tile (s)'] /
df['Average required / tile (s)'] - 1)
self.pass_progress = np.zeros((self.tiles.npasses, self.num_nights))
for program in self.tiles.programs:
progidx = self.tiles.program_index[program]
for program in self.tiles.PROGRAMS:
progidx = self.tiles.PROGRAM_INDEX[program]
dtexp = (
df['Average required / tile (s)'] +
df['Setup overhead / tile (s)'] +
Expand Down
39 changes: 21 additions & 18 deletions py/desisurvey/tiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@


class Tiles(object):

# Define the valid programs in canonical order.
PROGRAMS = ['DARK', 'GRAY', 'BRIGHT']
# Define a mapping from program name to index 0,1,2.
# Note that this mapping is independent of the programs actually present
# in a tiles file.
PROGRAM_INDEX = {pname: pidx for pidx, pname in enumerate(PROGRAMS)}

"""Manage static info associated with the tiles file.
The ``tiles_file`` configuration parameter determines which tiles
Expand All @@ -32,10 +40,15 @@ class Tiles(object):
def __init__(self, tiles_file=None):
log = desiutil.log.get_logger()
config = desisurvey.config.Configuration()
valid_programs = list(config.programs.keys)
# Read the specified tiles file.
self.tiles_file = tiles_file or config.tiles_file()
tiles = desimodel.io.load_tiles(
onlydesi=True, extra=False, tilesfile=self.tiles_file)
# Check for any unknown program names.
tile_programs = np.unique(tiles['PROGRAM'])
unknown = set(tile_programs) - set(self.PROGRAMS)
if unknown:
raise RuntimeError('Cannot schedule unknown program(s): {}.'.format(unknown))
# Copy tile arrays.
self.tileID = tiles['TILEID'].copy()
self.passnum = tiles['PASS'].copy()
Expand All @@ -53,25 +66,16 @@ def __init__(self, tiles_file=None):
# Can remove this when tile_index no longer uses searchsorted.
if not np.all(np.diff(self.tileID) > 0):
raise RuntimeError('Tile IDs are not increasing.')
# Build program <-> pass mappings. The programs present must be a subset
# of those defined in our config. Pass numbers are arbitrary integers
# and do not need to be consecutive or dense.
tile_programs = np.unique(tiles['PROGRAM'])
unknown = set(tile_programs) - set(valid_programs)
if unknown:
raise RuntimeError('Cannot schedule unknown program(s): {}.'.format(unknown))
# Build program -> [passes] maps. A program with no tiles will map to an empty array.
self.program_passes = {
p: np.unique(self.passnum[tiles['PROGRAM'] == p]) for p in tile_programs}
p: np.unique(self.passnum[tiles['PROGRAM'] == p]) for p in self.PROGRAMS}
# Build pass -> program maps.
self.pass_program = {}
for p in tile_programs:
for p in self.PROGRAMS:
self.pass_program.update({passnum: p for passnum in self.program_passes[p]})
# Save tile programs in canonical order.
self.programs = [p for p in valid_programs if p in tile_programs]
# Build a dictionary for mapping from program name to a small index.
self.program_index = {pname: pidx for pidx, pname in enumerate(self.programs)}
# Build tile masks for each program.
# Build tile masks for each program. A program will no tiles with have an empty mask.
self.program_mask = {}
for p in self.programs:
for p in self.PROGRAMS:
mask = np.zeros(self.ntiles, bool)
for pnum in self.program_passes[p]:
mask |= (self.passnum == pnum)
Expand Down Expand Up @@ -136,7 +140,6 @@ def get_tiles(tiles_file=None, use_cache=True, write_cache=True):

log = desiutil.log.get_logger()
config = desisurvey.config.Configuration()
valid_programs = list(config.programs.keys)
tiles_file = tiles_file or config.tiles_file()

if use_cache and tiles_file in _cached_tiles:
Expand All @@ -145,7 +148,7 @@ def get_tiles(tiles_file=None, use_cache=True, write_cache=True):
else:
tiles = Tiles(tiles_file)
log.info('Initialized tiles from "{}".'.format(tiles_file))
for pname in tiles.programs:
for pname in Tiles.PROGRAMS:
pinfo = []
for passnum in tiles.program_passes[pname]:
pinfo.append('{}({})'.format(passnum, tiles.pass_ntiles[passnum]))
Expand Down

0 comments on commit 09e8619

Please sign in to comment.