Skip to content
Snippets Groups Projects
Commit fc2754e9 authored by Jörn Künsemöller's avatar Jörn Künsemöller
Browse files

TMSS-259: Add tests for min_distance constraint

parent 16a8caf4
No related branches found
No related tags found
1 merge request!284Resolve TMSS-259
...@@ -138,15 +138,14 @@ def can_run_within_timewindow_with_sky_constraints(scheduling_unit: models.Sched ...@@ -138,15 +138,14 @@ def can_run_within_timewindow_with_sky_constraints(scheduling_unit: models.Sched
angle1 = beam['angle1'] angle1 = beam['angle1']
angle2 = beam['angle2'] angle2 = beam['angle2']
direction_type = beam['direction_type'] direction_type = beam['direction_type']
if "sky" in constraints and 'min_distance' in constraints['sky']: 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())) 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 body, timestamps in distances.items():
for timestamp, angle in timestamps.items(): for timestamp, angle in timestamps.items():
min_distance = constraints['sky']['min_distance'][body] min_distance = constraints['sky']['min_distance'][body]
if angle.rad < min_distance: 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)) logger.info('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 False
return True return True
......
...@@ -19,6 +19,9 @@ ...@@ -19,6 +19,9 @@
import unittest import unittest
import uuid import uuid
from unittest import mock
from astropy.coordinates import Angle
import logging import logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
...@@ -61,7 +64,7 @@ from lofar.common.postgres import PostgresDatabaseConnection ...@@ -61,7 +64,7 @@ from lofar.common.postgres import PostgresDatabaseConnection
# the module under test # the module under test
from lofar.sas.tmss.services.scheduling.dynamic_scheduling import * from lofar.sas.tmss.services.scheduling.dynamic_scheduling import *
@unittest.skip('Disabled until scheduler can deal with failing constraints. (Currently causes infinite loop.)')
class TestDynamicScheduling(unittest.TestCase): class TestDynamicScheduling(unittest.TestCase):
''' '''
Tests for the Dynamic Scheduling Tests for the Dynamic Scheduling
...@@ -267,6 +270,77 @@ class TestDynamicScheduling(unittest.TestCase): ...@@ -267,6 +270,77 @@ class TestDynamicScheduling(unittest.TestCase):
# ensure DEFAULT_INTER_OBSERVATION_GAP between them # ensure DEFAULT_INTER_OBSERVATION_GAP between them
self.assertGreaterEqual(scheduling_unit_blueprint_high.start_time - scheduling_unit_blueprint_manual.stop_time, DEFAULT_INTER_OBSERVATION_GAP) self.assertGreaterEqual(scheduling_unit_blueprint_high.start_time - scheduling_unit_blueprint_manual.stop_time, DEFAULT_INTER_OBSERVATION_GAP)
class TestSchedulingConstraints(unittest.TestCase):
'''
Tests for the constraint checkers used in dynamic scheduling
'''
@classmethod
def setUpClass(cls) -> None:
cls.obs_duration = 120 * 60
scheduling_set = models.SchedulingSet.objects.create(**SchedulingSet_test_data())
scheduling_unit_draft = TestDynamicScheduling.create_simple_observation_scheduling_unit("scheduling unit for contraints tests",
scheduling_set=scheduling_set,
obs_duration=cls.obs_duration)
cls.scheduling_unit_blueprint = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft)
def setUp(self) -> None:
self.sunrise_data = {
'CS002': {"sunrise": [{"start": datetime(2020, 1, 1, 7, 30, 0), "end": datetime(2020, 1, 1, 9, 30, 0)},{"start": datetime(2020, 1, 2, 7, 30, 0), "end": datetime(2020, 1, 2, 9, 30, 0)}],
"day": [{"start": datetime(2020, 1, 1, 9, 30, 0), "end": datetime(2020, 1, 1, 15, 30, 0)}, {"start": datetime(2020, 1, 2, 9, 30, 0), "end": datetime(2020, 1, 2, 15, 30, 0)}],
"sunset": [{"start": datetime(2020, 1, 1, 15, 30, 0), "end": datetime(2020, 1, 1, 17, 30, 0)},{"start": datetime(2020, 1, 2, 15, 30, 0), "end": datetime(2020, 1, 2, 17, 30, 0)}],
"night": [{"start": datetime(2020, 1, 1, 17, 30, 0), "end": datetime(2020, 1, 2, 7, 30, 0)}, {"start": datetime(2020, 1, 2, 17, 30, 0), "end": datetime(2020, 1, 3, 7, 30, 0)}]}}
self.sunrise_patcher = mock.patch('lofar.sas.tmss.services.scheduling.constraints.template_constraints_v1.timestamps_and_stations_to_sun_rise_and_set')
self.sunrise_mock = self.sunrise_patcher.start()
self.sunrise_mock.return_value = self.sunrise_data
self.addCleanup(self.sunrise_patcher.stop)
self.distance_data = {
"sun": {datetime(2020, 1, 1, 10, 0, 0): Angle("0.3rad"), datetime(2020, 1, 1, 12, 0, 0): Angle("0.35rad")},
"moon": {datetime(2020, 1, 1, 10, 0, 0): Angle("0.2rad"), datetime(2020, 1, 1, 12, 0, 0): Angle("0.25rad")},
"jupiter": {datetime(2020, 1, 1, 10, 0, 0): Angle("0.1rad"), datetime(2020, 1, 1, 12, 0, 0): Angle("0.15rad")}
}
self.distance_patcher = mock.patch('lofar.sas.tmss.services.scheduling.constraints.template_constraints_v1.coordinates_and_timestamps_to_separation_from_bodies')
self.distance_mock = self.distance_patcher.start()
self.distance_mock.return_value = self.distance_data
self.addCleanup(self.distance_patcher.stop)
def test_get_earliest_possible_start_time_with_daytime_constraint_timestamp_returns_day_start(self):
self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_day'] = True
self.scheduling_unit_blueprint.save()
timestamp = datetime(2020, 1, 1, 4, 0, 0)
returned_time = get_earliest_possible_start_time(self.scheduling_unit_blueprint, timestamp)
self.assertEqual(returned_time, self.sunrise_data['CS002']['day'][0]['start'])
def test_get_earliest_possible_start_time_with_daytime_constraint_timestamp_returns_timestamp(self):
self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_day'] = True
self.scheduling_unit_blueprint.save()
timestamp = datetime(2020, 1, 1, 10, 0, 0)
returned_time = get_earliest_possible_start_time(self.scheduling_unit_blueprint, timestamp)
self.assertEqual(returned_time, timestamp)
# todo: add more daytime checks with 255
# todo: add nighttime checks with 254
# todo: add twilight checks with 256
def test_can_run_within_timewindow_with_min_distance_constraint_returns_true_when_met(self):
self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky']['min_distance'] = {'sun': 0.1, 'moon': 0.1, 'jupiter': 0.1}
self.scheduling_unit_blueprint.save()
timestamp = datetime(2020, 1, 1, 10, 0, 0)
returned_value = can_run_within_timewindow(self.scheduling_unit_blueprint, timestamp, timestamp + timedelta(seconds=self.obs_duration))
self.assertTrue(returned_value)
def test_can_run_within_timewindow_with_min_distance_constraint_returns_false_when_not_met(self):
self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky']['min_distance'] = {'sun': 0.2, 'moon': 0.2, 'jupiter': 0.2}
self.scheduling_unit_blueprint.save()
timestamp = datetime(2020, 1, 1, 10, 0, 0)
returned_value = can_run_within_timewindow(self.scheduling_unit_blueprint, timestamp, timestamp + timedelta(seconds=self.obs_duration))
self.assertFalse(returned_value)
logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', level=logging.INFO) logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', level=logging.INFO)
if __name__ == '__main__': if __name__ == '__main__':
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment