diff --git a/SAS/TMSS/services/scheduling/lib/constraints/template_constraints_v1.py b/SAS/TMSS/services/scheduling/lib/constraints/template_constraints_v1.py index 247f89851ccdda58cdb07b98639c1349c45825fc..ab035589e8080c8c68fe11b6a24421c8e7af2b47 100644 --- a/SAS/TMSS/services/scheduling/lib/constraints/template_constraints_v1.py +++ b/SAS/TMSS/services/scheduling/lib/constraints/template_constraints_v1.py @@ -31,7 +31,7 @@ from datetime import datetime, timedelta from dateutil import parser from lofar.sas.tmss.tmss.tmssapp import models -from lofar.sas.tmss.tmss.tmssapp.conversions import create_astroplan_observer_for_station, Time, timestamps_and_stations_to_sun_rise_and_set +from lofar.sas.tmss.tmss.tmssapp.conversions import create_astroplan_observer_for_station, Time, timestamps_and_stations_to_sun_rise_and_set, coordinates_and_timestamps_to_separation_from_bodies from . import ScoredSchedulingUnit @@ -133,7 +133,22 @@ def can_run_within_timewindow_with_sky_constraints(scheduling_unit: models.Sched constraints = scheduling_unit.draft.scheduling_constraints_doc # TODO: TMSS-245 TMSS-250 (and more?), evaluate the constraints in constraints['sky'] # maybe even split this method into sub methods for the very distinct sky constraints: min_calibrator_elevation, min_target_elevation, transit_offset & min_distance - return True # for now, ignore sky contraints. + + beam = scheduling_unit.requirements_doc['tasks']['Observation']['specifications_doc']['tile_beam'] + angle1 = beam['angle1'] + angle2 = beam['angle2'] + direction_type = beam['direction_type'] + + if "sky" in constraints and 'min_distance' in constraints['sky']: + distances = coordinates_and_timestamps_to_separation_from_bodies(angle1=angle1, angle2=angle2, direction_type=direction_type, timestamps=(lower_bound, upper_bound), bodies=tuple(constraints['sky']['min_distance'].keys())) + for body, timestamps in distances.items(): + for timestamp, angle in timestamps.items(): + min_distance = constraints['sky']['min_distance'][body] + if angle.rad < min_distance: + logger.warning('Distance=%s from body=%s does not meet min_distance=%s constraint at timestamp=%s' % (angle.rad, body, min_distance, timestamp)) + return True # TODO: This should return False, but that currently leads to an infinite loop since this function seems to get called repeatedly with same lower_bound + + return True def get_earliest_possible_start_time(scheduling_unit: models.SchedulingUnitBlueprint, lower_bound: datetime) -> datetime: @@ -147,29 +162,41 @@ def get_earliest_possible_start_time(scheduling_unit: models.SchedulingUnitBluep if 'after' in constraints['time']: return parser.parse(constraints['time']['after'], ignoretz=True) - if constraints['daily']['require_day'] or constraints['daily']['require_night']: + if constraints['daily']['require_day'] or constraints['daily']['require_night'] or constraints['daily']['avoid_twilight']: # TODO: TMSS-254 and TMSS-255 - # TODO: take avoid_twilight into account - # for now, use the incorrect proof of concept which works for the demo - # but... this should be rewritten completely using Joerns new sun_events - LOFAR_CENTER_OBSERVER = create_astroplan_observer_for_station('CS002') - sun_events = timestamps_and_stations_to_sun_rise_and_set(timestamps=[lower_bound], stations=['CS002'])['CS002'] - sun_set = sun_events['sunset'][0]['start'] - sun_rise = sun_events['sunrise'][0]['end'] + # TODO: make sure contraints are met by all stations of this observation, not just CS002. + sun_events = timestamps_and_stations_to_sun_rise_and_set(timestamps=(lower_bound,lower_bound+timedelta(days=1)), stations=('CS002',))['CS002'] + day = sun_events['day'][0] + night = sun_events['night'][0] + next_day = sun_events['day'][1] + next_night = sun_events['night'][1] if constraints['daily']['require_day']: - if lower_bound+scheduling_unit.duration > sun_set: - return LOFAR_CENTER_OBSERVER.sun_rise_time(time=Time(sun_set), which='next').to_datetime() - if lower_bound >= sun_rise: + # TODO: Do we need to check for observations that are too long and can e.g. only be run in summer? + if lower_bound+scheduling_unit.duration > day['end']: + return next_day['start'] + if lower_bound >= day['start']: return lower_bound - return sun_rise + return day['start'] if constraints['daily']['require_night']: - if lower_bound+scheduling_unit.duration < sun_rise: - return lower_bound - if lower_bound >= sun_set: + if lower_bound + scheduling_unit.duration > night['end']: + return next_night['start'] + if lower_bound >= night['start']: return lower_bound - return sun_set + return night['start'] + + if constraints['daily']['avoid_twilight']: + if lower_bound + scheduling_unit.duration < day['end']: + if lower_bound >= day['start']: + return lower_bound + return day['start'] + if lower_bound + scheduling_unit.duration < night['end']: + if lower_bound >= night['start']: + return lower_bound + return night['start'] + return next_day['start'] + except Exception as e: logger.exception(str(e))