oprava zbytecneho curtailu A
Some checks failed
CI and deploy / migration-check (push) Failing after 10s
CI and deploy / deploy (push) Has been skipped

This commit is contained in:
Dusan Vojacek
2026-05-30 23:23:17 +02:00
parent 830aa7a4cc
commit a03b45d4a9
7 changed files with 177 additions and 23 deletions

View File

@@ -3664,6 +3664,54 @@ class PreNegativeSellExportTests(unittest.TestCase):
self.assertLess(r0.pv_a_curtailed_w, 500, "pole A nesmí jít do curtail při sell>0 před neg")
self.assertLess(r0.grid_setpoint_w, -4000, "export přebytku A+B do site")
def test_ba81_dawn_low_pv_no_full_curtail_for_mi_cap(self) -> None:
"""Úsvit: malé pole A + MI — ne plný curtail A kvůli ge_pv≤pv_b (reg 340)."""
prague = ZoneInfo("Europe/Prague")
slot = PlanningSlot(
interval_start=datetime(2026, 5, 31, 5, 15, tzinfo=prague).astimezone(timezone.utc),
buy_price=3.088,
sell_price=2.95,
pv_a_forecast_w=405,
pv_b_forecast_w=49,
load_baseline_w=400,
ev1_connected=False,
ev2_connected=False,
allow_charge=True,
allow_discharge_export=True,
charge_acquisition_buy_czk_kwh=3.088,
future_sell_opportunity_czk_kwh=6.5,
)
battery = _battery(uc_wh=12_500.0, min_pct=10.0, arb_pct=30.0)
battery.max_charge_power_w = 6250
hp = SimpleNamespace(rated_heating_power_w=0, tuv_min_temp_c=45.0, tuv_target_temp_c=55.0)
grid = SimpleNamespace(
max_import_power_w=17_000,
max_export_power_w=8000,
block_export_on_negative_sell=False,
purchase_pricing_mode="fixed",
)
vehicles = [
SimpleNamespace(max_charge_power_w=0, battery_capacity_kwh=1.0, default_target_soc_pct=80.0),
SimpleNamespace(max_charge_power_w=0, battery_capacity_kwh=1.0, default_target_soc_pct=80.0),
]
res, _, _ = solve_dispatch(
[slot],
battery,
hp,
grid,
[None, None],
vehicles,
0.12 * battery.soc_max_wh,
50.0,
operating_mode="AUTO",
)
r = res[0]
self.assertLess(
r.pv_a_curtailed_w,
int(slot.pv_a_forecast_w) - 50,
"nesmí useknout celé A kvůli fixed_pv_b_export_cap",
)
def test_rolling_horizon_drains_to_reserve_before_first_neg(self) -> None:
"""Rolling bez D1 večera: výboj před 1. sell<0 na reserve (+ slack)."""
prague = ZoneInfo("Europe/Prague")
@@ -3722,7 +3770,7 @@ class PreNegativeSellExportTests(unittest.TestCase):
interval_start=(base + timedelta(minutes=15 * i)).astimezone(timezone.utc),
buy_price=6.35,
sell_price=sell,
pv_a_forecast_w=800 if sell < 4 else 200,
pv_a_forecast_w=4500 if i < 4 else (800 if sell < 4 else 200),
pv_b_forecast_w=0,
load_baseline_w=400,
ev1_connected=False,
@@ -3759,7 +3807,15 @@ class PreNegativeSellExportTests(unittest.TestCase):
operating_mode="AUTO",
)
self.assertLess(res[10].grid_setpoint_w, -500, "20:15 sell<buy: vývoz bat, ne jen peak 19:45")
self.assertLess(res[0].pv_a_curtailed_w, 500, "17:15: FVE do sítě, ne curtail")
for i in range(4):
self.assertNotEqual(
res[i].export_mode,
"BATTERY_SELL",
f"slot {i}: při FVE přebytku ne vývoz z baterie",
)
self.assertEqual(res[1].export_mode, "PV_SURPLUS")
self.assertGreater(abs(res[1].grid_setpoint_w), 500)
self.assertLess(abs(res[1].battery_setpoint_w), 500)
class Home01PvStoreValueTests(unittest.TestCase):