diff --git a/SAS/TMSS/backend/services/scheduling/lib/constraints.py b/SAS/TMSS/backend/services/scheduling/lib/constraints.py index 20d40cdc84ec806ca2b23206aee2b1ebe4e28ed4..91d4bca30a96d47e7250c3d5fe8d1c6ef9cadcef 100644 --- a/SAS/TMSS/backend/services/scheduling/lib/constraints.py +++ b/SAS/TMSS/backend/services/scheduling/lib/constraints.py @@ -1023,25 +1023,38 @@ def get_earliest_possible_start_time_for_sky_min_elevation(scheduling_unit: mode def get_earliest_possible_start_time_for_sky_transit_offset(scheduling_unit: models.SchedulingUnitBlueprint, lower_bound: datetime, upper_bound: datetime=None, gridder: Gridder=None) -> datetime: # compute the transit time, and thus the optimal_start_time and earliest_possible_start_time - if gridder is None: - gridder = Gridder() + gridded_lower_bound = gridder.grid_time(lower_bound) possible_start_time = gridded_lower_bound - result = evaluate_sky_transit_constraint(scheduling_unit, possible_start_time, gridder=gridder) - logger.debug('get_earliest_possible_start_time_for_sky_transit_offset %s', result) - - if not result.has_constraint: - return None + if upper_bound is None: + upper_bound = lower_bound + timedelta(hours=24) + upper_bound = max(lower_bound, upper_bound) + while possible_start_time < upper_bound: + result = evaluate_sky_transit_constraint(scheduling_unit, possible_start_time, gridder=gridder) + logger.debug('get_earliest_possible_start_time_for_sky_transit_offset %s', result) - if result.is_constraint_met: - if result.earliest_possible_start_time is not None and result.earliest_possible_start_time < lower_bound: - return lower_bound + if not result.has_constraint: + return None - return result.earliest_possible_start_time + if result.is_constraint_met: + return result.earliest_possible_start_time - return None + # constraint is not met, advance possible_start_time and evaluate again + if result.earliest_possible_start_time is None or result.earliest_possible_start_time < lower_bound: + # advance with a grid step, and evaluate again + possible_start_time += gridder.as_timedelta() + continue + if result.earliest_possible_start_time is not None: + # advance straight to earliest_possible_start_time, and evaluate again to ensure the constraint is met + next_possible_start_time = gridder.grid_time(result.earliest_possible_start_time) + if next_possible_start_time > possible_start_time: + possible_start_time = next_possible_start_time + else: + possible_start_time += gridder.as_timedelta() + continue + return None @lru_cache(maxsize=10000) def get_earliest_possible_start_time_for_sky_min_distance(scheduling_unit: models.SchedulingUnitBlueprint, lower_bound: datetime, upper_bound: datetime=None, gridder: Gridder=None) -> datetime: diff --git a/SAS/TMSS/backend/services/scheduling/lib/dynamic_scheduling.py b/SAS/TMSS/backend/services/scheduling/lib/dynamic_scheduling.py index a13f9b5d5e364de333846d6580673e8ecd2aaa49..7ecf79bd838f8b97cf4c8c28b31c116b339e663e 100644 --- a/SAS/TMSS/backend/services/scheduling/lib/dynamic_scheduling.py +++ b/SAS/TMSS/backend/services/scheduling/lib/dynamic_scheduling.py @@ -213,7 +213,7 @@ class Scheduler: logger.info("Scheduler skipping update of dynamic schedule because it is not enabled in the settings") logger.info("Scheduler full schedule computation finished.") - self.log_schedule() + self.log_schedule(log_level=logging.INFO) def schedule_fixed_time_scheduling_units(self): ''' Schedule all schedulable fixed_time scheduling units.''' @@ -259,6 +259,8 @@ class Scheduler: msg = "fixed_time-scheduled scheduling unit id=%d cannot be scheduled at '%s'" % (schedulable_unit.id, start_time) logger.warning(msg) mark_independent_subtasks_in_scheduling_unit_blueprint_as_unschedulable(schedulable_unit, reason=msg) + + self.log_schedule(log_level=logging.DEBUG) except Exception as e: logger.exception("Could not schedule fixed_time-scheduled scheduling unit id=%d: %s", schedulable_unit.id, e) else: @@ -450,6 +452,8 @@ class Scheduler: for scheduled_scheduling_unit in get_scheduled_scheduling_units().filter(scheduling_constraints_doc__scheduler='dynamic').exclude(id=scheduled_scheduling_unit.id).all(): unschedule_subtasks_in_scheduling_unit_blueprint(scheduled_scheduling_unit) + self.log_schedule(log_level=logging.DEBUG) + # return the scheduled scheduling_unit, early exit out of looping over priority queues. return scheduled_scheduling_unit @@ -524,6 +528,8 @@ class Scheduler: logger.info("mid-term schedule: next scheduling unit id=%s '%s' start_time=%s", scheduling_unit.id, scheduling_unit.name, start_time) update_subtasks_start_times_for_scheduling_unit(scheduling_unit, start_time) + self.log_schedule(log_level=logging.DEBUG) + # keep track of the lower_bound_start_time based on last sub.on_sky_stop_time and gap lower_bound_start_time = scheduling_unit.on_sky_stop_time + DEFAULT_INTER_OBSERVATION_GAP @@ -546,21 +552,24 @@ class Scheduler: logger.info("Estimating mid-term schedule... finished") - def log_schedule(self): + def log_schedule(self, log_level: int=logging.INFO): '''Log the upcoming schedule in a table like format''' try: + if not logger.isEnabledFor(log_level): + return + units_in_schedule = models.SchedulingUnitBlueprint.objects.filter( status__value__in=models.SchedulingUnitStatus.SCHEDULABLE_ACTIVE_OR_FINISHED_STATUS_VALUES).filter( scheduled_start_time__isnull=False).filter( scheduled_start_time__gte=datetime.utcnow()).order_by('scheduled_start_time').all() if units_in_schedule: - logger.info("-----------------------------------------------------------------") - logger.info("Schedule:") + logger.log(log_level, "-----------------------------------------------------------------") + logger.log(log_level, "Schedule:") for unit in units_in_schedule: try: transit_time, transit_offset, elevation = get_transit_timestamp_offset_and_elevation(unit, unit.scheduled_start_time) - logger.info( + logger.log(log_level, " id=% 3d name=%s start_time='%s'[UTC] status=%s transit_offset=% 5d[min] elevation=% 3.1f[deg]", unit.id, ("'%s'" % (unit.name[:32],)).ljust(34), @@ -570,7 +579,7 @@ class Scheduler: Angle(elevation, astropy.units.rad).degree) except Exception as e: logger.warning(e) - logger.info("-----------------------------------------------------------------") + logger.log(log_level, "-----------------------------------------------------------------") # TODO: report on schedule density except Exception as e: logger.warning(e) diff --git a/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/_stations.scss b/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/_stations.scss index 9b56d4eb1373401e97aecc046dfe58fd335e86e2..ee576fe99af5a15878246be37e70ccdbf86ef0e2 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/_stations.scss +++ b/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/_stations.scss @@ -104,9 +104,6 @@ // .icon-left{ // margin-left: 20% // } -.p-multiselect-items-wrapper { - height: 150px; -} .stations-dialog .p-overlaypanel { margin-left: -250px; @@ -119,4 +116,4 @@ background-color: #007ad9 !important; color: white !important; margin-right: 7px; -} \ No newline at end of file +} diff --git a/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/_timeline.scss b/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/_timeline.scss index 77a083fac789c73bd6e450b6b916f9dec45d20d6..74fb81eb3404d0205df2f84a77ffcf73f5ac9a71 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/_timeline.scss +++ b/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/_timeline.scss @@ -445,10 +445,6 @@ display: none !important; } -.p-multiselect-items-wrapper { - height: 120px !important; -} - .p-multiselect-header .p-multiselect-close { position: absolute; margin-left: -45px; @@ -598,4 +594,4 @@ body .p-multiselect-panel .p-multiselect-header .p-multiselect-filter-container z-index: 999; opacity: 1; background-color: white !important; -} \ No newline at end of file +}