diff --git a/SAS/TMSS/backend/services/scheduling/lib/constraints.py b/SAS/TMSS/backend/services/scheduling/lib/constraints.py index ec2298855ed760dc19f6e30e98b223994ac9ff18..79be8a045c2861fec0f0469ebe9a0c974a059c5f 100644 --- a/SAS/TMSS/backend/services/scheduling/lib/constraints.py +++ b/SAS/TMSS/backend/services/scheduling/lib/constraints.py @@ -428,7 +428,7 @@ def get_best_scored_scheduling_unit_scored_by_constraints(scheduling_units: [mod # First score everything based on coarse grid logger.info("get_best_scored_scheduling_unit_scored_by_constraints: scoring and sorting %d units at coarse grid of %s[min]...", len(scheduling_units), coarse_gridder.grid_minutes) - sorted_scored_scheduling_units_coarse = sort_scheduling_units_scored_by_constraints(scheduling_units, lower_bound_start_time, upper_bound_stop_time, coarse_gridder) + sorted_scored_scheduling_units_coarse = sort_scheduling_units_scored_by_constraints(scheduling_units, lower_bound_start_time, upper_bound_stop_time, coarse_gridder, raise_if_interruped) if sorted_scored_scheduling_units_coarse: if logger.level == logging.DEBUG: @@ -480,7 +480,7 @@ def get_best_scored_scheduling_unit_scored_by_constraints(scheduling_units: [mod return None -def sort_scheduling_units_scored_by_constraints(scheduling_units: [models.SchedulingUnitBlueprint], lower_bound_start_time: datetime, upper_bound_stop_time: datetime, gridder: Gridder) -> [ScoredSchedulingUnit]: +def sort_scheduling_units_scored_by_constraints(scheduling_units: [models.SchedulingUnitBlueprint], lower_bound_start_time: datetime, upper_bound_stop_time: datetime, gridder: Gridder, raise_if_interruped: Callable=noop) -> [ScoredSchedulingUnit]: """ Compute the score and proposed start_time for all given scheduling_units. Return them sorted by their weighted_score. :param lower_bound_start_time: evaluate and score the constrains at and after lower_bound_start_time. The returned unit has a start_time guaranteed at or after lower_bound_start_time. @@ -489,7 +489,7 @@ def sort_scheduling_units_scored_by_constraints(scheduling_units: [models.Schedu Returns a list of ScoredSchedulingUnit structs with the score details, a weighted_score and a proposed start_time where it best fits its contraints. """ - scored_scheduling_units = compute_individual_and_weighted_scores(scheduling_units, lower_bound_start_time, upper_bound_stop_time, gridder) + scored_scheduling_units = compute_individual_and_weighted_scores(scheduling_units, lower_bound_start_time, upper_bound_stop_time, gridder, raise_if_interruped=raise_if_interruped) unstartable_scheduling_units = [sssu for sssu in scored_scheduling_units if sssu.start_time is None] if unstartable_scheduling_units: @@ -1841,51 +1841,51 @@ def get_weighted_start_time(scheduling_unit: models.SchedulingUnitBlueprint, low weighted_start_time = round_to_second_precision(weighted_start_time) if can_run_at(scheduling_unit, weighted_start_time, gridder): - logger.info("get_weighted_start_time: SUB id=%s weighted='%s' - weight=%.3f earliest='%s' optimal='%s' latest='%s' - window=['%s', '%s']", scheduling_unit.id, weighted_start_time, density_vs_optimal.weight, earliest_possible_start_time, optimal_start_time, latest_possible_start_time, lower_bound, upper_bound) + logger.debug("get_weighted_start_time: SUB id=%s weighted='%s' - weight=%.3f earliest='%s' optimal='%s' latest='%s' - window=['%s', '%s']", scheduling_unit.id, weighted_start_time, density_vs_optimal.weight, earliest_possible_start_time, optimal_start_time, latest_possible_start_time, lower_bound, upper_bound) return weighted_start_time - logger.info("get_weighted_start_time: SUB id=%s returning earliest='%s' - window=['%s', '%s']", scheduling_unit.id, earliest_possible_start_time, lower_bound, upper_bound) + logger.debug("get_weighted_start_time: SUB id=%s returning earliest='%s' - window=['%s', '%s']", scheduling_unit.id, earliest_possible_start_time, lower_bound, upper_bound) return earliest_possible_start_time logger.warning("get_weighted_start_time: SUB id=%s could not compute weighted_start_time - window=['%s', '%s']", scheduling_unit.id, lower_bound, upper_bound) return None -def compute_individual_and_weighted_scores(scheduling_units: [models.SchedulingUnitBlueprint], lower_bound:datetime, upper_bound:datetime, gridder: Gridder=None) -> [ScoredSchedulingUnit]: +def compute_individual_and_weighted_scores(scheduling_units: [models.SchedulingUnitBlueprint], lower_bound:datetime, upper_bound:datetime, gridder: Gridder=None, raise_if_interruped: Callable=noop) -> [ScoredSchedulingUnit]: if gridder is None: gridder = Gridder() scored_scheduling_units = [] for i, su in enumerate(scheduling_units): + raise_if_interruped() + try: unit_gridder = fine_enough_gridder(su, gridder) scored_su = compute_scheduling_unit_scores(su, lower_bound, upper_bound, unit_gridder) - if scored_su is not None and scored_su.start_time is not None: - scored_scheduling_units.append(scored_su) + if scored_su is not None and scored_su.start_time is not None and len(scored_su.scores) > 0: + # compute weighted total score + weighted_score = 0.0 + for score_key, score_value in scored_su.scores.items(): + weight_factor, created = models.SchedulingConstraintsWeightFactor.objects.get_or_create( + scheduling_constraints_template=scored_su.scheduling_unit.scheduling_constraints_template, + constraint_name=score_key, + defaults={'weight': 1.0}) + + weighted_score += weight_factor.weight * score_value - logger.info("compute_individual_and_weighted_scores: checked unit [%d/%d] %.1f%% id=%d", - i+1, len(scheduling_units), 100.0 * (i+1) / len(scheduling_units), su.id) + scored_su.weighted_score = weighted_score / float(len(scored_su.scores)) + + scored_scheduling_units.append(scored_su) + logger.info("compute_individual_and_weighted_scores: checked unit [%d/%d] %.1f%% %s", + i+1, len(scheduling_units), 100.0 * (i+1) / len(scheduling_units), scored_su) + else: + logger.warning("compute_individual_and_weighted_scores: could not determine start_time for unit [%d/%d] %.1f%% id=%d", + i+1, len(scheduling_units), 100.0 * (i+1) / len(scheduling_units), su.id) except Exception as e: logger.exception(e) - # compute weighted total score - for scored_scheduling_unit in sorted(scored_scheduling_units, key=lambda x: x.scheduling_unit.id): - scored_scheduling_unit.weighted_score = 0.0 - count = len(scored_scheduling_unit.scores) - if count > 0: - weighted_score = 0.0 - for score_key, score_value in scored_scheduling_unit.scores.items(): - weight_factor, created = models.SchedulingConstraintsWeightFactor.objects.get_or_create(scheduling_constraints_template=scored_scheduling_unit.scheduling_unit.scheduling_constraints_template, - constraint_name=score_key, - defaults={'weight': 1.0}) - - weighted_score += weight_factor.weight * score_value - - scored_scheduling_unit.weighted_score = weighted_score / float(count) - logger.debug("computed (weighted) score(s): %s", scored_scheduling_unit) - return scored_scheduling_units def compute_scheduling_unit_scores(scheduling_unit: models.SchedulingUnitBlueprint, lower_bound:datetime, upper_bound:datetime, gridder: Gridder) -> ScoredSchedulingUnit: