diff --git a/SAS/TMSS/backend/services/scheduling/lib/dynamic_scheduling.py b/SAS/TMSS/backend/services/scheduling/lib/dynamic_scheduling.py index ab8767a225fc5fcc1f66aff0c4956a274529992f..da5ddb2df3d93121557f8d2b816d77ff1f0559f1 100644 --- a/SAS/TMSS/backend/services/scheduling/lib/dynamic_scheduling.py +++ b/SAS/TMSS/backend/services/scheduling/lib/dynamic_scheduling.py @@ -346,7 +346,7 @@ class Scheduler: scheduled_units.extend(self.try_schedule_relational_units(scheduled_unit)) # see if we can fit any B-prio units in the new gap(s) in the schedule? - scheduled_B_units = self.schedule_B_priority_units_in_gaps_around_scheduling_unit(scheduled_unit, exclude_units=to_be_excluded_units) + scheduled_B_units = self.schedule_B_priority_units_in_gaps_around_scheduling_unit(scheduled_unit, exclude_units=to_be_excluded_units, lower_bound=lower_bound, upper_bound=upper_bound) scheduled_units.extend(scheduled_B_units) else: # advance window and search again @@ -802,7 +802,7 @@ class Scheduler: mark_subtasks_in_scheduling_unit_blueprint_as_schedulable(related_unit) - def schedule_B_priority_units_in_gaps_around_scheduling_unit(self, scheduling_unit: models.SchedulingUnitBlueprint, exclude_units: []=None) -> [models.SchedulingUnitBlueprint]: + def schedule_B_priority_units_in_gaps_around_scheduling_unit(self, scheduling_unit: models.SchedulingUnitBlueprint, exclude_units: []=None, lower_bound: datetime=None, upper_bound: datetime=None) -> [models.SchedulingUnitBlueprint]: '''try to schedule one or more scheduling units from queue B in the gap between the given scheduled_unit and its previous observed+ unit''' scheduled_units = [] @@ -823,7 +823,12 @@ class Scheduler: gaps = get_gaps_to_previous_and_next_observations_in_scheduling_unit(scheduling_unit, include_schedulable_unschedulable=False) gaps = [gap for gap in gaps if gap[1] != datetime.max] # skip open-ended future gaps - gaps = [gap for gap in gaps if gap[0] >= scheduling_unit.scheduled_observation_stop_time] # skip future gaps, will be treated in a later iteration as 'past' gap. + if lower_bound: + gaps = [gap for gap in gaps if gap[1] >= lower_bound] + gaps = [(max(lower_bound, gap[0]), gap[1]) for gap in gaps] + if upper_bound: + gaps = [gap for gap in gaps if gap[0] <= upper_bound] + gaps = [(gap[0], min(upper_bound, gap[1])) for gap in gaps] gaps = sorted(gaps, key=lambda gap: gap[0]) # sorted ascending in time for gap in gaps: @@ -867,7 +872,7 @@ class Scheduler: # Recurse. There may be a new gap, so let's try to squeeze in more. best_B_candidate_for_gap.scheduling_unit.refresh_from_db() logger.debug("schedule_B_priority_units_in_gaps: recursing to schedule more B-queue units next to just scheduled unit id=%s", best_B_candidate_for_gap.scheduling_unit.id) - scheduled_units.extend(self.schedule_B_priority_units_in_gaps_around_scheduling_unit(best_B_candidate_for_gap.scheduling_unit, exclude_units=scheduled_units)) + scheduled_units.extend(self.schedule_B_priority_units_in_gaps_around_scheduling_unit(best_B_candidate_for_gap.scheduling_unit, exclude_units=scheduled_units, lower_bound=lower_bound, upper_bound=upper_bound)) except RecursionError as e: logger.error("Max recursion depth reached. Skipping further scheduling of B-queue units in %d[min]-wide gap( ['%s', '%s')", (upper_bound_stop_time-lower_bound_start_time).total_seconds()/60, lower_bound_start_time, upper_bound_stop_time) else: diff --git a/SAS/TMSS/backend/services/scheduling/test/t_dynamic_scheduling.py b/SAS/TMSS/backend/services/scheduling/test/t_dynamic_scheduling.py index 7d50dd595633b33b43ebc6f33ed61d6de9257714..e6828d2182c687ecbe77f1b35cfd4cfc9fef2440 100755 --- a/SAS/TMSS/backend/services/scheduling/test/t_dynamic_scheduling.py +++ b/SAS/TMSS/backend/services/scheduling/test/t_dynamic_scheduling.py @@ -642,7 +642,7 @@ class TestFixedTimeScheduling(BaseDynamicSchedulingTestCase): # the bug used to yield a generic reason: constraint time.at='2023-03-30 18:40:00' falls outside of window ['2023-03-30 18:40:00', '2023-03-30 22:40:00'] self.assertNotIn('falls outside of window', scheduling_unit_blueprint.unschedulable_reason) # assert that the bug is fixed and yields a specific unschedulable_reason - self.assertIn('sky min_elevation constraint is not met', scheduling_unit_blueprint.unschedulable_reason) + self.assertIn('sky min_elevation, sky transit_offset constraints are not met', scheduling_unit_blueprint.unschedulable_reason) def test_bug_fix_TMSS_2496_reserved_stations_are_not_used_for_constraints(self):