Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new features for extension, allowing one program to depend on another #160

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions py/desisurvey/ephem.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,10 @@
import desisurvey.tiles


# Date range 2019-2025 for tabulated ephemerides.
# This range is chosen large enough to cover commissioning,
# survey validation and the 5-year main survey, so should
# not normally need to be changed, except for testing.
# Date range 2019-2029 for tabulated ephemerides.
# This range is intended to cover out through the DESI extension.
START_DATE = datetime.date(2019, 1, 1)
STOP_DATE = datetime.date(2027, 12, 31)
STOP_DATE = datetime.date(2029, 12, 31)

_ephem = None

Expand Down
24 changes: 24 additions & 0 deletions py/desisurvey/plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

import astropy.table
import astropy.io.fits
from astropy.coordinates import SkyCoord
from astropy import units as u

import desiutil.log

Expand Down Expand Up @@ -512,6 +514,7 @@ def afternoon_plan(self, night):
self.add_pending_tile(tileid)
if self.tiles_lowpass:
self.prefer_low_passnum()
self.require_program_dependencies()
zeropriority = ((self.tile_status != 'unobs') &
(self.tile_available == 0))
self.tile_priority[zeropriority] = 0
Expand Down Expand Up @@ -559,3 +562,24 @@ def prefer_low_passnum(self):
# unobserved, overlapping tiles with lower pass numbers.
mfree[idx] = 0
self.tile_available[~mfree] = 0

def require_program_dependencies(self):
depends_on = self.tiles.program_dependencies()
config = desisurvey.config.Configuration()
tile_diameter = 2 * config.tile_radius()

for program in depends_on:
mprog = self.tiles.program_mask[program]
mtodo = ((self.tile_status != 'done') &
(self.tiles.in_desi != 0))
otherprog = depends_on[program]
# tiles we still intend to do in the underlying program
motherprog = self.tiles.program_mask[otherprog] & mtodo
cprog = SkyCoord(self.tiles.tileRA[mprog]*u.deg,
self.tiles.tileDEC[mprog]*u.deg)
cotherprog = SkyCoord(self.tiles.tileRA[motherprog]*u.deg,
self.tiles.tileDEC[motherprog]*u.deg)
idxo, idxp, _, _ = cprog.search_around_sky(cotherprog, tile_diameter)
mblocked = np.zeros(len(mprog), dtype='bool')
mblocked[np.flatnonzero(mprog)[idxp]] = True
self.tile_available[mblocked] = 0
3 changes: 2 additions & 1 deletion py/desisurvey/plots.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@

# Color associated with each program in the functions below.
program_color = {'DARK': 'black', 'GRAY': 'gray', 'BRIGHT': 'orange',
'BACKUP': 'green'}
'BACKUP': 'green', 'DARK1B': 'purple',
'BRIGHT1B': 'red'}


def plot_sky_passes(ra, dec, passnum, z, clip_lo=None, clip_hi=None,
Expand Down
11 changes: 7 additions & 4 deletions py/desisurvey/scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,10 +213,10 @@ def conditions_to_program(self, seeing, transparency, skylevel,
return 'BRIGHT'
return 'BACKUP'

def select_program(self, mjd_now, ETC, verbose=False,
def current_conditions(self, mjd_now, ETC, verbose=False,
seeing=None, transparency=None, skylevel=None,
airmass=None, speed=None):
"""Select program to observe now.
"""Return current conditions, based on ephemerides or speed.
"""
if mjd_now < self.night_changes[0]:
if verbose:
Expand Down Expand Up @@ -248,7 +248,9 @@ def select_program(self, mjd_now, ETC, verbose=False,
else:
mjd_program_end = self.night_changes[-1]
return program, mjd_program_end

# select program based on ephemerides, not conditions.
# we have not actually used this in DESI.
idx = 0
while ((idx + 1 < len(self.night_changes)) and
(mjd_now >= self.night_changes[idx + 1])):
Expand Down Expand Up @@ -348,14 +350,15 @@ def next_tile(self, mjd_now, ETC, seeing, transp, skylevel, HA_sigma=15.,
self.tile_sel = np.ones(self.tiles.ntiles, dtype=bool)
if program is None:
# Which program are we in?
program, mjd_program_end = self.select_program(
conditions, mjd_program_end = self.current_conditions(
mjd_now, ETC, verbose=verbose, seeing=seeing,
skylevel=skylevel, transparency=transp, speed=speed)
self.tile_sel &= self.tiles.allowed_in_conditions(program)
self.tile_sel &= self.tiles.allowed_in_conditions(conditions)
if verbose:
self.log.info(
'Selecting a tile observable in {} conditions.'.format(
program))
program = conditions
else:
self.tile_sel &= self.tiles.program_mask[program]
mjd_program_end = self.night_changes[-1] # end of night?
Expand Down
8 changes: 7 additions & 1 deletion py/desisurvey/scripts/surveyinit.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ def parse(options=None):
parser.add_argument(
'--start', default=None, type=str,
help='Use this start date instead of config.')
parser.add_argument(
'--stop', default=None, type=str,
help='Use this stop date instead of config.')

if options is None:
args = parser.parse_args()
Expand Down Expand Up @@ -163,7 +166,10 @@ def calculate_initial_plan(args):
start = config.first_day()
else:
start = desisurvey.utils.get_date(args.start)
stop = config.last_day()
if args.stop is None:
stop = config.last_day()
else:
stop = desisurvey.utils.get_date(args.stop)
assert start >= first and stop <= last
hdr['START'] = start.isoformat()
hdr['STOP'] = stop.isoformat()
Expand Down
13 changes: 7 additions & 6 deletions py/desisurvey/scripts/surveymovie.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ def __init__(self, exposures_path, start, stop, label, show_scores):
self.tileid = self.tiles.tileID
self.prognames = [p for p in self.tiles.programs]
# if DARK and BRIGHT are names, put them first
for pname in ['BRIGHT', 'DARK']:
for pname in ['BRIGHT1B', 'DARK1B', 'BRIGHT', 'DARK']:
if pname in self.prognames:
self.prognames.remove(pname)
self.prognames = [pname] + self.prognames
Expand Down Expand Up @@ -200,7 +200,7 @@ def init_figure(self, nightly, width=1920, height=1080, dpi=32):
self.figure = plt.figure(
frameon=False,figsize=(width / self.dpi, height / self.dpi),
dpi=self.dpi)
grid = matplotlib.gridspec.GridSpec(2, 2)
grid = matplotlib.gridspec.GridSpec(3, 2)
grid.update(left=0, right=1, bottom=0, top=0.97, hspace=0, wspace=0)
axes = []
self.labels = []
Expand All @@ -222,15 +222,15 @@ def init_figure(self, nightly, width=1920, height=1080, dpi=32):
self.nowcolor = np.array([0., 0.7, 0., 1.])
pcolors = desisurvey.plots.program_color
progidx = 0
for row in range(2):
for row in range(3):
for col in range(2):
# Create the axes for this program.
ax = plt.subplot(grid[row, col], facecolor=bgcolor)
ax.set_xticks([])
ax.set_yticks([])
axes.append(ax)
# Bottom-right corner is reserved for integrated progress plots.
if row == 1 and col == 1:
if row == 2 and col == 1:
ax.set_xlim(0, self.survey_weeks)
ax.set_ylim(0, 1)
ax.plot([0, self.survey_weeks], [0., 1.], 'w-')
Expand All @@ -249,7 +249,7 @@ def init_figure(self, nightly, width=1920, height=1080, dpi=32):
# e.g., for no-gray mode, where we have only two programs.
continue
ax.set_xlim(-55, 293)
ax.set_ylim(-20, 77)
ax.set_ylim(-30, 77)
# Draw label for this plot.
pname = self.prognames[progidx]
pc = pcolors[pname]
Expand Down Expand Up @@ -553,7 +553,8 @@ def update(iframe):
animation = matplotlib.animation.FuncAnimation(
animator.figure, update, init_func=init, blit=True, frames=nframes)
writer = matplotlib.animation.writers['ffmpeg'](
bitrate=2400, fps=args.fps, metadata=dict(artist='surveymovie'))
bitrate=2400, fps=args.fps, codec='vp9',
metadata=dict(artist='surveymovie'))
save_name = args.save + '.mp4'
animation.save(save_name, writer=writer, dpi=animator.dpi)
log.info('Saved {0}.'.format(save_name))
16 changes: 11 additions & 5 deletions py/desisurvey/tiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,17 @@ def allowed_in_conditions(self, cond):
res = res | (self.tileobsconditions == 'BRIGHT')
return res

def program_dependencies(self):
depends_on = dict()
config = desisurvey.config.Configuration()
for program in config.programs.keys:
prognode = getattr(config.programs, program)
dependencies = getattr(prognode, 'depends_on', None)
if dependencies is not None:
depends_on[program] = dependencies()
return depends_on


@property
def overlapping(self):
"""Dictionary of tile overlap matrices.
Expand Down Expand Up @@ -350,11 +361,6 @@ def _calculate_neighbors(self):
# ignore self matches
continue
self._neighbors[rownum[ind1]].append(rownum[ind2])

for passnum in np.unique(self.tilepass[mprogram]):
m = (mprogram & (self.tilepass == passnum) &
(self.in_desi != 0))
rownum = np.flatnonzero(m)
# self._neighbors: list of lists, giving tiles neighboring each
# tile

Expand Down
Loading