From 79880cf4907e3c588e1655db97601d081df87084 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20K=C3=BCnsem=C3=B6ller?=
 <jkuensem@physik.uni-bielefeld.de>
Date: Tue, 27 Apr 2021 21:38:32 +0200
Subject: [PATCH] TMSS-697: use scheduling constraints on blueprint instead of
 draft

---
 .../scheduling/lib/constraints/__init__.py       | 12 ++++++------
 .../lib/constraints/template_constraints_v1.py   | 16 ++++++++--------
 .../scheduling/lib/dynamic_scheduling.py         |  3 +--
 3 files changed, 15 insertions(+), 16 deletions(-)

diff --git a/SAS/TMSS/backend/services/scheduling/lib/constraints/__init__.py b/SAS/TMSS/backend/services/scheduling/lib/constraints/__init__.py
index 85e452ae483..783dd86c11c 100644
--- a/SAS/TMSS/backend/services/scheduling/lib/constraints/__init__.py
+++ b/SAS/TMSS/backend/services/scheduling/lib/constraints/__init__.py
@@ -68,7 +68,7 @@ def filter_scheduling_units_using_constraints(scheduling_units: [models.Scheduli
 
     for scheduling_unit in scheduling_units:
         try:
-            if scheduling_unit.draft is None or scheduling_unit.draft.scheduling_constraints_template is None:
+            if scheduling_unit.draft is None or scheduling_unit.scheduling_constraints_template is None:
                 logger.warning("cannot dynamically schedule scheduling_unit id=%s name='%s' because it has not constraints template", scheduling_unit.id, scheduling_unit.name)
                 continue
 
@@ -168,7 +168,7 @@ def sort_scheduling_units_scored_by_constraints(scheduling_units: [models.Schedu
 
 def can_run_within_timewindow(scheduling_unit: models.SchedulingUnitBlueprint, lower_bound: datetime, upper_bound: datetime) -> bool:
     '''Check if the given scheduling_unit can run somewhere within the given time window depending on the sub's constrains-template/doc.'''
-    constraints_template = scheduling_unit.draft.scheduling_constraints_template
+    constraints_template = scheduling_unit.scheduling_constraints_template
 
     # choose appropriate method based on template (strategy pattern), or raise
     if constraints_template.name == 'constraints' and constraints_template.version == 1:
@@ -184,7 +184,7 @@ def can_run_within_timewindow(scheduling_unit: models.SchedulingUnitBlueprint, l
 
 def can_run_after(scheduling_unit: models.SchedulingUnitBlueprint, lower_bound: datetime) -> bool:
     '''Check if the given scheduling_unit can run somewhere after the given lowerbound timestamp depending on the sub's constrains-template/doc.'''
-    constraints_template = scheduling_unit.draft.scheduling_constraints_template
+    constraints_template = scheduling_unit.scheduling_constraints_template
 
     # choose appropriate method based on template (strategy pattern), or raise
     if constraints_template.name == 'constraints' and constraints_template.version == 1:
@@ -201,7 +201,7 @@ def can_run_after(scheduling_unit: models.SchedulingUnitBlueprint, lower_bound:
 
 def compute_scores(scheduling_unit: models.SchedulingUnitBlueprint, lower_bound:datetime, upper_bound:datetime) -> ScoredSchedulingUnit:
     '''Compute the "fitness" scores per constraint for the given scheduling_unit at the given starttime depending on the sub's constrains-template/doc.'''
-    constraints_template = scheduling_unit.draft.scheduling_constraints_template
+    constraints_template = scheduling_unit.scheduling_constraints_template
 
     # choose appropriate method based on template (strategy pattern), or raise
     if constraints_template.name == 'constraints' and constraints_template.version == 1:
@@ -217,7 +217,7 @@ def compute_scores(scheduling_unit: models.SchedulingUnitBlueprint, lower_bound:
 
 def get_earliest_possible_start_time(scheduling_unit: models.SchedulingUnitBlueprint, lower_bound: datetime) -> datetime:
     '''determine the earliest possible start_time for the given scheduling unit, taking into account all its constraints'''
-    constraints_template = scheduling_unit.draft.scheduling_constraints_template
+    constraints_template = scheduling_unit.scheduling_constraints_template
 
     # choose appropriate method based on template (strategy pattern), or raise
     if constraints_template.name == 'constraints' and constraints_template.version == 1:
@@ -234,7 +234,7 @@ def get_earliest_possible_start_time(scheduling_unit: models.SchedulingUnitBluep
 def get_min_earliest_possible_start_time(scheduling_units: [models.SchedulingUnitBlueprint], lower_bound: datetime) -> datetime:
     '''deterimine the earliest possible starttime over all given scheduling units, taking into account all their constraints'''
     try:
-        return min(get_earliest_possible_start_time(scheduling_unit, lower_bound) for scheduling_unit in scheduling_units if scheduling_unit.draft.scheduling_constraints_template is not None)
+        return min(get_earliest_possible_start_time(scheduling_unit, lower_bound) for scheduling_unit in scheduling_units if scheduling_unit.scheduling_constraints_template is not None)
     except ValueError:
         return lower_bound
 
diff --git a/SAS/TMSS/backend/services/scheduling/lib/constraints/template_constraints_v1.py b/SAS/TMSS/backend/services/scheduling/lib/constraints/template_constraints_v1.py
index 594c088ecd6..7dcb48aef02 100644
--- a/SAS/TMSS/backend/services/scheduling/lib/constraints/template_constraints_v1.py
+++ b/SAS/TMSS/backend/services/scheduling/lib/constraints/template_constraints_v1.py
@@ -61,7 +61,7 @@ def can_run_within_timewindow(scheduling_unit: models.SchedulingUnitBlueprint, l
 
 def can_run_after(scheduling_unit: models.SchedulingUnitBlueprint, lower_bound: datetime) -> bool:
     '''Check if the given scheduling_unit can run somewhere after the given lowerbound timestamp depending on the sub's constrains-template/doc.'''
-    constraints = scheduling_unit.draft.scheduling_constraints_doc
+    constraints = scheduling_unit.scheduling_constraints_doc
     if 'before' in constraints['time']:
         before = parser.parse(constraints['time']['before'], ignoretz=True)
         return before > lower_bound
@@ -74,7 +74,7 @@ __all__ = ['can_run_within_timewindow', 'can_run_after']
 
 def has_manual_scheduler_constraint(scheduling_unit: models.SchedulingUnitBlueprint) -> bool:
     '''evaluate the scheduler contraint. Should this unit be manually scheduled?'''
-    constraints = scheduling_unit.draft.scheduling_constraints_doc
+    constraints = scheduling_unit.scheduling_constraints_doc
     return constraints.get('scheduler', '') == 'manual'
 
 
@@ -101,7 +101,7 @@ def can_run_anywhere_within_timewindow_with_daily_constraints(scheduling_unit: m
     :return: True if all daily constraints are met over the entire time window, else False.
     """
     main_observation_task_name = get_target_observation_task_name_from_requirements_doc(scheduling_unit)
-    constraints = scheduling_unit.draft.scheduling_constraints_doc
+    constraints = scheduling_unit.scheduling_constraints_doc
     if constraints['daily']['require_day'] or constraints['daily']['require_night'] or constraints['daily']['avoid_twilight']:
 
         if (upper_bound - lower_bound).days >= 1:
@@ -158,7 +158,7 @@ def can_run_within_timewindow_with_time_constraints(scheduling_unit: models.Sche
              constraints are met over the runtime of the observation, else False.
     """
     main_observation_task_name = get_target_observation_task_name_from_requirements_doc(scheduling_unit)
-    constraints = scheduling_unit.draft.scheduling_constraints_doc
+    constraints = scheduling_unit.scheduling_constraints_doc
 
     # Check the 'at' constraint and then only check can_run_anywhere for the single possible time window
     if 'at' in constraints['time']:
@@ -189,7 +189,7 @@ def can_run_anywhere_within_timewindow_with_time_constraints(scheduling_unit: mo
     can_run_with_after = True
     can_run_between = True
     can_run_not_between = True
-    constraints = scheduling_unit.draft.scheduling_constraints_doc
+    constraints = scheduling_unit.scheduling_constraints_doc
 
     # given time window needs to end before constraint
     if 'before' in constraints['time']:
@@ -254,7 +254,7 @@ def can_run_anywhere_within_timewindow_with_sky_constraints(scheduling_unit: mod
     # TODO: remove this shortcut after demo
     return True
 
-    constraints = scheduling_unit.draft.scheduling_constraints_doc
+    constraints = scheduling_unit.scheduling_constraints_doc
     if not "sky" in constraints:
         return True
 
@@ -312,7 +312,7 @@ def get_target_observation_task_name_from_requirements_doc(scheduling_unit: mode
 
 
 def get_earliest_possible_start_time(scheduling_unit: models.SchedulingUnitBlueprint, lower_bound: datetime) -> datetime:
-    constraints = scheduling_unit.draft.scheduling_constraints_doc
+    constraints = scheduling_unit.scheduling_constraints_doc
 
     main_observation_task_name = get_target_observation_task_name_from_requirements_doc(scheduling_unit)
     duration = timedelta(seconds=scheduling_unit.requirements_doc['tasks'][main_observation_task_name]['specifications_doc']['duration'])
@@ -383,7 +383,7 @@ def get_earliest_possible_start_time(scheduling_unit: models.SchedulingUnitBluep
 
 def compute_scores(scheduling_unit: models.SchedulingUnitBlueprint, lower_bound:datetime, upper_bound:datetime) -> ScoredSchedulingUnit:
     '''Compute the "fitness" scores per constraint for the given scheduling_unit at the given starttime depending on the sub's constrains-template/doc.'''
-    constraints = scheduling_unit.draft.scheduling_constraints_doc
+    constraints = scheduling_unit.scheduling_constraints_doc
 
     # TODO: add compute_scores methods for each type of constraint
     # TODO: take start_time into account. For example, an LST constraint yields a better score when the starttime is such that the center of the obs is at LST.
diff --git a/SAS/TMSS/backend/services/scheduling/lib/dynamic_scheduling.py b/SAS/TMSS/backend/services/scheduling/lib/dynamic_scheduling.py
index 3b45ac16bd9..5ff4971b7f7 100644
--- a/SAS/TMSS/backend/services/scheduling/lib/dynamic_scheduling.py
+++ b/SAS/TMSS/backend/services/scheduling/lib/dynamic_scheduling.py
@@ -298,8 +298,7 @@ def get_dynamically_schedulable_scheduling_units() -> [models.SchedulingUnitBlue
     defined_independend_subtasks = models.Subtask.independent_subtasks().filter(state__value='defined')
     defined_independend_subtask_ids = defined_independend_subtasks.values('task_blueprints__scheduling_unit_blueprint_id').distinct().all()
     scheduling_units = models.SchedulingUnitBlueprint.objects.filter(id__in=defined_independend_subtask_ids) \
-                                                             .filter(draft__scheduling_constraints_template__isnull=False) \
-                                                             .select_related('draft', 'draft__scheduling_constraints_template').all()
+                                                             .filter(scheduling_constraints_template__isnull=False).all()
     return [su for su in scheduling_units if su.status == 'schedulable']
 
 
-- 
GitLab