Skip to content

Commit c2424ed

Browse files
chore(plan): make the planner log readable at default verbosity
The planner's normal-verbosity log was dominated by two things that repeat on every optimisation pass: an "Optimise price set" line per price level per pass, and the full charge and export window lists after each. On a plan with 24 charge and 96 export windows that is thousands of characters repeated dozens of times, which buries the lines that say what actually happened. Both now only appear with debug_enable, where the per-pass detail is what you are looking for. In their place, the lines that remain say more: - each region optimisation pass reports the metric, cost, cycle and import it arrived at, instead of only announcing that it started - so it is visible which pass width actually moved the plan - prune_dead_plan_slots reports the nominal metric it started and finished on, plus the full metric and cost of the resulting plan. The trials themselves run nominal-only, so the plan figures are taken from a full evaluation rather than reusing the trial number, which would otherwise be quietly comparing against a different scenario blend Logging only; run_random is identical on all 20 scenarios and the debug cases are unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 1f4a935 commit c2424ed

1 file changed

Lines changed: 21 additions & 8 deletions

File tree

apps/predbat/plan.py

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2676,6 +2676,7 @@ def prune_dead_plan_slots(self):
26762676
eps = 0.02
26772677
record_limit = self.end_record + self.minutes_now
26782678
baseline = None
2679+
start_metric = None
26792680
pruned = 0
26802681
trials = 0
26812682
for typ, windows, limits, off_value in (("export", self.export_window_best, self.export_limits_best, 100.0), ("charge", self.charge_window_best, self.charge_limit_best, 0)):
@@ -2690,6 +2691,7 @@ def prune_dead_plan_slots(self):
26902691
continue
26912692
if baseline is None:
26922693
baseline = self.run_prediction_metric(self.charge_limit_best, self.charge_window_best, self.export_window_best, self.export_limits_best, end_record=self.end_record, nominal_only=True)[0]
2694+
start_metric = baseline
26932695
limits[window_n] = off_value
26942696
trial = self.run_prediction_metric(self.charge_limit_best, self.charge_window_best, self.export_window_best, self.export_limits_best, end_record=self.end_record, nominal_only=True)[0]
26952697
trials += 1
@@ -2701,7 +2703,17 @@ def prune_dead_plan_slots(self):
27012703
else:
27022704
limits[window_n] = limit
27032705
if pruned:
2704-
self.log("Pruned {} dead plan slot(s) in {} trial(s)".format(pruned, trials))
2706+
# The trials run on the nominal scenario only, so report the full metric and cost of the
2707+
# pruned plan rather than the nominal figure the trials compared on
2708+
metric, battery_value, cost, metric_keep, battery_cycle, final_carbon_g, import_kwh, export_kwh = self.run_prediction_metric(
2709+
self.charge_limit_best, self.charge_window_best, self.export_window_best, self.export_limits_best, end_record=self.end_record
2710+
)
2711+
curr = self.currency_symbols[1]
2712+
self.log(
2713+
"Pruned {} dead plan slot(s) in {} trial(s), nominal metric {}{} -> {}{}, plan now metric {}{}, cost {}{}, cycle {}kWh, import {}kWh".format(
2714+
pruned, trials, dp2(start_metric), curr, dp2(baseline), curr, dp2(metric), curr, dp2(cost), curr, dp2(battery_cycle), dp2(import_kwh)
2715+
)
2716+
)
27052717
return pruned
27062718

