Skip to content

Commit

Permalink
Merge pull request #494 from gemini-hlsw/SCHED-692
Browse files Browse the repository at this point in the history
SCHED 692: Add night conditions
  • Loading branch information
stroncod committed Aug 19, 2024
2 parents f104d05 + 92020fd commit ee0aa89
Show file tree
Hide file tree
Showing 14 changed files with 776 additions and 15 deletions.
5 changes: 3 additions & 2 deletions scheduler/core/calculations/selection.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@

from dataclasses import dataclass
from datetime import timedelta
from typing import final, Callable, FrozenSet, Mapping, Optional
from typing import final, Callable, FrozenSet, Mapping, Optional, Dict

from lucupy.helpers import flatten
from lucupy.minimodel import Group, NightIndices, Program, ProgramID, Site, UniqueGroupID
from lucupy.minimodel import Group, NightIndices, Program, ProgramID, Site, UniqueGroupID, VariantSnapshot

from scheduler.core.components.ranker import Ranker
from scheduler.core.types import StartingTimeslots
Expand Down Expand Up @@ -35,6 +35,7 @@ class Selection:
schedulable_groups: Mapping[UniqueGroupID, GroupData]
night_events: Mapping[Site, NightEvents]
night_indices: NightIndices
night_conditions: Dict[Site, VariantSnapshot]
time_slot_length: timedelta
starting_time_slots: StartingTimeslots
ranker: Ranker
Expand Down
2 changes: 1 addition & 1 deletion scheduler/core/components/changemonitor/change_monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ def process_event(self,
# Regardless, we want to change the weather values for CC and IQ.
self.selector.update_site_variant(site, variant_change)

# If the site is blocked, we have no reason to recalculate a plan until all blocking evens
# If the site is blocked, we have no reason to recalculate a plan until all blocking events
# are unblocked.
if plans is None:
if self.is_site_blocked(site):
Expand Down
4 changes: 3 additions & 1 deletion scheduler/core/components/optimizer/optimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ def schedule(self, selection: Selection) -> List[Plans]:
self.night_events = selection.night_events

# Create set of plans for the amount of nights
nights = [Plans(self.night_events, night_idx) for night_idx in self.selection.night_indices]
nights = [Plans(self.night_events,
selection.night_conditions,
night_idx) for night_idx in self.selection.night_indices]
self.algorithm.schedule(nights)
return nights

Expand Down
1 change: 1 addition & 0 deletions scheduler/core/components/selector/selector.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ def select(self,
schedulable_groups=schedulable_groups_map,
night_events={site: self.collector.get_night_events(site) for site in sites},
night_indices=night_indices,
night_conditions=self._variant_snapshot_per_site,
starting_time_slots=starting_time_slots,
time_slot_length=self.collector.time_slot_length.to_datetime(),
ranker=ranker,
Expand Down
3 changes: 2 additions & 1 deletion scheduler/core/eventsqueue/nightchanges.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ def get_final_plan(self, night_idx: NightIndex, site: Site) -> Optional[Plan]:
end=relevant_entries[-1].plan_generated.end,
time_slot_length=relevant_entries[0].plan_generated.time_slot_length,
site=site,
_time_slots_left=relevant_entries[-1].plan_generated.time_left())
_time_slots_left=relevant_entries[-1].plan_generated.time_left(),
conditions=relevant_entries[-1].plan_generated.conditions)
p.visits = [v for v in reversed(all_generated)]
return p

Expand Down
6 changes: 4 additions & 2 deletions scheduler/core/plans/plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from typing import final, List, Optional, Tuple

from lucupy.observatory.abstract import ObservatoryProperties
from lucupy.minimodel import Observation, ObservationID, Site
from lucupy.minimodel import Observation, ObservationID, Site, VariantSnapshot
from lucupy.timeutils import time2slots

from .nightstats import NightStats
Expand All @@ -31,12 +31,14 @@ class Plan:
time_slot_length: timedelta
site: Site
_time_slots_left: int
conditions: VariantSnapshot

visits: List[Visit] = field(init=False, default_factory=list)
is_full: bool = field(init=False, default=False)
night_stats: Optional[NightStats] = field(init=False, default=None)
alt_degs: List[List[float]] = field(init=False, default_factory=list)


def nir_slots(self,
science_obs: List[Observation],
n_slots_filled: int,
Expand Down Expand Up @@ -115,7 +117,7 @@ def get_slice(self, start: Optional[int] = None, stop: Optional[int] = None) ->
else:
visits_by_timeslot = {v.start_time_slot: v for v in self.visits}
visits_timeslots = [v.start_time_slot for v in self.visits]
plan = Plan(self.start, self.end, self.time_slot_length, self.site, self._time_slots_left)
plan = Plan(self.start, self.end, self.time_slot_length, self.site, self._time_slots_left, self.conditions)

start = start or 0
stop = stop or visits_timeslots[-1]
Expand Down
6 changes: 4 additions & 2 deletions scheduler/core/plans/plans.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from dataclasses import dataclass, field, InitVar
from typing import final, Dict, Mapping

from lucupy.minimodel import NightIndex, Site
from lucupy.minimodel import NightIndex, Site, VariantSnapshot

from .plan import Plan
from scheduler.core.calculations.nightevents import NightEvents
Expand All @@ -21,6 +21,7 @@ class Plans:
A collection of Plan for all sites for a specific night.
"""
night_events: InitVar[Mapping[Site, NightEvents]]
night_conditions: Dict[Site, VariantSnapshot]
night_idx: NightIndex
plans: Dict[Site, Plan] = field(init=False, default_factory=dict)

Expand All @@ -32,7 +33,8 @@ def __post_init__(self, night_events: Mapping[Site, NightEvents]):
ne.local_times[self.night_idx][-1],
ne.time_slot_length.to_datetime(),
site,
len(ne.times[self.night_idx]))
len(ne.times[self.night_idx]),
self.night_conditions[site])

def __getitem__(self, site: Site) -> Plan:
return self.plans[site]
Expand Down
5 changes: 4 additions & 1 deletion scheduler/engine/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,10 @@ def setup(self, scp: SCP) -> Dict[Site, Dict[NightIndex, Optional[VariantSnapsho
# morn_twi_slot = time2slots(time_slot_length, morn_twi_time - eve_twi_time)
morn_twi_slot = night_events.num_timeslots_per_night[night_idx]

# Get initial conditions for the nights
initial_variants[site][night_idx] = scp.collector.sources.origin.env.get_initial_conditions(site,
night_date)

# Get the weather events for the site for the given night date.
# Get the VariantSnapshots for the times of the night where the variant changes.
variant_changes_dict = scp.collector.sources.origin.env.get_variant_changes_for_night(site, night_date)
Expand All @@ -296,7 +300,6 @@ def setup(self, scp: SCP) -> Dict[Site, Dict[NightIndex, Optional[VariantSnapsho
# The closer to the first time slot, the more accurate, and the ordering on them will overwrite
# the previous values.
if variant_timeslot <= 0:
initial_variants[site][night_idx] = variant_snapshot
continue

if variant_timeslot >= morn_twi_slot:
Expand Down
15 changes: 13 additions & 2 deletions scheduler/graphql_mid/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@ def from_computed_night_stats(ns: NightStats) -> 'SNightStats':
program_completion=pc)


@strawberry.type
class SConditions:
iq: str
cc: str

@staticmethod
def from_computed_conditions(variant: VariantSnapshot):
return SConditions(iq=variant.iq.name, cc=variant.cc.name)


@strawberry.type
class SVisit:
"""
Expand Down Expand Up @@ -85,6 +95,7 @@ class SPlan:
end_time: datetime
visits: List[SVisit]
night_stats: SNightStats
night_conditions: SConditions

@staticmethod
def from_computed_plan(plan: Plan) -> 'SPlan':
Expand All @@ -94,7 +105,8 @@ def from_computed_plan(plan: Plan) -> 'SPlan':
start_time=plan.start.astimezone(utc),
end_time=plan.end.astimezone(utc),
visits=[SVisit.from_computed_visit(visit, alt) for visit, alt in zip(plan.visits, plan.alt_degs)],
night_stats=SNightStats.from_computed_night_stats(plan.night_stats)
night_stats=SNightStats.from_computed_night_stats(plan.night_stats),
night_conditions=SConditions.from_computed_conditions(plan.conditions)
)


Expand Down Expand Up @@ -169,7 +181,6 @@ def from_computed_timelines(timeline: NightlyTimeline) -> 'SNightTimelines':
timelines.append(sn)
return SNightTimelines(night_timeline=timelines)


@strawberry.type
class NewNightPlans:
night_plans: SNightTimelines
Expand Down
Binary file modified scheduler/pickles/ocsenv.pickle
Binary file not shown.
7 changes: 5 additions & 2 deletions scheduler/scripts/run_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,9 @@ def main(*,
# morn_twi_slot = time2slots(time_slot_length, morn_twi_time - eve_twi_time)
morn_twi_slot = night_events.num_timeslots_per_night[night_idx]

# Get initial conditions for the nights
initial_variants[site][night_idx] = collector.sources.origin.env.get_initial_conditions(site, night_date)

# Get the weather events for the site for the given night date.
# Get the VariantSnapshots for the times of the night where the variant changes.
variant_changes_dict = collector.sources.origin.env.get_variant_changes_for_night(site, night_date)
Expand All @@ -151,7 +154,6 @@ def main(*,
# The closer to the first time slot, the more accurate, and the ordering on them will overwrite
# the previous values.
if variant_timeslot <= 0:
initial_variants[site][night_idx] = variant_snapshot
continue

if variant_timeslot >= morn_twi_slot:
Expand Down Expand Up @@ -384,7 +386,8 @@ def main(*,
# Piece together the plans for the night to get the overall plans.
# This is rather convoluted because of the confusing relationship between Plan, Plans, and NightlyTimeline.
night_events = {site: collector.get_night_events(site) for site in collector.sites}
final_plans = Plans(night_events, NightIndex(night_idx))
night_conditions = {site: initial_variants[site][night_idx] for site in collector.sites}
final_plans = Plans(night_events, night_conditions, NightIndex(night_idx))
for site in collector.sites:
calculated_plan = nightly_timeline.get_final_plan(NightIndex(night_idx), site)
if calculated_plan is not None:
Expand Down
Loading

0 comments on commit ee0aa89

Please sign in to comment.