Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions apps/predbat/plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -4113,10 +4113,12 @@ def optimise_swap_export(self, record_charge_windows, record_export_windows, dro
set_window_start(self.export_window_best[window_n_target], self.export_window_best[window_n_target]["end"] - (window_length + window_length_target))
is_combined = True
elif export_mode_of(export_limit_target) == EXPORT_MODE_TARGET and window_length_target < orig_length_target:
# Partial combine
# Partial combine - move export time from this window into the target, so
# this window shrinks by what the target gains. Growing it instead pushed
# its start back into the slot before, through any manual override there (#5423)
amount_to_move = min(orig_length_target - window_length_target, window_length)
window_length_target_new = amount_to_move + window_length_target
window_length_new = amount_to_move + window_length
window_length_new = window_length - amount_to_move
self.export_limits_best[window_n] = min(export_limit, export_limit_target, key=export_limit_sort_key)
set_window_start(self.export_window_best[window_n], self.export_window_best[window_n]["end"] - window_length_new)
set_window_start(self.export_window_best[window_n_target], self.export_window_best[window_n_target]["end"] - window_length_target_new)
Expand Down
23 changes: 23 additions & 0 deletions apps/predbat/tests/test_optimise_swap_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,29 @@ def run_optimise_swap_export_tests(my_predbat):
failed = True
my_predbat.calculate_best_export = True

# ---------------------------------------------------------------------------------------------
# Partial combine regression (#5423): moving export time from an earlier window into a later,
# trimmed one must shrink the earlier window, never grow it backwards into the slot before it.
# Here the slot before is a manual demand override, so growing into it exports through it.
# ---------------------------------------------------------------------------------------------
now = my_predbat.minutes_now
export_window_best = [
{"start": now, "end": now + 30, "average": 50.0},
{"start": now + 30, "end": now + 60, "average": 50.0},
{"start": now + 80, "end": now + 90, "average": 50.0, "start_orig": now + 60},
]
setup_swap_export(my_predbat, export_window_best, export_limits_best=[100.0, 0.0, 0.0], rate_import=30.0, rate_export=50.0)
saved_manual_all_times = my_predbat.manual_all_times
my_predbat.manual_all_times = {now}
try:
my_predbat.optimise_swap_export(0, len(export_window_best))
finally:
my_predbat.manual_all_times = saved_manual_all_times
middle = my_predbat.export_window_best[1]
if middle["start"] < now + 30:
print("ERROR: partial combine grew window 1 back to {} into the manual slot ending {}, windows {}".format(middle["start"], now + 30, my_predbat.export_window_best))
failed = True

# ---------------------------------------------------------------------------------------------
# Ordering regression (#4478): the export swap must run after every pass that can enable an
# export, otherwise the exports the plan pass / optimise_solar add are never
Expand Down
36 changes: 18 additions & 18 deletions coverage/cases/random_results.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,17 @@
{
"id": 1,
"seed": 1,
"metric": 1164.5356,
"cost": 1154.7627,
"metric": 1164.4733,
"cost": 1154.5992,
"cost_pv10": 1429.766,
"cost_pv90": 1017.5324,
"cost_pv90": 1018.3924,
"import_kwh_battery": 8.2145,
"import_kwh_house": 20.3602,
"export_kwh": 10.5863,
"import_kwh_house": 20.3497,
"export_kwh": 10.5909,
"soc_min": 0.38,
"soc_final": 4.762,
"battery_cycles": 16.5804,
"carbon_g": 20357.15,
"soc_final": 4.7532,
"battery_cycles": 16.4913,
"carbon_g": 20352.73,
"runtime_s": 1.161,
"failed": false,
"error": null,
Expand Down Expand Up @@ -65,17 +65,17 @@
{
"id": 3,
"seed": 3,
"metric": 628.401,
"cost": 646.8817,
"cost_pv10": 624.2009,
"cost_pv90": 579.9167,
"metric": 628.3622,
"cost": 649.2458,
"cost_pv10": 623.6014,
"cost_pv90": 582.2808,
"import_kwh_battery": 0.0792,
"import_kwh_house": 0.0,
"export_kwh": 8.3425,
"export_kwh": 8.1858,
"soc_min": 0.3907,
"soc_final": 1.2819,
"battery_cycles": 11.1137,
"carbon_g": 9719.92,
"soc_final": 1.4502,
"battery_cycles": 10.9505,
"carbon_g": 9769.74,
"runtime_s": 0.343,
"failed": false,
"error": null,
Expand Down Expand Up @@ -179,9 +179,9 @@
{
"id": 9,
"seed": 9,
"metric": 477.0656,
"metric": 477.3462,
"cost": 581.2203,
"cost_pv10": 805.6605,
"cost_pv10": 807.2194,
"cost_pv90": 254.3911,
"import_kwh_battery": 16.7377,
"import_kwh_house": 5.1054,
Expand Down
Loading