27072719
def clip_charge_slots(self, minutes_now, predict_soc, charge_window_best, charge_limit_best, record_charge_windows, step):
@@ -3663,7 +3675,7 @@ def optimise_detailed_pass(
36633675
continue
36643676

36653677
if self.calculate_best_charge and (window_start not in self.manual_all_times):
3666-
if not printed_set:
3678+
if not printed_set and self.debug_enable:
36673679
self.log(
36683680
"Optimise price set {}{}, pass {}, price {}{}, start_at_low {}, best_price_charge {}{}, best_metric {}{}, best_cost {}{}, best_cycle {}kWh, best_carbon {}kg, best_import {}kWh".format(
36693681
price_key,
@@ -3790,7 +3802,7 @@ def optimise_detailed_pass(
37903802
continue
37913803

37923804
if self.allow_this_export_window(window_n):
3793-
if not printed_set:
3805+
if not printed_set and self.debug_enable:
37943806
self.log(
37953807
"Optimise price set {}{}, pass {}, price {}{}, start_at_low {}, best_price_export {}{}, level {}{}, best_metric {}{}, best_cost {}{}, best_cycle {}kWh, best_carbon {}kg, best_import {}kWh".format(
37963808
price_key,
@@ -3883,8 +3895,9 @@ def optimise_detailed_pass(
38833895
dp2(best_import),
38843896
)
38853897
)
3886-
# Log set of charge and export windows
3887-
if self.calculate_best_charge:
3898+
# Log set of charge and export windows - the full window list is long and repeats after
3899+
# every pass, so it is debug only
3900+
if self.calculate_best_charge and self.debug_enable:
38883901
self.log(
38893902
"Best charge windows best_metric {}{}, best_cost {}{}, best_carbon {}kg, best_import {}kWh, metric_keep {}kWh, end_record {}, windows {}".format(
38903903
dp2(best_metric),
@@ -3899,7 +3912,7 @@ def optimise_detailed_pass(
38993912
)
39003913
)
39013914

3902-
if self.calculate_best_export:
3915+
if self.calculate_best_export and self.debug_enable:
39033916
self.log(
39043917
"Best export windows best_metric {}{}, best_cost {}{}, best_carbon {}kg, best_import {}kWh, metric_keep {}kWh, end_record {}, windows {}".format(
39053918
dp2(best_metric),
@@ -3926,6 +3939,7 @@ def optimise_levels_pass(self, best_metric, metric_keep, debug_mode=False):
39263939
"""
39273940
Select the charge and export price levels and create the high level plan
39283941
"""
3942+
curr = self.currency_symbols[1]
39293943
record_charge_windows = max(self.max_charge_windows(self.end_record + self.minutes_now, self.charge_window_best), 1)
39303944
record_export_windows = max(self.max_charge_windows(self.end_record + self.minutes_now, self.export_window_best), 1)
39313945

@@ -3990,7 +4004,6 @@ def optimise_levels_pass(self, best_metric, metric_keep, debug_mode=False):
39904004
region_size = int(16 * 60)
39914005
min_region_size = int(120)
39924006
while region_size >= min_region_size:
3993-
self.log(">> Region optimisation pass width {}".format(region_size))
39944007
# step_size = int(max(region_size / 2, min_region_size))
39954008
step_size = region_size
39964009
fast_mode = not (region_size == min_region_size)
@@ -4049,6 +4062,7 @@ def optimise_levels_pass(self, best_metric, metric_keep, debug_mode=False):
40494062
if self.end_record + self.minutes_now - region - region_size < 0:
40504063
break
40514064

4065+
self.log(">> Region optimisation pass width {} gives best_metric {}{}, best_cost {}{}, best_cycle {}kWh, best_import {}kWh".format(region_size, dp2(best_metric), curr, dp2(best_cost), curr, dp2(best_cycle), dp2(best_import)))
40524066
self.plan_write_debug(debug_mode, "plan_levels_{}.html".format(region_size), self.pv_forecast_minute_step, self.pv_forecast_minute10_step, self.load_minutes_step, self.load_minutes_step10, self.end_record)
40534067
region_size = int(region_size / 2)
40544068

@@ -4061,7 +4075,6 @@ def optimise_levels_pass(self, best_metric, metric_keep, debug_mode=False):
40614075

40624076
self.log("Optimise levels pass ended at {}, duration {:.1f} seconds tried {} combinations".format(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())), time.time() - start_time, len(tried_list)))
40634077

4064-
curr = self.currency_symbols[1]
40654078
self.log(
40664079
"Set best_price_charge_level {}{}, best_price_export_level {}{}, best_price_charge {}{}, best_cost_export {}{}, best_metric {}{}, best_keep {}kWh, best_cycle {}kWh, best_carbon {}kg, best_import {}kWh".format(
40674080
dp2(best_price_charge_level), curr, dp2(best_price_export_level), curr, dp2(best_price_charge), curr, dp2(best_price_export), curr, dp2(best_metric), curr, dp2(best_keep), dp2(best_cycle), dp0(best_carbon), dp2(best_import)

0 commit comments

Comments
 (0)